// ==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!");
}
);
})();