Torn 12-Hour Tooltips

Converts the sidebar Energy, Nerve, Happy, and Life floating tooltips into a 12-hour format, synced to your local time. While also adding a floating tooltip over the 24Hour format TCT clock, in your local time.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Torn 12-Hour Tooltips
// @namespace    Torn12HrEnergyFix
// @version      1.9
// @description  Converts the sidebar Energy, Nerve, Happy, and Life floating tooltips into a 12-hour format, synced to your local time. While also adding a floating tooltip over the 24Hour format TCT clock, in your local time.
// @author       Nerros
// @license      MIT
// @match        https://www.torn.com/*
// @match        https://torn.com/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const energyDateTimeRegex = /(\d{1,2}\.\d{1,2}\.\d{4})\s+(\d{1,2}):(\d{2}):(\d{2})/;
    const clockTextRegex = /[A-Za-z]{3}\s+\d{2}:\d{2}:\d{2}\s*-\s*\d{2}\/\d{2}\/\d{2}/;

    function getLocalTimeString() {
        const now = new Date();
        const localTimeString = now.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit', second: '2-digit', hour12: true });
        const localDateString = now.toLocaleDateString([], { weekday: 'short', month: '2-digit', day: '2-digit', year: '2-digit' });
        return `Local Time: ${localDateString} ${localTimeString}`;
    }

    function convertTo12Hour(text) {
        return text.replace(energyDateTimeRegex, (match, dateStr, h, minutes, seconds) => {
            let hours = parseInt(h, 10);
            const ampm = hours >= 12 ? 'PM' : 'AM';
            hours = hours % 12 || 12;
            const formattedHours = String(hours).padStart(2, '0');
            return `${dateStr} ${formattedHours}:${minutes}:${seconds} ${ampm}`;
        });
    }

    // Create a single custom floating tooltip element
    let customTooltip = null;
    function getCustomTooltip() {
        if (!customTooltip) {
            customTooltip = document.createElement('div');
            customTooltip.id = 'torn-local-clock-tooltip';
            Object.assign(customTooltip.style, {
                position: 'fixed',
                backgroundColor: 'rgba(30, 30, 30, 0.95)',
                color: '#ffffff',
                padding: '6px 10px',
                borderRadius: '4px',
                fontSize: '12px',
                fontFamily: 'Arial, sans-serif',
                zIndex: '999999',
                pointerEvents: 'none',
                boxShadow: '0 2px 8px rgba(0,0,0,0.6)',
                display: 'none',
                border: '1px solid #444',
                whiteSpace: 'nowrap'
            });
            document.body.appendChild(customTooltip);
        }
        return customTooltip;
    }

    // 1. Process Energy Tooltips (12-hour conversion)
    function processEnergyTooltips() {
        const tooltips = document.querySelectorAll(
            '[data-tippy-root], .tippy-box, .tippy-content, .ui-tooltip, [role="tooltip"]'
        );

        tooltips.forEach((tooltip) => {
            if (energyDateTimeRegex.test(tooltip.innerHTML) && !tooltip.dataset.energy12hrDone) {
                if (!tooltip.id.includes('torn-local-clock-tooltip')) {
                    tooltip.dataset.energy12hrDone = 'true';
                    tooltip.innerHTML = convertTo12Hour(tooltip.innerHTML);
                }
            }
        });
    }

    // 2. Attach hover listeners for the top-right clock
    let activeClockInterval = null;

    function processClockHover() {
        const candidates = document.querySelectorAll('header *, #user-bar *, [class*="clock" i], [id*="clock" i]');

        for (const el of candidates) {
            if (clockTextRegex.test(el.textContent)) {
                const clockContainer = el.closest('a, button, [class*="clock" i], [id*="clock" i]') || el;

                if (!clockContainer.dataset.localClockSetup) {
                    clockContainer.dataset.localClockSetup = 'true';

                    // Remove native title attribute to suppress secondary browser popups
                    clockContainer.removeAttribute('title');

                    const tooltip = getCustomTooltip();

                    clockContainer.addEventListener('mouseenter', () => {
                        clockContainer.removeAttribute('title');
                        tooltip.textContent = getLocalTimeString();
                        tooltip.style.display = 'block';

                        const rect = clockContainer.getBoundingClientRect();
                        tooltip.style.top = `${rect.bottom + 6}px`;
                        tooltip.style.left = `${Math.max(10, rect.left + (rect.width / 2) - 80)}px`;

                        if (!activeClockInterval) {
                            activeClockInterval = setInterval(() => {
                                if (tooltip.style.display === 'block') {
                                    tooltip.textContent = getLocalTimeString();
                                }
                            }, 1000);
                        }
                    });

                    clockContainer.addEventListener('mouseleave', () => {
                        tooltip.style.display = 'none';
                        if (activeClockInterval) {
                            clearInterval(activeClockInterval);
                            activeClockInterval = null;
                        }
                    });
                }
                break;
            }
        }
    }

    const observer = new MutationObserver(() => {
        processEnergyTooltips();
        processClockHover();
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    processEnergyTooltips();
    processClockHover();
})();