Lolz.live Dynamic Time

Показывает секунды первую минуту. Обновляет значение каждую секунду. До 1 часа считает время и также каждую минуту обновляет значение без обновления страницы. Воркает на устройстве (нагрузка).

当前为 2025-08-02 提交的版本,查看 最新版本

// ==UserScript==
// @name         Lolz.live Dynamic Time
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Показывает секунды первую минуту. Обновляет значение каждую секунду. До 1 часа считает время и также каждую минуту обновляет значение без обновления страницы. Воркает на устройстве (нагрузка).
// @author       eretly
// @match        https://lolz.live/*
// @match        https://lzt.market/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const activeElements = new WeakMap();
    let updateTimer = null;

    function pluralize(number, one, few, many) {
        number = Math.abs(number);
        if (number % 100 >= 11 && number % 100 <= 19) return many;
        switch (number % 10) {
            case 1: return one;
            case 2:
            case 3:
            case 4: return few;
            default: return many;
        }
    }

    function getSafeDiff(timestamp) {
        return Math.max(0, Math.floor(Date.now() / 1000) - timestamp);
    }

    function formatRelativeTime(diff) {
        diff = Math.max(0, diff);

        if (diff < 60) {
            return `${diff} ${pluralize(diff, 'секунду', 'секунды', 'секунд')} назад`;
        } else if (diff < 120) {
            return 'Минуту назад';
        } else if (diff < 3600) {
            const mins = Math.floor(diff / 60);
            return `${mins} мин. назад`;
        }
        return null;
    }

    function formatAbsoluteTime(el) {
        const timeStr = el.getAttribute('data-timestring');
        if (!timeStr) return null;
        return `Сегодня, в ${timeStr}`;
    }

    function updateTimes() {
        const now = Math.floor(Date.now() / 1000);
        let needsUpdate = false;

        document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
            const currentText = el.textContent;
            if (/сегодня|вчера|\d{1,2} \w+ \d{4}/i.test(currentText)) return;

            const timestamp = parseInt(el.getAttribute('data-time'));
            const diff = getSafeDiff(timestamp);

            if (diff < 3600) {
                if (!el.hasAttribute('data-original-text')) {
                    el.setAttribute('data-original-text', currentText);
                }

                const newText = formatRelativeTime(diff);
                if (newText && el.textContent !== newText) {
                    el.textContent = newText;
                }

                activeElements.set(el, true);
                needsUpdate = true;
            } else if (activeElements.has(el)) {
                const absText = formatAbsoluteTime(el);
                if (absText) el.textContent = absText;
                activeElements.delete(el);
            }
        });

        if (needsUpdate && !updateTimer) {
            updateTimer = setTimeout(() => {
                updateTimer = null;
                updateTimes();
            }, 1000);
        } else if (!needsUpdate && updateTimer) {
            clearTimeout(updateTimer);
            updateTimer = null;
        }
    }

    const observer = new MutationObserver(mutations => {
        let shouldUpdate = false;

        mutations.forEach(mutation => {
            mutation.addedNodes.forEach(node => {
                if (node.nodeType === 1) {
                    const timeNodes = node.matches('abbr.DateTime[data-time]')
                        ? [node]
                        : Array.from(node.querySelectorAll('abbr.DateTime[data-time]'));

                    timeNodes.forEach(el => {
                        const currentText = el.textContent;
                        if (/сегодня|вчера|\d{1,2} \w+ \d{4}/i.test(currentText)) return;

                        const timestamp = parseInt(el.getAttribute('data-time'));
                        const diff = getSafeDiff(timestamp);

                        if (diff < 3600) {
                            el.setAttribute('data-original-text', el.textContent);
                            const newText = formatRelativeTime(diff);
                            if (newText) el.textContent = newText;
                            activeElements.set(el, true);
                            shouldUpdate = true;
                        } else {
                            const absText = formatAbsoluteTime(el);
                            if (absText) el.textContent = absText;
                        }
                    });
                }
            });
        });

        if (shouldUpdate) {
            setTimeout(updateTimes, 50);
        }
    });

    function init() {
        document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
            const currentText = el.textContent;
            if (/сегодня|вчера|\d{1,2} \w+ \d{4}/i.test(currentText)) return;

            const timestamp = parseInt(el.getAttribute('data-time'));
            const diff = getSafeDiff(timestamp);

            if (diff < 3600) {
                el.setAttribute('data-original-text', el.textContent);
                const newText = formatRelativeTime(diff);
                if (newText) el.textContent = newText;
                activeElements.set(el, true);
            } else {
                const absText = formatAbsoluteTime(el);
                if (absText) el.textContent = absText;
            }
        });

        updateTimes();

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

        ['click', 'scroll', 'mousemove'].forEach(event => {
            document.addEventListener(event, () => {
                setTimeout(updateTimes, 100);
            }, { passive: true });
        });
    }

    if (document.readyState === 'complete') {
        init();
    } else {
        window.addEventListener('load', init);
    }

    window.addEventListener('unload', () => {
        observer.disconnect();
        if (updateTimer) clearTimeout(updateTimer);
    });
})();