douban blacklist manage

add button to douban to delete follower

  1. // ==UserScript==
  2. // @name douban blacklist manage
  3. // @version 0.0.3
  4. // @description add button to douban to delete follower
  5. // @author harryhare, ✌
  6. // @license GPL 3.0
  7. // @icon https://raw.githubusercontent.com/harryhare/userscript/master/index.png
  8. // @match https://www.douban.com/**
  9. // @grant none
  10. // @namespace https://gf.qytechs.cn/users/1384897
  11. // ==/UserScript==
  12.  
  13. var buttons_map = {};//userid,buttons list
  14. var user_id_map = {};
  15. var blacklist_set = new Set();
  16. var ck = "";
  17. var page_url = "";
  18. const url_ban = "https://www.douban.com/j/contact/addtoblacklist";
  19. const url_unban = "https://www.douban.com/j/contact/unban";
  20.  
  21. //time delay
  22. var interval = 2000;
  23. var interval_id;
  24.  
  25.  
  26. const ban_text = "加入黑名单";
  27. const unban_text = "移出黑名单";
  28. const banning_text = "正在加入黑名单...";
  29. const unbanning_text = "正在移出黑名单...";
  30. const error_text = "失败请重试";
  31. let isBanningActive = false; // 用于标记拉黑操作是否在进行中
  32. let stopBan = false; // 用于停止拉黑操作
  33.  
  34.  
  35. function getCookie(c_name) {
  36. if (document.cookie.length > 0) {
  37. var c_start = document.cookie.indexOf(c_name + "=");
  38. if (c_start !== -1) {
  39. c_start = c_start + c_name.length + 1;
  40. var c_end = document.cookie.indexOf(";", c_start);
  41. if (c_end === -1) c_end = document.cookie.length;
  42. return unescape(document.cookie.substring(c_start, c_end));
  43. }
  44. }
  45. return "";
  46. }
  47.  
  48. async function ban_simple(user_name) {
  49. let user_id = await get_real_user_id(user_name);
  50. var xmlhttp = new XMLHttpRequest();
  51. var data = "people=" + user_id + "&ck=" + ck;
  52. xmlhttp.open("POST", url_ban, true);
  53. xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  54. xmlhttp.onload = function () {
  55. if (this.status === 200) {
  56. console.log(`拉黑${user_name}成功`);
  57. } else {
  58. console.log(`拉黑${user_name}失败`);
  59. }
  60. };
  61. xmlhttp.onerror = function () {
  62. console.log(`拉黑${user_name}失败`);
  63. };
  64. xmlhttp.send(data);
  65. }
  66.  
  67. async function ban(user_name, node) {
  68. let user_id = await get_real_user_id(user_name);
  69. var xmlhttp = new XMLHttpRequest();
  70. var url = url_ban;
  71. var data = "people=" + user_id + "&ck=" + ck;
  72. console.log('ban:', data);
  73. node.innerHTML = banning_text;
  74. xmlhttp.open("POST", url, true);
  75. xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  76. xmlhttp.onreadystatechange = function () {
  77. if (xmlhttp.readyState === 4) {
  78. if (xmlhttp.status === 200) {
  79. //node.innerHTML = "已加入黑名单";
  80. let buttons = buttons_map[user_name];
  81. blacklist_set.add(user_name);
  82. for (let i = 0; i < buttons.length; i++) {
  83. buttons[i].innerHTML = unban_text;
  84. }
  85. } else {
  86. node.innerHTML = error_text;
  87. }
  88. }
  89. };
  90. xmlhttp.send(data);
  91. }
  92.  
  93. async function unban(user_name, node) {
  94. let user_id = await get_real_user_id(user_name);
  95. var xmlhttp = new XMLHttpRequest();
  96. var url = url_unban;
  97. var data = "people=" + user_id + "&ck=" + ck;
  98. console.log('unban:', data);
  99. node.innerHTML = unbanning_text;
  100. xmlhttp.open("POST", url, true);
  101. xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  102. xmlhttp.onreadystatechange = function () {
  103. if (xmlhttp.readyState === 4) {
  104. if (xmlhttp.status === 200) {
  105. //node.innerHTML = "已加入黑名单";
  106. let buttons = buttons_map[user_name];
  107. blacklist_set.delete(user_name);
  108. for (let i = 0; i < buttons.length; i++) {
  109. buttons[i].innerHTML = ban_text;
  110. }
  111. } else {
  112. node.innerHTML = error_text;
  113. }
  114. }
  115. };
  116. xmlhttp.send(data);
  117. }
  118.  
  119. async function add_to_blacklist(e) {
  120. if (e.target.innerHTML === unban_text) {
  121. await unban(e.target.getAttribute("user-id"), e.target);
  122. } else {
  123. await ban(e.target.getAttribute("user-id"), e.target);
  124. }
  125. }
  126.  
  127. function get_blacklist_button(user_id, style) {
  128. let b = document.createElement('a');
  129. b.setAttribute("user-id", user_id);
  130. if (blacklist_set.has(user_id)) {
  131. b.innerHTML = unban_text;
  132. } else {
  133. b.innerHTML = ban_text;
  134. }
  135. b.style = style;
  136. b.onclick = add_to_blacklist;
  137. if (user_id in buttons_map) {
  138. buttons_map[user_id].push(b);
  139. } else {
  140. buttons_map[user_id] = [b];
  141. }
  142. return b
  143. }
  144.  
  145. function check_user_link(href) {
  146. const status_reg = /https:\/\/www\.douban\.com\/people\/[^\/]+\/?$/;
  147. return status_reg.test(href);
  148. }
  149.  
  150. function get_user_id_from_url(href) {
  151. if (href[href.length - 1] === "/") {
  152. href = href.substr(0, href.length - 1)
  153. }
  154. const j = href.lastIndexOf("/");
  155. return href.substr(j + 1, href.length - j);
  156. }
  157.  
  158. // 评论,日志和广播
  159. function process_comment() {
  160. function process_item(item) {
  161. let a = item.children[0];
  162. let href = a.href;
  163. let name = a.title;
  164. let user_id = get_user_id_from_url(a.href);
  165. let b = get_blacklist_button(user_id, "margin-left:10px");
  166. // 如果回复已被投诉则没有投诉那一排按钮
  167. let action_bars = item.parentElement.querySelectorAll("div.action-bar-group");
  168. if (action_bars.length > 0) {
  169. action_bars[0].append(b);
  170. }
  171. }
  172.  
  173. let items = document.querySelectorAll("div.item .meta-header");
  174. for (let i = 0; i < items.length; i++) {
  175. process_item(items[i]);
  176. }
  177.  
  178. function callback(records) {
  179. records.map(function (record) {
  180. if (record.addedNodes.length !== 0) {
  181. for (var i = 0; i < record.addedNodes.length; i++) {
  182. var node = record.addedNodes[i];
  183. if (node.className === "item reply-item") {//meta-head不行
  184. //console.log(node);
  185. var items = node.querySelectorAll("div.item .meta-header");
  186. //console.log(items);
  187. for (let i = 0; i < items.length; i++) {
  188. process_item(items[i]);
  189. }
  190. }
  191. }
  192. }
  193. });
  194. }
  195.  
  196. var mo = new MutationObserver(callback);
  197.  
  198. var option = {
  199. 'childList': true,
  200. 'subtree': true,
  201. };
  202.  
  203. mo.observe(document.body, option);
  204. }
  205.  
  206. // 小组 回复
  207. function process_comment_group() {
  208. let items = document.querySelectorAll("div.operation-div");
  209. for (let i = 0; i < items.length; i++) {
  210. let item = items[i];
  211. let user_id = item.id;
  212. let b = get_blacklist_button(user_id, "color: #aaa; margin-right:10px");
  213. let containers = item.querySelectorAll("div.operation-more");
  214. if(containers.length>0) {
  215. containers[0].append(b);
  216. }
  217. }
  218. }
  219.  
  220. function sleep(ms) {
  221. return new Promise(resolve => setTimeout(resolve, ms));
  222. }
  223.  
  224.  
  225. function makeRequest(url) {
  226. return new Promise(function (resolve, reject) {
  227. let xhr = new XMLHttpRequest();
  228. xhr.open("GET", url);
  229. xhr.onload = function () {
  230. if (this.status === 200) {
  231. resolve(xhr.response);
  232. } else {
  233. reject({
  234. status: this.status,
  235. statusText: xhr.statusText
  236. });
  237. }
  238. };
  239. xhr.onerror = function () {
  240. reject({
  241. status: this.status,
  242. statusText: xhr.statusText
  243. });
  244. };
  245. xhr.send();
  246. });
  247. }
  248.  
  249.  
  250. async function get_real_user_id(user_name) {
  251. const user_id_reg = /^\d{6,}$/;
  252. if (user_id_reg.test(user_name)) {
  253. return user_name;
  254. }
  255. if (user_name in user_id_map) {
  256. return user_id_map[user_name];
  257. }
  258. let url = `https://www.douban.com/people/${user_name}/`;
  259. let response = await makeRequest(url);
  260. let parser = new window.DOMParser();
  261. let xmlDoc = parser.parseFromString(response, "text/html");
  262. let user_id = xmlDoc.querySelector("div.user-opt a").id;
  263.  
  264. if (user_id === "ban-cancel") {
  265. const user_id_reg2 = /\d{6,}/;
  266. let div = xmlDoc.querySelector("div.user-opt script");
  267. user_id = user_id_reg2.exec(div.text)[0];
  268. }
  269. user_id_map[user_name] = user_id;
  270. return user_id;
  271. }
  272.  
  273.  
  274. async function do_blacklist_page(url, t) {
  275. let response = await makeRequest(url);
  276. let parser = new window.DOMParser();
  277. let xmlDoc = parser.parseFromString(response, "text/html");
  278. let items = xmlDoc.querySelectorAll("li div.content");
  279. let str = t.innerHTML;
  280. for (let i = 0; i < items.length; i++) {
  281. let item = items[i];
  282. let a = item.children[0];
  283. // 如果不是 https://www.douban/people/xxx 的形式,那么就是匿名用户
  284. if (check_user_link(a.href) === false) {
  285. continue;
  286. }
  287. let user_id = get_user_id_from_url(a.href);
  288. //console.log(`拉黑${user_id}`);
  289. await ban_simple(user_id);
  290. t.innerHTML = `${str}, 该页已完成 ${i + 1}/${items.length}`;
  291. await sleep(interval);
  292. }
  293. return items.length;// 返回该页的人数
  294. }
  295.  
  296. async function do_blacklist_all_status_like(e) {
  297. let b = e.target;
  298. console.log("blacklist all...");
  299. for (let i = 0; ; i += 20) {
  300. b.innerHTML = `正在拉黑第 ${i / 20 + 1} 页`;
  301. let url = `${page_url}?start=${i}&tab=like#like`;
  302. let n = await do_blacklist_page(url, e.target);
  303. if (n === 0) {
  304. b.innerHTML = `已全部拉黑`;
  305. break;
  306. } else if (n === -1) {
  307. b.innerHTML = '失败请重试';
  308. break;
  309. }
  310. await sleep(interval);
  311. }
  312. }
  313.  
  314. async function do_blacklist_all_note_like(e) {
  315. let b = e.target;
  316. console.log("blacklist all...");
  317. for (let i = 0; ; i += 100) {
  318. b.innerHTML = `正在拉黑第 ${i / 100 + 1} 页`;
  319. let url = `${page_url}?start=${i}&type=like#sep`;
  320. let n = await do_blacklist_page(url, e.target);
  321. if (n === 0) {
  322. b.innerHTML = `已全部拉黑`;
  323. break;
  324. } else if (n === -1) {
  325. b.innerHTML = '失败请重试';
  326. break;
  327. }
  328. }
  329. }
  330.  
  331. async function do_blacklist_all_note_donate(e) {
  332. let b = e.target;
  333. console.log("blacklist all...");
  334. for (let i = 0; ; i += 100) {
  335. b.innerHTML = `正在拉黑第 ${i / 100 + 1} 页`;
  336. let url = `${page_url}?start=${i}&type=donate#sep`;
  337. let n = await do_blacklist_page(url, e.target);
  338. if (n === 0) {
  339. b.innerHTML = `已全部拉黑`;
  340. break;
  341. } else if (n === -1) {
  342. b.innerHTML = '失败请重试';
  343. break;
  344. }
  345. }
  346. }
  347.  
  348. // 打赏 - 日志
  349. function process_note_donate() {
  350. let tabs = document.querySelector("div.tabs");
  351. let b = document.createElement('a');
  352. b.innerHTML = "一键拉黑所有赞赏的人";
  353. b.style = "float: right; font-size: 13px; line-height: 1.2; color: #fff; background:#bbb; opacity: 1;";
  354. // b.onmouseover = (e) => {
  355. // e.target.style.opacity = 1;
  356. // };
  357. // b.onmouseout = (e) => {
  358. // e.target.style.opacity = 0;
  359. // };
  360. b.onclick = do_blacklist_all_note_donate;
  361. tabs.append(b);
  362. }
  363.  
  364. // 点赞 - 日志
  365. function process_note_like() {
  366. let tabs = document.querySelector("div.tabs");
  367. let b = document.createElement('a');
  368. b.innerHTML = "一键拉黑所有点赞的人";
  369. b.style = "float: right; font-size: 13px; line-height: 1.2; color: #fff; background:#bbb; opacity: 1;";
  370. // b.onmouseover = (e) => {
  371. // e.target.style.opacity = 1;
  372. // };
  373. // b.onmouseout = (e) => {
  374. // e.target.style.opacity = 0;
  375. // };
  376. b.onclick = do_blacklist_all_note_like;
  377. tabs.append(b);
  378. }
  379.  
  380. // 点赞 - 广播
  381. function process_status_like() {
  382. let tabs = document.querySelector("div.tabs");
  383. let b = document.createElement('a');
  384. b.innerHTML = "一键拉黑所有点赞的人";
  385. b.style = "float: right; font-size: 13px; line-height: 1.2; color: #fff; background:#bbb; opacity: 1;";
  386. // b.onmouseover = (e) => {
  387. // e.target.style.opacity = 1;
  388. // };
  389. // b.onmouseout = (e) => {
  390. // e.target.style.opacity = 0;
  391. // };
  392. b.onclick = do_blacklist_all_status_like;
  393. tabs.append(b);
  394. }
  395.  
  396. // 转发 - 广播
  397. function process_reshare() {
  398. let items = document.querySelectorAll("li .content");
  399. for (let i = 0; i < items.length; i++) {
  400. let item = items[i];
  401. let a = item.children[0];
  402. let user_id = get_user_id_from_url(a.href);
  403. let b = get_blacklist_button(user_id, "margin-left:10px");
  404. b.className = "go-status";
  405. item.insertBefore(b, item.children[2]);
  406. }
  407. }
  408.  
  409. // 转发 - 日志
  410. function process_rec() {
  411. let items = document.querySelectorAll("li .content");
  412. for (let i = 0; i < items.length; i++) {
  413. let item = items[i];
  414. let a = item.children[0];
  415. let user_id = get_user_id_from_url(a.href);
  416. let b = get_blacklist_button(
  417. user_id,
  418. "position: absolute; top: 10px; right: 140px; color: #fff; background:#bbb; opacity: 0;"
  419. );
  420. b.onmouseover = (e) => {
  421. e.target.style.opacity = 1;
  422. };
  423. b.onmouseout = (e) => {
  424. e.target.style.opacity = 0;
  425. };
  426. item.insertBefore(b, item.children[2]);
  427. }
  428. }
  429.  
  430. // 收藏-日志, 日志的收藏是动态加载的
  431. function process_note_collect() {
  432. function process_item(item) {
  433. let a = item.children[0];
  434. let user_id = get_user_id_from_url(a.href);
  435. let b = get_blacklist_button(
  436. user_id,
  437. "position: absolute; top: 10px; right: 140px; color: #fff; background:#bbb; opacity: 0;"
  438. );
  439. b.onmouseover = (e) => {
  440. e.target.style.opacity = 1;
  441. };
  442. b.onmouseout = (e) => {
  443. e.target.style.opacity = 0;
  444. };
  445. item.insertBefore(b, item.children[2]);
  446. }
  447.  
  448. let items = document.querySelectorAll("li div.content");
  449. for (let i = 0; i < items.length; i++) {
  450. process_item(items[i]);
  451. }
  452.  
  453. function callback(records) {
  454. records.map(function (record) {
  455. if (record.addedNodes.length !== 0) {
  456. for (var i = 0; i < record.addedNodes.length; i++) {
  457. var node = record.addedNodes[i];
  458. //console.log(node.tagName);
  459. if (node.tagName && node.tagName.toLowerCase() === "ul") {
  460. //console.log(node);
  461. var items = node.querySelectorAll("li div.content");
  462. //console.log(items);
  463. for (let i = 0; i < items.length; i++) {
  464. process_item(items[i]);
  465. }
  466. }
  467. }
  468. }
  469. });
  470. }
  471.  
  472. var mo = new MutationObserver(callback);
  473.  
  474. var option = {
  475. 'childList': true,
  476. 'subtree': true,
  477. };
  478. mo.observe(document.body, option);
  479.  
  480. }
  481.  
  482. // 收藏-广播,广播的收藏也是动态的
  483. function process_status_collect() {
  484. function process_item(item) {
  485. let a = item.children[0];
  486. let user_id = get_user_id_from_url(a.href);
  487. let b = get_blacklist_button(
  488. user_id,
  489. "float: right; color: #fff; background:#bbb; opacity: 0;"
  490. );
  491. b.onmouseover = (e) => {
  492. e.target.style.opacity = 1;
  493. };
  494. b.onmouseout = (e) => {
  495. e.target.style.opacity = 0;
  496. };
  497. item.append(b);
  498. }
  499.  
  500. let items = document.querySelectorAll("li div.content");
  501. for (let i = 0; i < items.length; i++) {
  502. process_item(items[i]);
  503. }
  504.  
  505. function callback(records) {
  506. records.map(function (record) {
  507. if (record.addedNodes.length !== 0) {
  508. for (var i = 0; i < record.addedNodes.length; i++) {
  509. var node = record.addedNodes[i];
  510. //console.log(node.tagName);
  511. if (node.tagName && node.tagName.toLowerCase() === "ul") {
  512. //console.log(node);
  513. var items = node.querySelectorAll("li div.content");
  514. //console.log(items);
  515. for (let i = 0; i < items.length; i++) {
  516. process_item(items[i]);
  517. }
  518. }
  519. }
  520. }
  521. });
  522. }
  523.  
  524. var mo = new MutationObserver(callback);
  525.  
  526. var option = {
  527. 'childList': true,
  528. 'subtree': true,
  529. };
  530. mo.observe(document.body, option);
  531. }
  532.  
  533. function addBlacklistAllButton() {
  534. let dogShape = document.createElement('div');
  535. dogShape.innerHTML = `
  536. <div style="position: relative; width: 80px; height: 80px; background-color: #f9d3b4; border-radius: 50%; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); text-align: center; font-size: 12px; font-family: 'Arial Rounded MT Bold', 'Helvetica Rounded', sans-serif; color: white; font-weight: bold; display: flex; justify-content: center; align-items: center; padding: 5px;">
  537. 爱护<br>棉花小狗计划
  538. </div>
  539. <div style="position: absolute; top: -8px; left: 4px; width: 25px; height: 25px; background-color: #fce6d6; border-radius: 50%;"></div>
  540. <div style="position: absolute; top: -8px; right: 4px; width: 25px; height: 25px; background-color: #fce6d6; border-radius: 50%;"></div>
  541. `;
  542. dogShape.style = `
  543. position: fixed;
  544. bottom: 100px;
  545. right: 20px;
  546. z-index: 1000;
  547. text-align: center;
  548. font-size: 12px;
  549. color: #333;
  550. font-family: 'Comic Sans MS', cursive, sans-serif;
  551. line-height: 1.4;
  552. background-color: #fdebd0;
  553. padding: 15px;
  554. border-radius: 50%;
  555. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  556. transition: transform 0.3s ease;
  557. `;
  558.  
  559. // 添加悬停效果
  560. dogShape.onmouseover = function() {
  561. dogShape.style.transform = "scale(1.1)";
  562. };
  563. dogShape.onmouseout = function() {
  564. dogShape.style.transform = "scale(1)";
  565. };
  566.  
  567. let button = document.createElement('button');
  568. button.innerHTML = "拉黑所有小组成员";
  569. button.style = `
  570. position: fixed;
  571. bottom: 20px;
  572. right: 10px;
  573. z-index: 1000;
  574. background-color: #f78f8f;
  575. color: white;
  576. padding: 12px 24px;
  577. border: none;
  578. border-radius: 20px;
  579. cursor: pointer;
  580. font-size: 16px;
  581. font-family: 'Arial', sans-serif;
  582. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  583. transition: background-color 0.3s ease, transform 0.2s ease;
  584. `;
  585.  
  586. button.onmouseover = function() {
  587. button.style.backgroundColor = "#d86a6a";
  588. button.style.transform = "translateY(-2px)";
  589. };
  590.  
  591. button.onmouseout = function() {
  592. button.style.backgroundColor = "#f78f8f";
  593. button.style.transform = "translateY(0)";
  594. };
  595.  
  596. button.onclick = async function() {
  597. if (confirm("你确定要拉黑该小组所有成员吗?这可能需要一些时间。")) {
  598. await ban_all_members_in_group();
  599. }
  600. };
  601.  
  602. // 将狗狗提示文本和按钮添加到页面
  603. document.body.appendChild(dogShape);
  604. document.body.appendChild(button);
  605. }
  606.  
  607. async function ban_all_members_in_group() {
  608. console.log("开始拉黑该小组所有成员...");
  609. let current_page = getCurrentPage();
  610. let total_members_banned = parseInt(sessionStorage.getItem("total_members_banned") || "0");
  611. let members_per_page = 36;
  612.  
  613. while (true) {
  614. // 检查当前页面是否依旧是小组成员页面,如果不是则停止操作
  615. if (!isGroupMemberPage()) {
  616. console.log("已经离开小组成员页面,停止拉黑操作");
  617. clearBanState(); // 清空sessionStorage并停止
  618. break;
  619. }
  620.  
  621. console.log(`正在拉黑第 ${current_page + 1} 页的成员`);
  622. document.querySelector('button').innerHTML = `正在拉黑第 ${current_page + 1} 页...`;
  623.  
  624. let members_banned_on_page = await ban_all_members_on_page();
  625. total_members_banned += members_banned_on_page;
  626.  
  627. document.querySelector('button').innerHTML = `已拉黑 ${total_members_banned} 位成员 (第 ${current_page + 1} 页)`;
  628.  
  629. // 检查是否有下一页
  630. let next_button = document.querySelector("span.next a");
  631. if (!next_button || members_banned_on_page < members_per_page) {
  632. console.log("所有页面已处理完毕");
  633. clearBanState(); // 清空sessionStorage
  634. document.querySelector('button').innerHTML = "拉黑所有小组成员";
  635. break;
  636. }
  637.  
  638. // 保存当前页码和总数到sessionStorage
  639. sessionStorage.setItem("current_page", current_page + 1);
  640. sessionStorage.setItem("total_members_banned", total_members_banned);
  641.  
  642. next_button.click();
  643. await sleep(2000);
  644. return;
  645. }
  646. }
  647.  
  648. async function ban_all_members_on_page() {
  649. console.log("拉黑当前页面的所有成员");
  650. let items = document.querySelectorAll("li.member-item .name a");
  651. let members_banned = 0;
  652.  
  653. for (let i = 0; i < items.length; i++) {
  654. let user_name = items[i].href.split("/people/")[1].replace("/", "");
  655. console.log(`正在拉黑: ${user_name}`);
  656.  
  657. try {
  658. await ban_simple(user_name);
  659. members_banned++;
  660. console.log(`成功拉黑: ${user_name}`);
  661. } catch (error) {
  662. console.warn(`无法拉黑${error.message}`);
  663. // 继续下一个用户
  664. }
  665.  
  666. await sleep(interval);
  667. }
  668.  
  669. return members_banned;
  670. }
  671.  
  672. // 检查当前页面是否是小组成员页面
  673. function isGroupMemberPage() {
  674. const member_list_reg = /^https:\/\/www\.douban\.com\/group\/\d+\/members/;
  675. return member_list_reg.test(window.location.href);
  676. }
  677.  
  678. function clearBanState() {
  679. sessionStorage.removeItem("current_page");
  680. sessionStorage.removeItem("total_members_banned");
  681.  
  682. let groupBanButton = document.querySelector('button#group-ban-button');
  683. if (groupBanButton) {
  684. groupBanButton.innerHTML = "拉黑所有小组成员";
  685. }
  686. }
  687.  
  688. // 页面加载时自动从sessionStorage恢复状态并继续拉黑
  689. window.onload = async function () {
  690. let saved_page = sessionStorage.getItem("current_page");
  691. if (saved_page && isGroupMemberPage()) {
  692. console.log(`恢复到第 ${saved_page} 页`);
  693. await ban_all_members_in_group();
  694. } else {
  695. clearBanState();
  696. }
  697. };
  698.  
  699. // 获取当前页码
  700. function getCurrentPage() {
  701. let urlParams = new URLSearchParams(window.location.search);
  702. let start = urlParams.get("start") || "0";
  703. return Math.floor(parseInt(start) / 36);
  704. }
  705.  
  706. function addBlacklistAllButtonForTopic() {
  707. let dogShape = document.createElement('div');
  708. dogShape.innerHTML = `
  709. <div style="position: relative; width: 80px; height: 80px; background-color: #f9d3b4; border-radius: 50%; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); text-align: center; font-size: 12px; font-family: 'Arial Rounded MT Bold', 'Helvetica Rounded', sans-serif; color: white; font-weight: bold; display: flex; justify-content: center; align-items: center; padding: 5px;">
  710. 请勿<br>踹棉花小狗
  711. </div>
  712. <div style="position: absolute; top: -8px; left: 4px; width: 25px; height: 25px; background-color: #fce6d6; border-radius: 50%;"></div>
  713. <div style="position: absolute; top: -8px; right: 4px; width: 25px; height: 25px; background-color: #fce6d6; border-radius: 50%;"></div>
  714. `;
  715. dogShape.style = `
  716. position: fixed;
  717. bottom: 100px;
  718. right: 20px;
  719. z-index: 1000;
  720. text-align: center;
  721. font-size: 12px;
  722. color: #333;
  723. font-family: 'Comic Sans MS', cursive, sans-serif;
  724. line-height: 1.4;
  725. background-color: #fdebd0;
  726. padding: 15px;
  727. border-radius: 50%;
  728. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  729. transition: transform 0.3s ease;
  730. `;
  731.  
  732. // 添加悬停效果
  733. dogShape.onmouseover = function() {
  734. dogShape.style.transform = "scale(1.1)";
  735. };
  736. dogShape.onmouseout = function() {
  737. dogShape.style.transform = "scale(1)";
  738. };
  739.  
  740. let button = document.createElement('button');
  741. button.innerHTML = "拉黑所有回复的人";
  742. button.style = `
  743. position: fixed;
  744. bottom: 20px;
  745. right: 10px;
  746. z-index: 9999;
  747. background-color: #f78f8f;
  748. color: white;
  749. padding: 12px 24px;
  750. border: none;
  751. border-radius: 20px;
  752. cursor: pointer;
  753. font-size: 16px;
  754. font-family: 'Arial', sans-serif;
  755. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  756. transition: background-color 0.3s ease, transform 0.2s ease;
  757. `;
  758.  
  759. button.onmouseover = function () {
  760. button.style.backgroundColor = "#d86a6a";
  761. button.style.transform = "translateY(-2px)";
  762. };
  763.  
  764. button.onmouseout = function () {
  765. button.style.backgroundColor = "#f78f8f";
  766. button.style.transform = "translateY(0)";
  767. };
  768.  
  769. button.onclick = async function () {
  770. if (confirm("你确定要拉黑该帖子中的所有回复者吗?")) {
  771. await ban_all_reply_users();
  772. }
  773. };
  774.  
  775. document.body.appendChild(dogShape);
  776. document.body.appendChild(button);
  777. }
  778.  
  779. async function ban_all_reply_users() {
  780. console.log("开始拉黑帖子中的所有回复者...");
  781.  
  782. let total_banned = 0;
  783.  
  784. // 先处理主贴作者
  785. try {
  786. let topic_author = document.querySelector("#topic-content > div.topic-doc > h3 > span.from > a");
  787. if (topic_author) {
  788. let author_name = topic_author.href.split("/people/")[1].replace("/", "");
  789. console.log(`正在拉黑贴主: ${author_name}`);
  790. await ban_simple(author_name);
  791. total_banned++;
  792. await sleep(interval);
  793. }
  794. } catch (error) {
  795. console.warn(`无法拉黑贴主: ${error.message}`);
  796. }
  797.  
  798. // 然后处理所有回复者
  799. let items = document.querySelectorAll("li.comment-item"); // 获取所有回复
  800. for (let i = 0; i < items.length; i++) {
  801. try {
  802. let user_name = items[i].querySelector(".user-face a").href.split("/people/")[1].replace("/", "");
  803. console.log(`正在拉黑回复者: ${user_name}`);
  804. await ban_simple(user_name);
  805. total_banned++;
  806. await sleep(interval);
  807. } catch (error) {
  808. console.warn(`无法拉黑回复者: ${error.message}`);
  809. }
  810. }
  811.  
  812. alert(`已成功拉黑${total_banned}位用户`);
  813. }
  814.  
  815.  
  816. (function () {
  817. 'use strict';
  818.  
  819. ck = getCookie("ck");
  820. let url = window.location.href;
  821. url = url.replace("#sep", "");
  822. let i = url.indexOf("?");
  823. if (i === -1) {
  824. i = url.length;
  825. }
  826. const page = url.substr(0, i);
  827. const arg = url.substr(i + 1, url.length - i);
  828. const status_reg = /^https:\/\/www\.douban\.com\/people\/[^\/]+\/status\/\d+\/$/;
  829. const note_reg = /^https:\/\/www\.douban\.com\/note\/\d+\/$/;
  830. const group_reg = /^https:\/\/www\.douban\.com\/group\/topic\/\d+\/$/;
  831. const member_list_reg = /^https:\/\/www\.douban\.com\/group\/[a-zA-Z0-9_-]+\/members/;
  832.  
  833. let page_mode = "None";
  834. if (status_reg.test(page)) {
  835. page_mode = "status";
  836. } else if (note_reg.test(page)) {
  837. page_mode = "node";
  838. } else if (group_reg.test(page)) {
  839. page_mode = "group";
  840. } else if (member_list_reg.test(page)) {
  841. page_mode = "members";
  842. } else {
  843. return;
  844. }
  845. page_url = page;
  846.  
  847. let tab_mode = "comment";
  848. if (arg.indexOf("comment") !== -1) {
  849. tab_mode = "comment";
  850. } else if (arg.indexOf("type=like") !== -1) {
  851. tab_mode = "note_like";
  852. } else if (arg.indexOf("tab=like") !== -1) {
  853. tab_mode = "status_like";
  854. } else if (arg.indexOf("tab=reshare") !== -1) {
  855. tab_mode = "reshare"; //for status
  856. } else if (arg.indexOf("type=rec") !== -1) {
  857. tab_mode = "rec"; // for note
  858. } else if (arg.indexOf("type=collect") !== -1) {
  859. tab_mode = "note_collect";
  860. } else if (arg.indexOf("tab=collect") !== -1) {
  861. tab_mode = "status_collect";
  862. } else if (arg.indexOf("type=donate") !== -1) {
  863. tab_mode = "note_donate";
  864. }
  865.  
  866. console.log(tab_mode);
  867. if (tab_mode === "comment") {
  868. if (page_mode === "group") {
  869. addBlacklistAllButtonForTopic();
  870. process_comment_group();
  871. } else {
  872. process_comment();
  873. }
  874. } else if (tab_mode === "note_like") {
  875. process_note_like();
  876. } else if (tab_mode === "status_like") {
  877. process_status_like();
  878. } else if (tab_mode === "reshare") {
  879. process_reshare();
  880. } else if (tab_mode === "rec") {
  881. process_rec();
  882. } else if (tab_mode === "note_collect") {
  883. process_note_collect();
  884. } else if (tab_mode === "status_collect") {
  885. process_status_collect();
  886. } else if (tab_mode === "note_donate") {
  887. process_note_donate();
  888. }
  889.  
  890. if (page_mode === "members") {
  891. addBlacklistAllButton();
  892. }
  893. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址