Last active
May 8, 2025 11:40
-
-
Save wefalltomorrow/42095f51e9558b44edef39277930ca6d to your computer and use it in GitHub Desktop.
Nexus Endorsement Manager - Fork
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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 | |
// @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(); // Already in desired state | |
} | |
}); | |
} | |
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(); | |
const originalCount = data.length; | |
const filteredData = data.filter(item => item[12] !== positive); | |
const skippedCount = originalCount - filteredData.length; | |
if (skippedCount > 0) { | |
console.log(`Skipped ${skippedCount} mods that were already ${positive ? 'endorsed' : 'not endorsed/abstained'}.`); | |
} | |
function processItems(index) { | |
if (!active() || index >= filteredData.length) { | |
btn_text.text(original_text + (skippedCount > 0 ? ` (Skipped ${skippedCount})` : "")); | |
working = false; | |
working_on = "none"; | |
return; | |
} | |
const item = filteredData[index]; | |
const modName = item[0] || `Mod ID ${item[8]}`; | |
endorse(index, item, positive).then(function (response) { | |
if (!active()) return; | |
console.log(`${positive ? 'Endorsed' : 'Abstained from'} \"${modName}\"`); | |
btn_text.text(count_func(filteredData.length - index - 1)); | |
setTimeout(() => processItems(index + 1), delayInputValue); | |
}).catch(function (err) { | |
console.clear(); | |
if (!active()) return; | |
console.error(`Error processing \"${modName}\":`, err); | |
btn_text.text(count_func(filteredData.length - index)); | |
setTimeout(() => processItems(index), delayInputValue); | |
}); | |
} | |
processItems(0); | |
btn_text.text(count_func(filteredData.length)); | |
}).catch(function (err) { | |
console.clear(); | |
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 = $("<span class='flex-label'>Endorse all mods</span>"); | |
var btn_endorse_a = $("<a class='btn inline-flex' tabindex='0'></a>"); | |
btn_endorse_a.append(create_icon("endorse", "endorse"), btn_endorse_text); | |
btn_endorse_a.click(() => work(1, btn_endorse_text, "Endorse all mods", count => `Endorsing ${count} mods . . .`)); | |
var btn_endorse_li = $("<li></li>").append(btn_endorse_a); | |
if ($("#action-preview").length) { | |
btn_endorse_li.insertBefore("#action-preview"); | |
} else { | |
let container = $("ul.subby.subforum.double"); | |
if (container.length) container.first().prepend(btn_endorse_li); | |
} | |
var btn_abstain_text = $("<span class='flex-label'>Abstain from endorsing all mods</span>"); | |
var btn_abstain_a = $("<a class='btn inline-flex' tabindex='0'></a>"); | |
btn_abstain_a.append(create_icon("ignore", "endorse"), btn_abstain_text); | |
btn_abstain_a.click(() => work(0, btn_abstain_text, "Abstain from endorsing all mods", count => `Abstaining from endorsing ${count} mods . . .`)); | |
var btn_abstain_li = $("<li></li>").append(btn_abstain_a); | |
btn_abstain_li.insertAfter(btn_endorse_li); | |
// Delay input UI | |
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"; | |
delayInput.style.marginLeft = "5px"; | |
delayInput.style.width = "80px"; | |
delayInput.style.color = "black"; | |
delayInput.style.backgroundColor = "white"; | |
delayLabel.appendChild(delayInput); | |
delayContainer.appendChild(delayLabel); | |
if ($("#action-preview").length) { | |
$("#action-preview").before(delayContainer); | |
} else if (btn_abstain_li.parent().length) { | |
$(delayContainer).insertAfter(btn_abstain_li); | |
} else { | |
console.warn("Nexus Endorsement Manager: Could not find a suitable place for delay input."); | |
} | |
delayInput.addEventListener('input', () => { | |
const delay = getDelay(); | |
console.log("New delay set: " + delay + " ms"); | |
}); | |
function getDelay() { | |
const value = delayInput.value; | |
if (value === "") return 1000; | |
const parsed = parseInt(value, 10); | |
return isNaN(parsed) || parsed < 0 ? 1000 : parsed; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment