您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Dynamically numbers duplicate OC roles based on slot order
当前为
// ==UserScript== // @name OC Role Display // @namespace http://tampermonkey.net/ // @version 1.2.0 // @description Dynamically numbers duplicate OC roles based on slot order // @author Allenone [2033011] // @match https://www.torn.com/factions.php?step=your* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant GM_info // @license MIT // ==/UserScript== (async function() { 'use strict'; let globalObserver = null; let processing = false; const roleMappings = {}; const debounceDelay = 200; const requestIdleCallback = window.requestIdleCallback || function(callback) { return setTimeout(callback, 200); }; function processScenario(element) { const ocName = element.querySelector('.panelTitle___aoGuV')?.innerText.trim() || "Unknown"; const slots = element.querySelectorAll('.wrapper___Lpz_D'); if (!roleMappings[ocName]) { const slotsWithPosition = Array.from(slots).map(slot => { const slotFiberKey = Object.keys(slot).find(key => key.startsWith("__reactFiber$")); if (!slotFiberKey) return null; const fiberNode = slot[slotFiberKey]; const positionKey = fiberNode.return.key.replace('slot-', ''); const positionNumber = parseInt(positionKey.match(/P(\d+)/)?.[1] || 0, 10); return { slot, positionNumber }; }).filter(Boolean); slotsWithPosition.sort((a, b) => a.positionNumber - b.positionNumber); const originalNames = slotsWithPosition.map(({ slot }) => { return slot.querySelector('.title___UqFNy')?.innerText.trim() || "Unknown"; }); const frequencyMap = originalNames.reduce((acc, name) => { acc[name] = (acc[name] || 0) + 1; return acc; }, {}); const displayNames = []; const countTracker = {}; originalNames.forEach(name => { if (frequencyMap[name] > 1) { countTracker[name] = (countTracker[name] || 0) + 1; displayNames.push(`${name} ${countTracker[name]}`); } else { displayNames.push(name); } }); roleMappings[ocName] = displayNames; } slots.forEach(slot => { const slotFiberKey = Object.keys(slot).find(key => key.startsWith("__reactFiber$")); if (!slotFiberKey) return; const fiberNode = slot[slotFiberKey]; const positionKey = fiberNode.return.key.replace('slot-', ''); const positionNumber = parseInt(positionKey.match(/P(\d+)/)?.[1] || 0, 10); const roleIndex = positionNumber - 1; const displayName = roleMappings[ocName][roleIndex]; const roleElement = slot.querySelector('.title___UqFNy'); if (displayName && roleElement && roleElement.innerText !== displayName) { roleElement.innerText = displayName; } }); } function doOnHashChange() { if (processing) return; processing = true; requestIdleCallback(() => { try { const ocElements = document.querySelectorAll('.wrapper___U2Ap7:not(.role-processed)'); ocElements.forEach(element => { element.classList.add('role-processed'); processScenario(element); }); } finally { processing = false; } }); } function observeButtonContainer() { let buttonContainer = document.querySelector('.buttonsContainer___aClaa'); if (buttonContainer) { buttonContainer.addEventListener('click', () => { document.querySelectorAll('.wrapper___U2Ap7').forEach(el => { el.classList.remove('role-processed'); }); doOnHashChange(); }); } else { setTimeout(observeButtonContainer, 500); } } function setupHashChangeListener() { window.addEventListener('hashchange', () => { document.querySelectorAll('.wrapper___U2Ap7.role-processed').forEach(el => { el.classList.remove('role-processed'); }); doOnHashChange(); }); } function initializeScript() { if (globalObserver) globalObserver.disconnect(); const targetNode = document.querySelector('#factionCrimes-root') || document.body; globalObserver = new MutationObserver(debounce(() => { if (!document.querySelector('.wrapper___U2Ap7')) return; doOnHashChange(); }, debounceDelay)); globalObserver.observe(targetNode, { childList: true, subtree: true, attributes: false, characterData: false }); doOnHashChange(); observeButtonContainer(); setupHashChangeListener(); } function debounce(func, wait) { let timeout; return function(...args) { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; } if (document.readyState === 'complete') { initializeScript(); } else { window.addEventListener('load', initializeScript); } })();