您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows your local time and a table to convert Torn time to your local time
// ==UserScript== // @name Torn Time Table (optimized, live local time) // @namespace https://greasyfork.org // @version 0.5.3 // @description Shows your local time and a table to convert Torn time to your local time // @license MIT // @author MrChurch [3654415] // @match https://www.torn.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=torn.com // @run-at document-start // @grant none // ==/UserScript== (function () { 'use strict'; const SHOW_ON_LOAD = true; // true = expanded by default function waitFor(selector, root = document) { return new Promise((resolve) => { const found = root.querySelector(selector); if (found) return resolve(found); const obs = new MutationObserver(() => { const el = root.querySelector(selector); if (el) { resolve(el); obs.disconnect(); } }); obs.observe(document.documentElement, { subtree: true, childList: true }); }); } const z2 = (n) => String(n).padStart(2, '0'); function ensureStyles() { if (document.getElementById('myTornTimeTableStyles')) return; const style = document.createElement('style'); style.id = 'myTornTimeTableStyles'; style.textContent = ` #myTornTimeTableWrap { margin-top: 6px; } #myTornTimeTable { text-align:center; width:100%; border-collapse: collapse; } #myTornTimeTable th, #myTornTimeTable td { padding: 4px 0; color: #e3e3e3; } #myTornTimeTable thead td { border-top:1px solid #000; border-bottom:1px solid #000; } .tt-toggle { cursor:pointer; user-select:none; display:inline-block; margin-bottom:6px; color:#e3e3e3; } .tt-muted { opacity:0.9; color:#e3e3e3; } .tt-hidden { display:none; } `; document.head.appendChild(style); } function parseHHMMSS(text) { const m = text && text.trim().match(/(\d{1,2}):(\d{2}):(\d{2})/); if (!m) return null; const h = +m[1], mi = +m[2], s = +m[3]; if ([h, mi, s].some(Number.isNaN)) return null; return { h, mi, s }; } function minutesToHMS(totalMinutes, seconds = 0) { // Accepts possibly-negative minutes, wraps to 0..23 for hours const tMin = Math.floor(totalMinutes); const h = ((Math.floor(tMin / 60) % 24) + 24) % 24; const m = ((tMin % 60) + 60) % 60; const s = ((seconds % 60) + 60) % 60; return { h, m, s }; } function buildWrap(tctH, tctM) { const now = new Date(); const offsetMin = now.getTimezoneOffset(); // minutes to add to LOCAL to get UTC const tctTotalMin = tctH * 60 + tctM; const localTotalMin = tctTotalMin - offsetMin; const { h: localH, m: localM } = minutesToHMS(localTotalMin); const wrap = document.createElement('div'); wrap.id = 'myTornTimeTableWrap'; wrap.innerHTML = ` <a class="tt-toggle">Toggle Time Table</a> <table id="myTornTimeTable" ${SHOW_ON_LOAD ? '' : 'class="tt-hidden"'}> <thead> <tr> <td colspan="3" class="tt-muted"> Local: <span id="tt-local-time">${z2(localH)}:${z2(localM)}:00</span> </td> </tr> <tr><th width="33%">Add</th><th width="34%">TCT</th><th width="33%">Local</th></tr> </thead> <tbody></tbody> </table> `; const tbody = wrap.querySelector('tbody'); for (let add = 1; add <= 23; add++) { const tctHour = (tctH + add) % 24; const locMin = localTotalMin + add * 60; const { h: locHour } = minutesToHMS(locMin); const tr = document.createElement('tr'); tr.innerHTML = `<td>${add}</td><td>${z2(tctHour)}</td><td>${z2(locHour)}</td>`; tbody.appendChild(tr); } // Return a function to live-update the header given a TCT string "HH:MM:SS" const localHeader = () => wrap.querySelector('#tt-local-time'); const updater = (tctText) => { const p = parseHHMMSS(tctText); if (!p) return; // Recompute from current timezone offset each tick (DST-safe) const offMin = new Date().getTimezoneOffset(); const tctMinNow = p.h * 60 + p.mi; const localMinNow = tctMinNow - offMin; const { h, m } = minutesToHMS(localMinNow, p.s); const el = localHeader(); if (el) el.textContent = `${z2(h)}:${z2(m)}:${z2(p.s)}`; }; return { wrap, updater }; } async function main() { ensureStyles(); const timeSpan = await waitFor('.server-date-time'); if (!timeSpan || document.getElementById('myTornTimeTableWrap')) return; const parsed = parseHHMMSS(timeSpan.textContent || ''); if (!parsed) return; const { wrap, updater } = buildWrap(parsed.h, parsed.mi); timeSpan.insertAdjacentElement('afterend', wrap); // Toggle const toggle = wrap.querySelector('.tt-toggle'); const table = wrap.querySelector('#myTornTimeTable'); toggle.addEventListener('click', () => table.classList.toggle('tt-hidden')); // Live-sync local time with Torn's clock by observing text changes const mo = new MutationObserver(() => updater(timeSpan.textContent || '')); mo.observe(timeSpan, { characterData: true, subtree: true, childList: true }); // Initial paint with seconds updater(timeSpan.textContent || ''); } main(); })();