processItems(0); var count = data.length; btn_text.text(count_func(count)); }).catch(function(err) { console.clear(); // prevent console lag if (!active()) return; btn_text.text(original_text); }); }
function create_icon(icon_id, icon_class) { var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), use = document.createElementNS('http://www.w3.org/2000/svg', 'use'); use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "https://www.nexusmods.com/assets/images/icons/icons.svg#icon-" + icon_id); $(svg).addClass("icon icon-" + icon_class); svg.append(use); return svg; }
var btn_endorse_text = document.createElement("span"); $(btn_endorse_text).addClass("flex-label"); $(btn_endorse_text).text("Endorse all mods"); var btn_endorse_a = document.createElement("a"); $(btn_endorse_a).addClass("btn inline-flex"); btn_endorse_a.tabIndex = 0; btn_endorse_a.append(create_icon("endorse", "endorse")); btn_endorse_a.append(btn_endorse_text); $(btn_endorse_a).click(function() { work(1, $(btn_endorse_text), "Endorse all mods", function(count) { return "Endorsing " + count + " mods . . ."; }); }); var btn_endorse_li = document.createElement("li"); btn_endorse_li.append(btn_endorse_a); // Ensure #action-preview exists or use a more robust insertion point // For now, assuming it exists based on original script if ($("#action-preview").length) { $(btn_endorse_li).insertBefore("#action-preview"); } else { // Fallback or error handling if #action-preview is not found // e.g., append to a known parent or log an error console.warn("Nexus Endorsement Manager: #action-preview not found for button insertion."); // As a fallback, you might try to find a similar container // This is just an example, you might need to inspect the page for a better selector let container = $("ul.subby.subforum.double"); if (container.length) { container.first().prepend(btn_endorse_li); } else { // Or even just append to body if nothing else found, though not ideal // document.body.appendChild(btn_endorse_li); } }
var btn_abstain_text = document.createElement("span"); $(btn_abstain_text).addClass("flex-label"); $(btn_abstain_text).text("Abstain from endorsing all mods"); var btn_abstain_a = document.createElement("a"); $(btn_abstain_a).addClass("btn inline-flex"); btn_abstain_a.tabIndex = 0; btn_abstain_a.append(create_icon("ignore", "endorse")); btn_abstain_a.append(btn_abstain_text); $(btn_abstain_a).click(function() { work(0, $(btn_abstain_text), "Abstain from endorsing all mods", function(count) { return "Abstaining from endorsing " + count + " mods . . ."; }); }); var btn_abstain_li = document.createElement("li"); btn_abstain_li.append(btn_abstain_a); $(btn_abstain_li).insertAfter(btn_endorse_li); // This assumes btn_endorse_li was successfully inserted
// Add UI for delay configuration var delayContainer = document.createElement("li"); var delayLabel = document.createElement("label"); delayLabel.textContent = "Delay between requests (ms): "; var delayInput = document.createElement("input"); delayInput.type = "number"; delayInput.min = "0"; delayInput.value = "1000"; // Default value delayInput.style.marginLeft = "5px"; delayInput.style.width = "80px"; // --- ADDED STYLES FOR VISIBILITY --- delayInput.style.color = "black"; delayInput.style.backgroundColor = "white"; // --- END OF ADDED STYLES --- delayLabel.appendChild(delayInput); delayContainer.appendChild(delayLabel);
// Insert delayContainer before #action-preview, or after btn_abstain_li if #action-preview is problematic if ($("#action-preview").length) { $("#action-preview").before(delayContainer); } else if ($(btn_abstain_li).parent().length) { // If btn_abstain_li was inserted $(delayContainer).insertAfter(btn_abstain_li); } else { // Fallback for delayContainer if other elements also failed to insert console.warn("Nexus Endorsement Manager: Could not find a suitable place for delay input."); }
// Event listener for input change delayInput.addEventListener('input', function() { // On input change, ensure it is updated and valid const delay = getDelay(); console.log("New delay set: " + delay + " ms"); // Optional: debug output to check input changes });
// Function to get the current delay function getDelay() { const value = delayInput.value; if (value === "") return 1000; // Default to 1000ms if empty const parsedValue = parseInt(value, 10); return isNaN(parsedValue) || parsedValue < 0 ? 1000 : parsedValue; // Ensure non-negative } })();
Great script!
Updated version that works on current Nexus site and has throttling (adjustable via UI) to prevent getting rate limited/temp IP banned:
// ==UserScript==
// @name Nexus Endorsement Manager
// @version 1.2.0
// @description Adds buttons to the "My Nexus account" screen related to the mass endorsement and abstainment from endorsement of mods.
// @author pointfeev & wefalltomorrow
// @copyright 2021, pointfeev (https://github.com/pointfeev)
// @license MIT
// @match *://*.nexusmods.com/users/myaccount*
// @match *://*.nexusmods.com/settings/preferences*
// @icon https://www.nexusmods.com/favicon.ico
// @grant none
// @namespace https://github.com/pointfeev
// @homepageURL https://gist.github.com/pointfeev/aa70c3d600698df40141c3a79ad9bf59
// @downloadURL https://update.greasyfork.org/scripts/437215/Nexus%20Endorsement%20Manager.user.js
// @updateURL https://update.greasyfork.org/scripts/437215/Nexus%20Endorsement%20Manager.meta.js
// ==/UserScript==
(function() {
'use strict';
var requests = [];
function endorse(i, item, positive) {
return new Promise(function(resolve, reject) {
if (item[12] != positive) {
var request = $.ajax({
type: "POST",
url: "https://www.nexusmods.com/Core/Libs/Common/Managers/Mods?Endorse",
data: {
game_id: item[7],
mod_id: item[8],
positive: positive
},
dataType : 'json',
success: function (response) {
resolve(response);
requests.pop(request);
},
error: function(err) {
reject(err);
requests.pop(request);
}
});
requests.push(request);
}
else {
resolve();
}
});
}
var working = false;
var working_on = "none";
var working_index = 0;
var aborting = false;
function work(positive, btn_text, original_text, count_func) {
if (aborting) return;
if (working) {
if (working_on == original_text) {
aborting = true;
btn_text.text("Aborting . . .");
requests.forEach(function(request) {
request.abort();
requests.pop(request);
});
working = false;
working_on = "none";
aborting = false;
btn_text.text(original_text);
}
return;
}
requests.forEach(function(request) {
request.abort();
requests.pop(request);
});
working = true;
working_on = original_text;
working_index++;
var current_working_index = working_index;
function active()
{
return working && working_index == current_working_index;
}
btn_text.text("Requesting download history . . .");
new Promise(function(resolve, reject) {
var request = $.ajax({
type: "GET",
url: "https://www.nexusmods.com/Core/Libs/Common/Managers/Mods?GetDownloadHistory",
dataType : 'json',
success: function (response) {
resolve(response.data);
requests.pop(request);
},
error: function(err) {
reject(err);
requests.pop(request);
}
});
requests.push(request);
}).then(function(data) {
const delayInputValue = getDelay();
function processItems(index) {
if (!active() || index >= data.length) {
btn_text.text(original_text);
working = false;
working_on = "none";
return;
}
const item = data[index];
endorse(index, item, positive).then(function(response) {
if (!active()) return;
btn_text.text(count_func(data.length - index - 1));
setTimeout(() => processItems(index + 1), delayInputValue);
}).catch(function(err) {
console.clear(); // prevent console lag
if (!active()) return;
btn_text.text(count_func(data.length - index));
setTimeout(() => processItems(index), delayInputValue);
});
}
processItems(0);
var count = data.length;
btn_text.text(count_func(count));
}).catch(function(err) {
console.clear(); // prevent console lag
if (!active()) return;
btn_text.text(original_text);
});
}
function create_icon(icon_id, icon_class) {
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
use = document.createElementNS('http://www.w3.org/2000/svg', 'use');
use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "https://www.nexusmods.com/assets/images/icons/icons.svg#icon-" + icon_id);
$(svg).addClass("icon icon-" + icon_class);
svg.append(use);
return svg;
}
var btn_endorse_text = document.createElement("span");
$(btn_endorse_text).addClass("flex-label");
$(btn_endorse_text).text("Endorse all mods");
var btn_endorse_a = document.createElement("a");
$(btn_endorse_a).addClass("btn inline-flex");
btn_endorse_a.tabIndex = 0;
btn_endorse_a.append(create_icon("endorse", "endorse"));
btn_endorse_a.append(btn_endorse_text);
$(btn_endorse_a).click(function() {
work(1, $(btn_endorse_text), "Endorse all mods", function(count) {
return "Endorsing " + count + " mods . . .";
});
});
var btn_endorse_li = document.createElement("li");
btn_endorse_li.append(btn_endorse_a);
// Ensure #action-preview exists or use a more robust insertion point
// For now, assuming it exists based on original script
if ($("#action-preview").length) {
$(btn_endorse_li).insertBefore("#action-preview");
} else {
// Fallback or error handling if #action-preview is not found
// e.g., append to a known parent or log an error
console.warn("Nexus Endorsement Manager: #action-preview not found for button insertion.");
// As a fallback, you might try to find a similar container
// This is just an example, you might need to inspect the page for a better selector
let container = $("ul.subby.subforum.double");
if (container.length) {
container.first().prepend(btn_endorse_li);
} else {
// Or even just append to body if nothing else found, though not ideal
// document.body.appendChild(btn_endorse_li);
}
}
var btn_abstain_text = document.createElement("span");
$(btn_abstain_text).addClass("flex-label");
$(btn_abstain_text).text("Abstain from endorsing all mods");
var btn_abstain_a = document.createElement("a");
$(btn_abstain_a).addClass("btn inline-flex");
btn_abstain_a.tabIndex = 0;
btn_abstain_a.append(create_icon("ignore", "endorse"));
btn_abstain_a.append(btn_abstain_text);
$(btn_abstain_a).click(function() {
work(0, $(btn_abstain_text), "Abstain from endorsing all mods", function(count) {
return "Abstaining from endorsing " + count + " mods . . .";
});
});
var btn_abstain_li = document.createElement("li");
btn_abstain_li.append(btn_abstain_a);
$(btn_abstain_li).insertAfter(btn_endorse_li); // This assumes btn_endorse_li was successfully inserted
// Add UI for delay configuration
var delayContainer = document.createElement("li");
var delayLabel = document.createElement("label");
delayLabel.textContent = "Delay between requests (ms): ";
var delayInput = document.createElement("input");
delayInput.type = "number";
delayInput.min = "0";
delayInput.value = "1000"; // Default value
delayInput.style.marginLeft = "5px";
delayInput.style.width = "80px";
// --- ADDED STYLES FOR VISIBILITY ---
delayInput.style.color = "black";
delayInput.style.backgroundColor = "white";
// --- END OF ADDED STYLES ---
delayLabel.appendChild(delayInput);
delayContainer.appendChild(delayLabel);
// Insert delayContainer before #action-preview, or after btn_abstain_li if #action-preview is problematic
if ($("#action-preview").length) {
$("#action-preview").before(delayContainer);
} else if ($(btn_abstain_li).parent().length) { // If btn_abstain_li was inserted
$(delayContainer).insertAfter(btn_abstain_li);
} else {
// Fallback for delayContainer if other elements also failed to insert
console.warn("Nexus Endorsement Manager: Could not find a suitable place for delay input.");
}
// Event listener for input change
delayInput.addEventListener('input', function() {
// On input change, ensure it is updated and valid
const delay = getDelay();
console.log("New delay set: " + delay + " ms"); // Optional: debug output to check input changes
});
// Function to get the current delay
function getDelay() {
const value = delayInput.value;
if (value === "") return 1000; // Default to 1000ms if empty
const parsedValue = parseInt(value, 10);
return isNaN(parsedValue) || parsedValue < 0 ? 1000 : parsedValue; // Ensure non-negative
}
})();