Greasy Fork is available in English.
批量删除在别人个人资料下的留言
// ==UserScript==// @name Delete_My_Comment// @name:zh-CN 批量删除个人资料留言// @namespace https://blog.chrxw.com// @version 1.1// @description 批量删除在别人个人资料下的留言// @description:zh-CN 批量删除在别人个人资料下的留言// @author Chr_// @include /https://steamcommunity\.com/(id|profiles)/[^\/]+/commenthistory/?/// @license AGPL-3.0// @icon https://blog.chrxw.com/favicon.ico// @grant GM_addStyle// ==/UserScript==(async () => {'use strict';let GObjs = {};addGui();//添加UIfunction addGui() {function genBtn(name, foo) {const b = document.createElement('button');b.textContent = name;b.className = 'dmc_btn';b.addEventListener('click', foo);return b;}function genDiv(cls) {const d = document.createElement('div');d.className = cls ?? 'dmc_div';return d;}function genText() {const t = document.createElement('textarea');t.className = 'dmc_txt';return t;}function genNum() {const t = document.createElement('input');t.type = 'number';t.value = 0;t.min = 0;t.className = 'dmc_ipt';return t;}function genSpan(txt) {const t = document.createElement('span');t.textContent = txt;t.className = 'dmc_span';return t;}const rightDiv = document.querySelector("div.rightbox");const divArea = genDiv('dmc_panel');const btnStart = genBtn('开始删除', async () => {const startPage = parseInt(iptPage.value);if (startPage !== startPage) {ShowAlertDialog("错误", "只能输入整数");} else {const endPage = getPageCount();try {btnStart.textContent = '执行中';btnStart.disabled = true;await startDeleteComments(startPage, endPage);}finally {btnStart.textContent = '开始删除';btnStart.disabled = false;}}});const iptPage = genNum();const txtLog = genText();const divHide = genDiv('dmc_hide');rightDiv.appendChild(divArea);divArea.appendChild(btnStart);divArea.appendChild(genSpan('开始页码:'));divArea.appendChild(iptPage);divArea.appendChild(txtLog);divArea.appendChild(divHide);Object.assign(GObjs, { txtLog, divHide });}//批量删除留言async function startDeleteComments(startPage, endPage) {const { divHide, txtLog } = GObjs;const genTmp = () => {const d = document.createElement('div');divHide.appendChild(d);return d;};const log = (msg) => {if (txtLog.value) {txtLog.value += "\n";}txtLog.value += msg;txtLog.scrollTop = txtLog.scrollHeight;};log(`1 开始运行, 页码设置: ${startPage} / ${endPage}`);const baseUri = location.origin + location.pathname;for (let i = startPage; i <= endPage; i++) {log(`2 开始读取第 ${i} 页历史记录`);const historyUrl = `${baseUri}?p=${i}`;const response = await loadPage(historyUrl);if (response) {const tmp = genTmp();tmp.innerHTML = response;const links = fetchCommentFromHistory(tmp);divHide.removeChild(tmp);const count = links.length;if (count > 0) {log(`3 获取了 ${links.length} 条留言记录`);for (let link of links) {log('4 开始读取留言');const resp = await loadPage(link);if (response) {const ss = genTmp();ss.innerHTML = resp;const rst = fetchProfileComments(ss);const tasks = [];const gids = new Set();const cnt = rst.length;if (cnt > 0) {log(`5 获取了 ${cnt} 条留言记录`);for (let [steamid, gid] of rst) {if (!gids.has(gid)) {gids.add(gid);tasks.push(makePromise(steamid, gid));}}if (tasks.length > 0) {log(`5 总计 ${tasks.length} 条留言, 开始删除`);await Promise.all(tasks);} else {log('5 未找到可以删除的留言');}} else {log('5 未找到留言记录');}divHide.removeChild(ss);}else {log('4 读取失败');}}}else {log('3 无留言记录,跳过');}} else {log('2 读取失败');}}log('1 运行结束');function makePromise(steamid, gid) {return new Promise((resolve, reject) => {deleteComment(steamid, gid).then(() => {log(`> 删除留言 ${gid} 成功`);}).catch((reason) => {log(`> 删除留言 ${gid} 失败`);}).finally(() => {resolve();});});}}//获取总页数function getPageCount() {const pages = document.querySelectorAll("div.pageLinks>a.pagelink");if (pages.length === 0) {return 0;} else {const lastPage = parseInt(pages[pages.length - 1].textContent.replace(/[,.]/g, ""));return lastPage === lastPage ? lastPage : 0;}}//获取历史留言记录function fetchCommentFromHistory(element) {const comments = element.querySelectorAll("div.commenthistory_comment:not(.deleted) a");const matchLinks = new RegExp(/https:\/\/steamcommunity\.com\/(id|profiles)\/[^\/]+\/?\?tscn=\d+$/g);const r###lt = [];for (let comment of comments) {const href = comment.href;if (matchLinks.test(href)) {r###lt.push(href);}}return r###lt;}// 读取网页async function loadPage(href) {return new Promise((resolve, reject) => {fetch(href, {method: "GET",credentials: "include",}).then(async (response) => {if (response.ok) {const data = await response.text();resolve(data.trim());} else {resolve(null);}}).catch((err) => {console.error(err);resolve(null);});});}// 匹配所有自己的留言function fetchProfileComments(element) {const comments = element.querySelectorAll("a.actionlink:not(.report_and_hide)");const matchLinks = new RegExp(/'(\S+)'/g);const r###lt = [];for (let comment of comments) {const href = comment.href;const match = href.match(matchLinks);if (match && match.length >= 2) {const steamId = match[0].replace("Profile_", "").replace(/'/g, "");const commentId = match[1].replace(/'/g, "");r###lt.push([steamId, commentId]);}}return r###lt;}const SessionId = document.cookie.replace(/(?:(?:^|.*;\s*)sessionid\s*\=\s*([^;]*).*$)|^.*$/, "$1");// 删除指定留言async function deleteComment(steamId, gidComment) {const data = {"gidcomment": gidComment,"start": 0,"count": 6,"sessionid": SessionId,"feature2": -1,"lastvisit": 0};let s = '';for (let k in data) {s += `${k}=${data[k]}&`;}return new Promise((resolve, reject) => {fetch(`https://steamcommunity.com/comment/Profile/delete/${steamId}/-1/`, {method: "POST",credentials: "include",body: s,headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',},}).then(async (response) => {if (response.ok) {const data = await response.json();const r###lt = data.success ?? false;resolve(r###lt);} else {resolve(false);}}).catch((err) => {reject(err);});});}GM_addStyle(`.dmc_panel {padding: 15px;}.dmc_span {margin-left: 10px;margin-right: 10px;}.dmc_ipt {text-align: center;width: 50px;}.dmc_txt {margin-top: 10px;width: 100%;height: 300px;}.dmc_hide {display: none;}`);})();