您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A script that deletes all deletable comments posted from your account
// ==UserScript== // @name Steam Comments Cleaner // @namespace https://greasyfork.org/en/users/961305-darkharden // @match https://steamcommunity.com/id/*/commenthistory // @version 1.0.0 // @author Created by Justman (steamcommunity.com/id/justman666). Fixed by Portal124 (moddb) // @description A script that deletes all deletable comments posted from your account // @license MIT // ==/UserScript== // TO-DO // 1. 6x6 comment function // 2. Comment remover script - https://greasyfork.org/en/scripts/26473-steam-community-comments-remover // 3. Rate Entire Activity Feed - https://steamcommunity.com/sharedfiles/filedetails/?id=1442281864 / https://steamcommunity.com/sharedfiles/filedetails/?id=1198512278 // 4. Centering text in info box / bios (function () { "use strict"; let version = GM_info.script.version; console.log(`Steam Comments Cleaner ${version}`); /* Execute this code on https://steamcommunity.com/my/commenthistory This is the newest version. Created by Justman (steamcommunity.com/id/justman666) Fixed by Portal124 (moddb) Idk why it isn't maintained anymore but the dev should really get on that or at least post a disclaimer :) */ /* Changable constants */ var FIRST_PAGE_TO_CLEAR = 1; // Number of first page to be cleared var LAST_PAGE_TO_CLEAR = -1; // Number of last page to clear. -1 if you need to delete all of them // Example (2, 2) will clear 2nd page only var PRINT_EXECUTED_COMMANDS = true; // Print everything script does (It's a lot) /* Constants */ var COMMENTS_PAGE = "https://steamcommunity.com/my/commenthistory"; // URL to page with comments var FORUMS_JS_URL = ["https://steamcommunity.com/public/javascript/forums.js", "https://steamcommunity-a.akamaihd.net/public/javascript/forums.js", "https://community.edgecast.steamstatic.com/public/javascript/forums.js"]; // URL to page with forums.js var FORUM_JS_LOAD_TIMEOUT = 10000; // ms var USER_STEAM_PROFILE_URL = jQuery("#global_actions > a").attr("href").replace(/\/$/, ""); // https://steamcommunity.com/id/$ID var PAGE_REQUESTS_INTERVAL = 5500; // ms var TIMESTAMP_DIFF = 3; // Maximum difference between timestamps var REGEXP = { "body": /<body.{1,}?>([.\s\S]{1,})<\/body>/, // Body innerHTML (No depending on attributes) "link": /^(.{1,}?)(?:\?(.{1,}?))?$/, // Link -> url + data "initFTopic": /InitializeForumTopic\s?\([^"]+?(?:"[^"]+?"[^"]+?)+?[^"]+?\);/, // Protected from ); in quotes "initCThread": /InitializeCommentThread\s?\([^"]+?(?:"[^"]+?"[^"]+?)+?[^"]+?\);/, // Protected from ); in quotes }; /* Utility */ var pages_amount = jQuery(".pageLinks .pagelink:last").html(); // Amount of pages if (!pages_amount) { pages_amount = 1; } else { pages_amount = +pages_amount; } var pages = []; // Array with page bodies var comments = []; // Array with comments to clean var execute = function ( txt // Replacer to eval to be able to see commands printed ) { if (PRINT_EXECUTED_COMMANDS) { console.log(txt); } eval(txt); }; /* Functions */ var loadPagesFrom = function ( fromPageNumber, callback // Loading page body with comments and adding it to pages as div ) { if (fromPageNumber > pages_amount || (LAST_PAGE_TO_CLEAR != -1 && fromPageNumber > LAST_PAGE_TO_CLEAR)) { console.log("Loaded pages"); console.log(pages); if (typeof callback == "function") { callback(); } return; } console.log("Loading page #" + fromPageNumber); if (location.search.match(new RegExp("p=" + fromPageNumber)) || fromPageNumber == 1) { var elem = document.createElement("div"); elem.innerHTML = document.body.innerHTML; pages.push(elem); console.log("Loaded page #" + fromPageNumber); loadPagesFrom(fromPageNumber + 1, callback); return; } var search = location.search.replace(/\?/, ""); // Delete first ? if it exists if (search) { // Search is not empty if (search.match(/p=[0-9]{1,}/)) { // Page number is already stated (it must be 1) search = search.replace(/p=[0-9]{1,}/, "p=" + fromPageNumber); } else { // No page number but have some search parameters search += "&p=" + fromPageNumber; } } else { // empty search search = "p=" + fromPageNumber; } jQuery.ajax({ "success": function (data, status) { var inner = data.match(REGEXP.body)[1]; var elem = document.createElement("div"); elem.innerHTML = inner; pages.push(elem); console.log(" Loaded page #" + fromPageNumber); loadPagesFrom(fromPageNumber + 1, callback); }, "fail": function () { console.error(" Steam Comments Cleaner -->Unable to load page"); }, "data": search, "method": "GET", "url": COMMENTS_PAGE, }); }; var loadURLsFrom = function ( fromPageNumber, callback // Loading URLs and adding them to comments as objects ) { if (fromPageNumber > pages.length) { console.log(" Loaded URLs"); console.log(comments); if (typeof callback == "function") { callback(); } return; } jQuery(pages[fromPageNumber - 1]) .find(".commenthistory_comment .comment_item_title a") .each(function (index, a) { var info = {}; // Info about comment var link = a.href; link = link.replace(/#/, "/"); // Getting rid of # (replacable with /) if (link.match(/\/discussions\//)) { info["isForum"] = true; } else { info["isForum"] = false; } var m = link.match(REGEXP.link); info["link"] = link; // Full link info["url"] = m[1]; // Link with no GET args info["data"] = m[2]; // GET args (key=val&key=val...) if (info["data"] && info["data"].match(/tscn=[0-9]{1,}/)) { info["timestamp"] = info["data"].match(/tscn=([0-9]{1,})/)[1]; // Timestamp } if (info["isForum"]) { if (info["data"] && info["data"].match(/tscn=/)) { info["isForumTopic"] = false; } else { info["isForumTopic"] = true; } } info["text"] = jQuery(a).closest(".commenthistory_comment").find(".comment_text").text().replace(/\s/g, ""); comments.push(info); }); console.log(" Loaded URLs from page #" + (fromPageNumber + FIRST_PAGE_TO_CLEAR - 1)); loadURLsFrom(fromPageNumber + 1, callback); }; var clearURLfromIndex = function ( index, callback // Clearing comment form comments array by its index ) { if (index >= comments.length) { console.log("Cleared URLs"); console.log(comments); if (typeof callback == "function") { window.location.hash = ""; // Removing previously set hash callback(); } return; } window.location.hash = "#p0"; // Can't initialize Comment thread without this hash (Crutch ._ .) jQuery.ajax({ "success": function (data, status) { try { comments[index]["html"] = document.createElement("div"); comments[index]["html"].innerHTML = data; if (jQuery(comments[index]["html"]).find("#message").length) { throw new Error(jQuery(comments[index]["html"]).find("#message").text()); } if (comments[index]["isForum"]) { var initFTopic = jQuery(comments[index]["html"]).find("script:contains(InitializeForumTopic)").html(); // Code to be executed initFTopic = initFTopic.match(REGEXP.initFTopic)[0]; // Getting main command execute(initFTopic); var initCThread = jQuery(comments[index]["html"]).find("script:contains(InitializeCommentThread)").html(); // Code to be executed initCThread = initCThread.match(REGEXP.initCThread)[0]; // Getting main command initCThread = initCThread.replace(/\{/, '{"no_paging": true, '); // Adding no paging to prevent error execute(initCThread); if (comments[index]["isForumTopic"]) { // Topic var deleteTopic = jQuery(comments[index]["html"]).find('.forum_op a[href*="DeleteTopic"]'); var argument = jQuery(deleteTopic) .attr("href") .match(/\(([.\s\S]{1,}?)\)/)[1] .replace(/[\s'"]/g, ""); new Ajax.Request(g_rgForumTopics[argument].GetActionURL("deletetopic"), { "method": "POST", "parameters": g_rgForumTopics[argument].ParametersWithDefaults(), }); } else { // Message var messagesByUser = jQuery(comments[index]["html"]) .find('.commentthread_comment .commentthread_comment_avatar a[href*="' + USER_STEAM_PROFILE_URL + '"]') .closest(".commentthread_comment"); // Messages on the page by user var ifFoundMessage = false; messagesByUser.each(function (i, message) { var text = jQuery(message).find(".commentthread_comment_text").text().replace(/\s/g, ""); // innerText of message var timestamp = jQuery(message).find(".commentthread_comment_timestamp").attr("data-timestamp"); // Timestamp of message if (text == comments[index]["text"] && Math.abs(+timestamp - +comments[index]["timestamp"]) < TIMESTAMP_DIFF) { var deleteComment = jQuery(message).find('a[href*="DeleteComment"]').attr("href"); if (!deleteComment) { throw new Error('\nWas unable to find "Delete" button. Possibly you can\'t delete message from this group\n'); } deleteComment = deleteComment.replace(/javascript:/, ""); var args = deleteComment.match(/\(([.\s\S]{1,}?),([.\s\S]{1,}?)\)/); // Arguments // args looks like: " 'STRING' ". It may have [\s'"] in it execute("g_rgCommentThreads[" + args[1] + "].GetForumTopic().m_rgForumData.permissions.can_moderate = 1;"); // Need to prevent confirmation (execute is used just to be able to replace it with console.log. Also this is effective as we keep argument as it was at DeleteComment()) execute("g_rgCommentThreads[" + args[1] + "].DeleteComment(" + args[2] + ");"); ifFoundComment = true; return false; // break } }); } } else { // Comment if (comments[index]["url"].match(/\/id\//) && !jQuery(comments[index]["html"]).find(".commentthread_comments").length) { throw new Error("\nCan not delete comment. As profile owner locked his page and deleted you from friends\n"); } var initCThread = jQuery(comments[index]["html"]).find("script:contains(InitializeCommentThread)").html(); // Code to be executed initCThread = initCThread.match(REGEXP.initCThread)[0]; // Getting main command initCThread = initCThread.replace(/\{/, '{"no_paging": true, '); // Adding no paging to prevent error execute(initCThread); var commentsByUser = jQuery(comments[index]["html"]) .find('.commentthread_comment .commentthread_comment_avatar a[href*="' + USER_STEAM_PROFILE_URL + '"]') .closest(".commentthread_comment"); // Comments on the page by user var ifFoundComment = false; commentsByUser.each(function (i, comment) { var text = jQuery(comment).find(".commentthread_comment_text").text().replace(/\s/g, ""); // innerText of comment var timestamp = jQuery(comment).find(".commentthread_comment_timestamp").attr("data-timestamp"); // Timestamp of comment if (text == comments[index]["text"] && Math.abs(+timestamp - +comments[index]["timestamp"]) < TIMESTAMP_DIFF) { var deleteComment = jQuery(comment) .find('a[href*="DeleteComment"]') .attr("href") .replace(/javascript:/, ""); if (!deleteComment) { throw new Error('\nWas unable to find "Delete" button\n'); } execute(deleteComment); ifFoundComment = true; return false; // break } }); if (!ifFoundComment) { throw new Error("\nWas unable to find users comment\n"); } } console.log("Cleaned comment #" + (index + 1)); } catch (e) { console.error("Steam Comments Cleaner --> Can not clean comment #" + (index + 1)); console.error(comments[index]); console.error(e); } var nextTimeout = setTimeout(function () { clearURLfromIndex(index + 1, callback); }, PAGE_REQUESTS_INTERVAL); }, "fail": function () { console.error("Steam Comments Cleaner --> Unable to send request"); }, "data": comments[index]["data"], "method": "GET", "url": comments[index]["url"], }); }; var loadForumJS = function (i, callback, onFail) { var timeout = setTimeout(function () { // Setting timeout as reject of load is not supported with getScript console.error("Steam Comments Cleaner --> Error occured loading forum.js #" + i + " - timeout"); if (i + 1 < FORUMS_JS_URL.length) { // Still have some links console.error("Steam Comments Cleaner --> Trying next link"); loadForumJS(i + 1, callback, onFail); // Trying another one } else { // Tryed everything console.error("Steam Comments Cleaner --> No links left"); if (typeof onFail == "function") { onFail(); } } }, FORUM_JS_LOAD_TIMEOUT); console.log("Steam Comments Cleaner --> Trying forum.js #" + i + ". Will try next in " + FORUM_JS_LOAD_TIMEOUT / 1000 + " seconds if this wont work"); jQuery .getScript(FORUMS_JS_URL[i]) .done(function () { // Require forum.js to delete forum messages // Needed script is loaded and no errors detected console.log("Steam Comments Cleaner --> Loaded forum.js #" + i); clearTimeout(timeout); // Stop timeout if (typeof callback == "function") { callback(); } }) .fail(function () { console.error("Steam Comments Cleaner --> Error occurred loading forum.js #" + i); console.error("Steam Comments Cleaner --> Trying next link"); if (i + 1 < FORUMS_JS_URL.length) { loadForumJS(i + 1, callback, onFail); // Trying another one } else { if (typeof onFail == "function") { onFail(); } } }); }; /* Main */ loadForumJS( 0, function () { console.log("Steam Comments Cleaner --> Starts here"); console.log("profile_header_actions"); function setCommentsCleanerButton() { const uploadCustomArtworkButtonContainer = document.createElement("div"); uploadCustomArtworkButtonContainer.className = "rightbox"; // Create Buttons uploadCustomArtworkButtonContainer.innerHTML = ` <div class="profile_count_link addtocartbutton_Action_2ECxA CartBtn" style="margin-top:20px"> <span class="clean-comments-link" href="#">Clean Comments</span> </div> `; // Grab mainContentsDiv element reference const uploadArtworkButtonReferenceParent = document.querySelector(".rightbox .content"); const uploadArtworkButtonReferenceChild = document.querySelector(".rightbox .content > div:last-child"); // Insert the Buttons uploadArtworkButtonReferenceParent.insertBefore(uploadCustomArtworkButtonContainer, uploadArtworkButtonReferenceChild); const buttonCommentsCleaner = document.querySelector(".clean-comments-link"); buttonCommentsCleaner.addEventListener("click", () => { console.log("buttonCommentsCleaner clicked"); loadCommentsCleaner(); }); } setTimeout(setCommentsCleanerButton, 0); function loadCommentsCleaner() { loadPagesFrom(FIRST_PAGE_TO_CLEAR, function () { loadURLsFrom(1, function () { clearURLfromIndex(0, function () { alert("Steam Comments Cleaner --> Done"); }); }); }); } }, function () { alert("Steam Comments Cleaner --> Can not load forum.js!"); } ); })();