您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Delete your comments in group posts
// ==UserScript== // @name Douban Comment Deletion // @namespace http://tampermonkey.net/ // @version 1.1 // @description Delete your comments in group posts // @author https://www.douban.com/people/seebyl (viasyla) // @match *://www.douban.com/group/topic/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @license MIT // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // ==/UserScript== ;(async () => { 'use strict'; // —— fetch/prompt userId + menu command —— async function fetchOrPromptUserId() { let stored = await GM_getValue('userId', null); if (!stored) { const input = prompt('🚀 请输入你的用户 ID:'); if (input) { await GM_setValue('userId', input); return input; } return null; } return stored; } const userId = await fetchOrPromptUserId(); GM_registerMenuCommand('✏️ 修改用户 ID', async () => { const newId = prompt('✏️ 重新输入你的用户 ID:', userId || ''); if (newId) { await GM_setValue('userId', newId); location.reload(); } }); const box = document.createElement('div'); box.textContent = `你的 ID = ${userId}`; Object.assign(box.style, { position: 'fixed', bottom: '10px', left: '10px', padding: '8px', background: 'rgba(0,0,0,0.6)', color: '#fff', borderRadius: '4px', zIndex: 9999, }); document.body.appendChild(box); // —— now it’s safe to await every GM_… call —— console.log('Page Matched:', /\/group\/topic\//.test(window.location.href)); const targetUserId = Number(await GM_getValue('userId', null)); console.log('target user id:', targetUserId); const topicOpt = $('.topic-opt'); const topicAdminOpts = $('.topic-admin-opts'); const tid = location.href.match(/topic\/(\d+)\//)[1]; const ck = get_cookie("ck"); const pageStart = 0; // 顺手把ad关了 $('#gdt-ad-container').remove(); $('#dale_group_topic_inner_middle').remove(); function randomDelay(min = 500, max = 1500) { return new Promise(resolve => setTimeout(resolve, Math.random() * (max - min) + min)); } async function autoDeleteAllComments(p) { let hasNextPage = true; let pageCounter = p; while (hasNextPage) { await randomDelay(); await delPageComment(); hasNextPage = await gotoNextPage(); topicAdminOpts.append(`<div>页码${pageCounter}处理完毕</div>`); pageCounter++; } } async function delPageComment() { let topicReply = $('.topic-reply li'); for (let i = 0; i < topicReply.length; i++) { const comment = topicReply[i]; const authorId = $(comment).data('author-id'); // console.log('found id', authorId); // Check if the comment belongs to the target user if (authorId === targetUserId) { console.log('User id matched, delete it', authorId); await delComment(i, comment); } } } if (topicAdminOpts.children.length > 0) { topicAdminOpts.append(` <div id="auto-del-wrapper" style="display: flex; align-items: center; margin-top: 10px; gap: 8px;"> <label for="page-start-input" style="font-weight:bold; color:#ff0000;">起始页:</label> <input type="number" id="page-start-input" placeholder="1" style="width: 60px; padding: 4px; border: 1px solid #ccc; border-radius: 4px;"> <a id="auto-del" href="javascript:void(1);" style="padding: 6px 12px; background-color: #ff4d4f; color: white; border-radius: 4px; font-weight: bold; text-decoration: none;"> 自动删除我的评论 </a> </div> `); $('#auto-del').click(async e => { e.stopImmediatePropagation(); let pageStartInput = parseInt($('#page-start-input').val(), 10); let pageStart = (!isNaN(pageStartInput) && pageStartInput >= 1) ? pageStartInput : 1; console.log('Deletion start from page:', pageStart); await goToPage(pageStart); await autoDeleteAllComments(pageStart); topicAdminOpts.append(`<div>全部评论已删除。若意外中断,刷新后输入当前页码继续。</div>`); // setTimeout(() => location.reload(), 5000); }); } function delComment(i, e) { return new Promise(function (resolve, reject) { let cid = $(e).data('cid') $.post(`/j/group/topic/${tid}/remove_comment`, { ck: ck, cid: cid }, function(){ let targetText = $(e)[0].querySelector('.markdown').textContent.trim() topicAdminOpts.append(`<div>成功删除第${i+1}条评论:${targetText.substring(0, 20)}</div>`) resolve() }) }); } function gotoNextPage() { return new Promise((resolve) => { let nextLink = $('a:contains("后页")').attr('href'); if (nextLink) { console.log('Next page link:', nextLink); $.ajax({ url: nextLink, method: 'GET', success: function(data) { let newDom = $('<div></div>').html(data); // ✅ 更新普通评论 $('#comments').html(newDom.find('#comments').html()); // ✅ 清除最赞评论区域(第一页才有) $('#popular-comments').remove(); $('#content > div > div.article > h3').remove(); // ✅ 更新分页器 let newPaginator = newDom.find('.paginator'); if (newPaginator.length > 0) { $('.paginator').html(newPaginator.html()); } else { console.warn('新页面没有分页器'); } resolve(true); }, error: function() { console.error('加载下一页失败'); resolve(false); } }); } else { console.log('Last page reached. Congrats!'); resolve(false); } }); } function goToPage(pageNum) { // 如果是第 1 页,直接 resolve,不跳转 if (pageNum === 1) { console.log('Already at the 1st page.'); $('#popular-comments').remove(); $('#content > div > div.article > h3').remove(); return Promise.resolve(); } return new Promise((resolve, reject) => { let pageUrl = `/group/topic/${tid}/?start=${(pageNum - 1) * 100}`; console.log(`Jump to page ${pageNum}`, pageUrl); $.ajax({ url: pageUrl, method: 'GET', success: function(data) { let newDom = $('<div></div>').html(data); // 更新评论列表 $('.topic-reply').html(newDom.find('.topic-reply').html()); // 更新分页导航栏 let newPaginator = newDom.find('.paginator'); if (newPaginator.length > 0) { $('.paginator').html(newPaginator.html()); } else { console.warn('目标页面没有分页器'); } resolve(); }, error: function() { console.error('跳转页面失败'); reject(); } }); }); } })();