Stop tracking multiple mods at once on Nexus Mods.
// ==UserScript==
// @name Stop Tracking Mods
// @namespace https://github.com/ewigl/nexusmods-stop-tracking-mods
// @version 1.0.3
// @description Stop tracking multiple mods at once on Nexus Mods.
// @author Licht
// @license MIT
// @homepage https://github.com/ewigl/nexusmods-stop-tracking-mods
// @icon https://www.nexusmods.com/favicon.ico
// @match https://www.nexusmods.com/mods/trackingcentre*
// @match https://www.nexusmods.com/*/mods/trackingcentre*
// @grant GM_addStyle
// ==/UserScript==
; (function () {
'use strict';
// "UPDATED" label
GM_addStyle(`
.tracking-highlight {
left: 31px;
}
#batch-untrack-btn:hover {
opacity: 0.9;
}
`)
function initBatchUntrack() {
const trackingTable = document.querySelector('.mod-table.mod-tracking-table');
if (!trackingTable) return;
const hasMods = trackingTable.querySelector('tbody tr .tracking-mod') !== null;
let untrackControls = document.getElementById('batch-untrack-controls');
if (!untrackControls) {
untrackControls = document.createElement('div');
untrackControls.id = 'batch-untrack-controls';
untrackControls.style.display = hasMods ? 'flex' : 'none';
untrackControls.style.justifyContent = 'flex-start';
untrackControls.style.alignItems = 'center';
untrackControls.style.margin = "8px 0"
untrackControls.innerHTML = `
<input
type="checkbox"
id="select-all-untrack"
style="transform: scale(1.3); margin: 0 12px 0 6px; cursor: pointer;"
>
<button
id="batch-untrack-btn"
style="
width: 100px;
height: 60px;
padding: 4px;
font-size: 14px;
font-weight: bold;
background-color: #da3e3e;
color: white;
border-radius: 4px;
border: none;
cursor: pointer;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
"
>
Stop Tracking
</button>
`;
trackingTable.parentNode.insertBefore(untrackControls, trackingTable.nextSibling);
document.getElementById('select-all-untrack').addEventListener('change', (e) => {
const rowCbs = document.querySelectorAll('.batch-untrack-cb');
rowCbs.forEach(cb => {
cb.checked = e.target.checked;
});
});
document.getElementById('batch-untrack-btn').addEventListener('click', (e) => {
e.preventDefault();
const checkedCbs = document.querySelectorAll('.batch-untrack-cb:checked');
if (checkedCbs.length === 0) {
alert('Please select at least 1 mod.');
return;
}
if (!confirm(`Are you sure you want to stop tracking these ${checkedCbs.length} mods(s)?`)) {
return;
}
// Click "Stop tracking"
checkedCbs.forEach(cb => {
const tr = cb.closest('tr');
const untrackBtn = tr.querySelector('.toggle-track-mod');
if (untrackBtn) {
untrackBtn.click();
const wrapper = cb.closest('.batch-untrack-wrapper');
if (wrapper) wrapper.style.display = 'none';
}
});
document.getElementById('select-all-untrack').checked = false;
});
} else {
untrackControls.style.display = hasMods ? 'flex' : 'none';
}
if (!hasMods) return;
const tbodyTrs = trackingTable.querySelectorAll('tbody tr');
tbodyTrs.forEach(tr => {
const modNameTd = tr.querySelector('.tracking-mod');
if (modNameTd && !modNameTd.querySelector('.batch-untrack-cb')) {
modNameTd.insertAdjacentHTML('afterbegin', `
<div class="batch-untrack-wrapper" style="display: inline-block; vertical-align: middle; margin: 0 12px 0 6px;">
<input type="checkbox" class="batch-untrack-cb" style="transform: scale(1.3); cursor: pointer; margin: 0;">
</div>
`);
}
});
}
let observerTimeout = null;
const observer = new MutationObserver((_mutations) => {
clearTimeout(observerTimeout);
observerTimeout = setTimeout(() => {
const table = document.querySelector('.mod-table.mod-tracking-table');
if (table) {
const isControlsMissing = !document.getElementById('batch-untrack-controls');
const hasModRows = table.querySelector('.tracking-mod') !== null;
const isCheckboxMissing = hasModRows && !table.querySelector('.batch-untrack-cb');
if (isControlsMissing || isCheckboxMissing) {
initBatchUntrack();
}
}
}, 100);
});
const targetContainer = document.querySelector('.tabcontent') || document.querySelector('.wrapper') || document.body;
observer.observe(targetContainer, {
childList: true,
subtree: true
});
window.addEventListener('load', initBatchUntrack);
})();