Torn - Bigger active chain timer

Make the chain timer larger only while it is actively counting down

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Torn - Bigger active chain timer
// @namespace    LordTiny.torn.bigger-active-chain-timer
// @version      1.1.3
// @description  Make the chain timer larger only while it is actively counting down
// @author       LordTiny [4036444]
// @match        https://www.torn.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=torn.com
// @license      MIT
// @grant        none
// ==/UserScript==

(() => {
  'use strict';

  const STYLE_ID = 'bigger-active-chain-timer-style';
  const BIG_CLASS = 'chain-timer-big';
  const STATS_BIG_CLASS = 'chain-stats-big';
  const WARNING_CLASS = 'chain-timer-warning';
  const FLASH_CLASS = 'chain-timer-flash';

  function addStyle() {
    if (document.getElementById(STYLE_ID)) return;

    const style = document.createElement('style');
    style.id = STYLE_ID;
    style.textContent = `
      .${BIG_CLASS} {
        display: block !important;
        flex-basis: 100% !important;
        width: 100% !important;
        font-size: 60px !important;
        line-height: 1 !important;
        height: 62px !important;
        margin-top: 10px !important;
        margin-left: 0 !important;
        position: relative !important;
        left: 0 !important;
      }

      .${STATS_BIG_CLASS} {
        flex-wrap: wrap !important;
      }

      .${WARNING_CLASS} {
        color: yellow !important;
        text-shadow: -3px -3px 5px rgba(255, 255, 0, .15), 3px 3px 5px rgba(255, 255, 0, .15) !important;
      }

      @keyframes subtleUrgentPulse {
        0% {
          transform: scale(1);
        }

        50% {
          transform: scale(1.08);
        }

        100% {
          transform: scale(1);
        }
      }

      .${FLASH_CLASS} {
        display: inline-block !important;
        transform-origin: center center !important;
        animation: subtleUrgentPulse 0.75s infinite !important;
      }
    `;
    document.head.appendChild(style);
  }

  function getSecondsRemaining(text) {
    const parts = text.trim().split(':');

    if (parts.length !== 2) {
      return null;
    }

    const minutes = parseInt(parts[0], 10);
    const seconds = parseInt(parts[1], 10);

    if (Number.isNaN(minutes) || Number.isNaN(seconds)) {
      return null;
    }

    return (minutes * 60) + seconds;
  }

  function isActiveTimerText(text) {
    const trimmed = text.trim();

    // Treat empty, zero, and common zero-time formats as inactive.
    return trimmed !== ''
      && trimmed !== '0'
      && trimmed !== '00'
      && trimmed !== '0:00'
      && trimmed !== '00:00'
      && trimmed !== '00:00:00';
  }

  function getTimerElement() {
    // Torn uses generated class names, so match on the stable class prefix instead of the whole class.
    return document.querySelector('[class*="bar-timeleft"]');
  }

  function getSpeedElement() {
    // Torn uses generated class names, so match on the stable class prefix instead of the whole class.
    return document.querySelector('[class*="speed___"]');
  }

  function updateTimerSize() {
    const timer = getTimerElement();
    if (!timer) return;

    const speed = getSpeedElement();
    const stats = timer.closest('[class*="bar-stats"]');
    const isActive = isActiveTimerText(timer.textContent);
    const secondsLeft = getSecondsRemaining(timer.textContent);
    const shouldWarn = isActive && secondsLeft !== null && secondsLeft <= 60 && secondsLeft > 30;
    const shouldFlash = isActive && secondsLeft !== null && secondsLeft <= 15;

    timer.classList.toggle(BIG_CLASS, isActive);
    timer.classList.toggle(WARNING_CLASS, shouldWarn);
    timer.classList.toggle(FLASH_CLASS, shouldFlash);

    if (stats) {
      stats.classList.toggle(STATS_BIG_CLASS, isActive);
    }

    if (speed) {
      speed.style.top = isActive ? 'auto' : '';
    }
  }

  function start() {
    addStyle();
    updateTimerSize();

    const observer = new MutationObserver(updateTimerSize);

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

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', start);
  } else {
    start();
  }
})();