您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show how much cooldown & expiration is left for targets
// ==UserScript== // @name Torn Crimes Scamming Timers // @namespace https://github.com/SOLiNARY // @version 0.3.1 // @description Show how much cooldown & expiration is left for targets // @author Ramin Quluzade, Silmaril [2665762] // @license MIT License // @match https://www.torn.com/loader.php?sid=crimes* // @match https://torn.com/loader.php?sid=crimes* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant GM_addStyle // @grant unsafeWindow // @run-at document-start // ==/UserScript== (async function() { 'use strict'; const showExpiration = true; const showCooldown = true; const timeElementsToShow = 2; // Options: 1,2,3,4 const scammingCrimesUrl = 'loader.php?sid=crimesData&step=crimesList&rfcv=' const observerConfig = { childList: true, subtree: true }; let foundTargets = false; let noTargets = false; let targets = {}; const isTampermonkeyEnabled = typeof unsafeWindow !== 'undefined'; const isMobileView = window.innerWidth <= 784; const { fetch: originalFetch } = isTampermonkeyEnabled ? unsafeWindow : window; const customFetch = async (...args) => { let [resource, config] = args; let response = await originalFetch(resource, config); if (response.url.indexOf(scammingCrimesUrl) >= 0 && window.location.href.includes('crimes#/scamming')) { targets = {}; try { const jsonData = await response.clone().json(); jsonData.DB.crimesByType.targets.forEach((target, index) => { let expireTimestamp = target.expire.toString().length == 10 ? target.expire : target.expire.toString().substr(0, 10); // Fix for Torn's long timestamps bug let cooldownTimestamp = null; if (target.cooldown > 0){ cooldownTimestamp = target.cooldown.toString().length == 10 ? target.cooldown : target.cooldown.toString().substr(0, 10); // Fix for Torn's long timestamps bug } targets[index] = { email: target.email, expire: expireTimestamp, cooldown: cooldownTimestamp }; }); response.json = async () => jsonData; response.text = async () => JSON.stringify(jsonData); } catch (error) { noTargets = true; console.log('[TornCrimesScammingTimers] No targets, skipping the script init', error); } } return response; }; if (isTampermonkeyEnabled){ unsafeWindow.fetch = customFetch; } else { window.fetch = customFetch; } await addStyle(); const timeDeltas = { "After": 1, "Ago": -1 }; const timerTypes = { "Expiration": 1, "Cooldown": 2 } setInterval(addTimeSpans, 2 * 1_000); function addTimeSpans(){ let targetEmailSpans = document.querySelectorAll('div.crimes-app div.crime-root.scamming-root div[class^=virtualList___] div[class^=virtualItem___] span[class^=email___]'); Object.values(targets).forEach(target => { var match = Object.values(targetEmailSpans).find(targetRow => targetRow.innerText == target.email); if (match != null) { if (showCooldown){ let timeElement = match.parentNode.querySelector('span.silmaril-torn-crimes-scamming-timers-cooldown'); if (timeElement == null) { timeElement = document.createElement('span'); timeElement.className = 'silmaril-torn-crimes-scamming-timers-cooldown'; timeElement.innerText = calculateTimeDelta(target.cooldown, timeDeltas.After, timerTypes.Cooldown, !isMobileView); match.insertAdjacentElement('afterEnd', timeElement); } else { timeElement.innerText = calculateTimeDelta(target.cooldown, timeDeltas.After, timerTypes.Cooldown, !isMobileView); } } if (showExpiration){ let timeElement = match.parentNode.querySelector('span.silmaril-torn-crimes-scamming-timers-expiration'); if (timeElement == null) { timeElement = document.createElement('span'); timeElement.className = 'silmaril-torn-crimes-scamming-timers-expiration'; timeElement.innerText = calculateTimeDelta(target.expire, timeDeltas.After, timerTypes.Expiration, !isMobileView); match.insertAdjacentElement('afterEnd', timeElement); } else { timeElement.innerText = calculateTimeDelta(target.expire, timeDeltas.After, timerTypes.Expiration, !isMobileView); } } } }) } function calculateTimeDelta(timestamp, timeDeltaType, timerType, isDesktopView) { const now = Math.floor(Date.now() / 1000); // Current timestamp in seconds let timeDelta = timestamp - now; // Time remaining in seconds if (timeDeltaType === timeDeltas.After && timeDelta <= 0) { switch (timerType){ case timerTypes.Cooldown: return ""; case timerTypes.Expire: default: return "Expired"; } } if (timeDeltaType === timeDeltas.Ago) { timeDelta = Math.abs(timeDelta); if (timeDelta <= 0) { return "Just now"; } } const days = Math.floor(timeDelta / 86400); // 86400 seconds in a day const hours = Math.floor((timeDelta % 86400) / 3600); // 3600 seconds in an hour const minutes = Math.floor((timeDelta % 3600) / 60); // 60 seconds in a minute const seconds = timeDelta % 60; let prefix = ''; switch (timerType){ case timerTypes.Cooldown: prefix = "Cooldown in "; break; case timerTypes.Expire: default: prefix = "Expires in "; break; } let timeElementsAdded = 0; let timeDeltaText = isDesktopView ? timeDeltaType === timeDeltas.After ? prefix : "Created " : timeDeltaType === timeDeltas.After ? "In " : ""; if (days != 0 && timeElementsAdded < timeElementsToShow) { timeDeltaText += isDesktopView ? `${days} d` : `${days} day${days === 1 ? '' : 's'}`; timeElementsAdded += 1; } if (hours != 0 && timeElementsAdded < timeElementsToShow) { if (days !== 0){ timeDeltaText += ', '; } timeDeltaText += isDesktopView ? `${hours} h` : `${hours} hour${hours === 1 ? '' : 's'}`; timeElementsAdded += 1; } if (minutes != 0 && timeElementsAdded < timeElementsToShow) { if (days !== 0 || hours !== 0){ timeDeltaText += ', '; } timeDeltaText += isDesktopView ? `${minutes} m` : `${minutes} minute${minutes === 1 ? '' : 's'}`; timeElementsAdded += 1; } if (seconds != 0 && timeElementsAdded < timeElementsToShow) { if (days !== 0 || hours !== 0 || minutes !== 0){ timeDeltaText += ', '; } timeDeltaText += isDesktopView ? `${seconds} s` : `${seconds} second${seconds === 1 ? '' : 's'}`; timeElementsAdded += 1; } if (timeDeltaType === timeDeltas.Ago) { timeDeltaText += ' ago'; } return timeDeltaText; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function addStyle() { const styles = ` span.silmaril-torn-crimes-scamming-timers-cooldown { color: yellowgreen; font-size: xx-small; display: ${showCooldown ? 'block' : 'none'}; } span.silmaril-torn-crimes-scamming-timers-expiration { color: gray; font-size: xx-small; display: ${showExpiration ? 'block' : 'none'}; } `; if (isTampermonkeyEnabled){ GM_addStyle(styles); } else { let style = document.createElement("style"); style.type = "text/css"; style.innerHTML = styles; while (document.head == null){ await sleep(50); } document.head.appendChild(style); } } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址