您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows time left until territory is captured given the current or bestcase attackers & defenders count right underneath war timeout ticker.
// ==UserScript== // @name Torn Territory War Time Left // @namespace http://tampermonkey.net/ // @version 0.3 // @description Shows time left until territory is captured given the current or bestcase attackers & defenders count right underneath war timeout ticker. // @author Ramin Quluzade, Silmaril [2665762] // @license MIT License // @match https://www.torn.com/factions.php?step=your* // @match https://www.torn.com/factions.php?step=profile&ID=* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @grant none // ==/UserScript== (function() { 'use strict'; const targetElementSelector = '.f-war-list.war-new'; const observerOptions = { childList: true, subtree: true }; const observerCallback = async function(mutationsList, observer) { for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { const targetElement = document.querySelector(targetElementSelector); if (targetElement) { let territoryWars = mutation.target.querySelectorAll(".f-war-list.war-new div[class^='status-wrap territoryBox']"); if (territoryWars.length > 0) { console.log('Target element found!'); territoryWars.forEach(war => { war.querySelector('.info .faction-progress-wrap').style.paddingTop = '0px'; let timeLeftElement = document.createElement('div'); timeLeftElement.classList.add('time-left', 'timer'); let timeLeftBestElement = document.createElement('div'); timeLeftBestElement.classList.add('time-left-best', 'timer'); war.querySelector('.info .faction-progress-wrap').append(timeLeftElement, timeLeftBestElement); }); territoryWars.forEach(war => { let enemyCountDiv = war.querySelector('.info .member-count.enemy-count .count'); let allyCountDiv = war.querySelector('.info .member-count.your-count .count'); renderTimeLeft(war); // Set up a MutationObserver on the added child element const childObserver = new MutationObserver(function(childMutations) { childMutations.forEach(function(childMutation) { if (childMutation.type === 'characterData') { let territoryWar = childMutation.target.parentNode.parentNode.parentNode.parentNode; renderTimeLeft(territoryWar); } }); }); setInterval(renderTimeLeft, 1000 + Math.floor(Math.random() * 10) + 1, war); childObserver.observe(enemyCountDiv, { characterData: true, subtree: true }); childObserver.observe(allyCountDiv, { characterData: true, subtree: true }); }); observer.disconnect(); } } } } }; const observer = new MutationObserver(observerCallback); observer.observe(document.documentElement, observerOptions); console.log('Observer started. Waiting for target element to appear...'); function renderTimeLeft(war) { let enemyCountDiv = war.querySelector('.info .member-count.enemy-count .count'); let allyCountDiv = war.querySelector('.info .member-count.your-count .count'); let enemyCount = Number(enemyCountDiv.innerText); let allyCount = Number(allyCountDiv.innerText); let isAllyAttack = war.querySelector('.info .member-count.your-count .count i').classList.contains('swords-icon'); let remainder = isAllyAttack ? allyCount - enemyCount : enemyCount - allyCount; let timeLeft = '??:??:??:??'; let timeLeftBest = '??:??:??:??'; let scoreText = war.querySelector('.info .faction-progress-wrap .score').innerText; let score = scoreText.replaceAll(',', '').split('/'); let pointsLeft = Number(score[1]) - Number(score[0]); let maximumSlots = Number(score[1]) / 50000; if (remainder > 0) { let secondsUntilGoal = pointsLeft / remainder; timeLeft = convertSecondsToDHMS(secondsUntilGoal); } timeLeftBest = convertSecondsToDHMS(pointsLeft / maximumSlots); let timeLeftDiv = war.querySelector('.info .faction-progress-wrap .time-left'); let timeLeftBestDiv = war.querySelector('.info .faction-progress-wrap .time-left-best'); const timeLeftCharacters = timeLeft.split(''); const timeLeftBestCharacters = timeLeftBest.split(''); const timeLeftSpanArray = ['CURRENT ']; timeLeftCharacters.forEach(char => { const span = document.createElement('span'); span.textContent = char; timeLeftSpanArray.push(span); }); timeLeftDiv.replaceChildren(...timeLeftSpanArray); const timeLeftBestSpanArray = ['BESTCASE ']; timeLeftBestCharacters.forEach(char => { const span = document.createElement('span'); span.textContent = char; timeLeftBestSpanArray.push(span); }); timeLeftBestDiv.replaceChildren(...timeLeftBestSpanArray); } function convertSecondsToDHMS(seconds) { if (seconds === Infinity){ return '??:??:??:??'; } const oneDay = 86400; // number of seconds in a day const oneHour = 3600; // number of seconds in an hour const oneMinute = 60; // number of seconds in a minute // Calculate the number of days, hours, minutes, and seconds const days = Math.floor(seconds / oneDay); const hours = Math.floor((seconds % oneDay) / oneHour); const minutes = Math.floor((seconds % oneHour) / oneMinute); const remainingSeconds = Math.round(seconds % oneMinute); // Construct a formatted string with the results let output = ''; output += `${days.toString().padStart(2, '0')}:`; output += `${hours.toString().padStart(2, '0')}:`; output += `${minutes.toString().padStart(2, '0')}:`; output += `${remainingSeconds.toString().padStart(2, '0')}`; return output; } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址