Lolz.live Dynamic Time

Добавляет секунды + обновление времени в реальном времени (нагрузка на усройстве).

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Lolz.live Dynamic Time
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Добавляет секунды + обновление времени в реальном времени (нагрузка на усройстве).
// @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 addSecondsToDateTime() {
        document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
            const timestamp = parseInt(el.getAttribute('data-time'));
            if (!timestamp) return;

            const diff = getSafeDiff(timestamp);
            const sixDays = 7 * 24 * 60 * 60; // 7 дней в секундах

            if (diff >= 3600 && diff <= sixDays) {
                const timeStr = el.getAttribute('data-timestring');
                if (!timeStr) return;

                if (timeStr.match(/^\d{1,2}:\d{2}:\d{2}$/)) return;

                const date = new Date(timestamp * 1000);
                const hours = date.getHours();
                const minutes = date.getMinutes().toString().padStart(2, '0');
                const seconds = date.getSeconds().toString().padStart(2, '0');

                const timeWithSeconds = `${hours}:${minutes}:${seconds}`;

                const currentText = el.textContent;
                const newText = currentText.replace(/\d{1,2}:\d{2}$/, timeWithSeconds);
                el.textContent = newText;

                const title = el.getAttribute('title');
                if (title) {
                    const newTitle = title.replace(/\d{1,2}:\d{2}$/, timeWithSeconds);
                    el.setAttribute('title', newTitle);
                }
                el.setAttribute('data-timestring', timeWithSeconds);
            }
        });
    }

    function updateTimes() {
        let needsUpdate = false;

        document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
            if (!activeElements.has(el)) return;

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

            if (diff < 3600) {
                const newText = formatRelativeTime(diff);
                if (newText && el.textContent !== newText) {
                    el.textContent = newText;
                }
                needsUpdate = true;
            } else if (diff >= 3600) {
                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;
        }
    }

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

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

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

        return false;
    }

    function addSecondsToConversations() {
        if (window.location.pathname.includes('/conversations/')) {
            document.querySelectorAll('span.messageDate[data-absolutetime]').forEach(el => {
                const timestamp = parseInt(el.getAttribute('data-absolutetime'));
                if (!timestamp) return;

                if (el.textContent.match(/^\d{2}:\d{2}:\d{2}$/)) return;

                const date = new Date(timestamp * 1000);
                const hours = date.getHours().toString().padStart(2, '0');
                const minutes = date.getMinutes().toString().padStart(2, '0');
                const seconds = date.getSeconds().toString().padStart(2, '0');

                el.textContent = `${hours}:${minutes}:${seconds}`;
            });
        }

        document.querySelectorAll('div.conversationItem--messageDate[data-absolutetime]').forEach(el => {
            const timestamp = parseInt(el.getAttribute('data-absolutetime'));
            if (!timestamp) return;

            const messageDate = new Date(timestamp * 1000);
            const today = new Date();

            if (messageDate.toDateString() === today.toDateString()) {
                const currentText = el.textContent.trim();
                if (currentText.match(/^\d{2}:\d{2}:\d{2}$/)) return;

                const hours = messageDate.getHours().toString().padStart(2, '0');
                const minutes = messageDate.getMinutes().toString().padStart(2, '0');
                const seconds = messageDate.getSeconds().toString().padStart(2, '0');

                el.textContent = ` ${hours}:${minutes}:${seconds} `;
            }
        });
    }

    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 => {
                        if (processNewElement(el)) {
                            shouldUpdate = true;
                        }
                    });

                    setTimeout(addSecondsToConversations, 10);

                    setTimeout(addSecondsToDateTime, 10);
                }
            });
        });

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

    function init() {
        let needsUpdate = false;

        document.querySelectorAll('abbr.DateTime[data-time]').forEach(el => {
            if (processNewElement(el)) {
                needsUpdate = true;
            }
        });

        if (needsUpdate) {
            updateTimes();
        }

        addSecondsToConversations();

        addSecondsToDateTime();

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

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

                setTimeout(addSecondsToConversations, 10);

                setTimeout(addSecondsToDateTime, 10);
            }, { passive: true });
        });
    }

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

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