Lolz Offtopic Renamer

Меняет название оффтопика на lolz.live

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Lolz Offtopic Renamer
// @namespace    http://tampermonkey.net/
// @version      3.5
// @description  Меняет название оффтопика на lolz.live
// @author       eretly (optimized version)
// @match        *://lolz.live/*
// @grant        none
// @license      MIT
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // Конфиг
    const NEW_OFFTOPIC_NAME = "Анимешный Оффтопик"; // Вписываем название оффтопика

    let originalOfftopicName = "";
    const processedElements = new WeakSet();

    const OFFTOPIC_LINK_SELECTORS = [
        'a[href="https://lolz.live/forums/8/"]',
        'a[href="/forums/8/"]',
        'a[href="forums/8/"]',
        '.p-nav-list a[href="/forums/8/"]',
        'a.u-concealed[href="/forums/8/"]',
        '.p-breadcrumbs a[href="/forums/8/"]'
    ];

    const TEXT_ELEMENT_SELECTORS = [
        'span[itemprop="name"]',
        'span.muted',
        'span.innerText',
        '.search-choice span',
        '.p-title-value',
        '.p-title h1',
        '.p-title span',
        '.p-description .u-muted',
        '.p-navgroup-linkText',
        '.node-title'
    ];

    function escapeRegExp(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function replaceOfftopicName(text) {
        if (!originalOfftopicName || typeof text !== 'string' || !text.includes(originalOfftopicName)) {
            return text;
        }
        return text.replace(new RegExp(escapeRegExp(originalOfftopicName), 'g'), NEW_OFFTOPIC_NAME);
    }

    async function fetchOfftopicName() {
        try {
            const response = await fetch("https://lolz.live/forums/8/");
            const html = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            const h1Element = doc.querySelector('h1[title]');
            if (h1Element && h1Element.textContent.trim()) {
                return h1Element.textContent.trim();
            }

            const titleElement = doc.querySelector('title');
            if (titleElement) {
                const match = titleElement.textContent.match(/(.*?)\s*\|\s*lolz\.live/i);
                if (match && match[1]) {
                    return match[1].trim();
                }
            }

            const breadcrumb = doc.querySelector('.p-breadcrumbs-list li:last-child span');
            if (breadcrumb) {
                return breadcrumb.textContent.trim();
            }

            return "";
        } catch (error) {
            console.log("[Lolz Offtopic Renamer] Ошибка при запросе страницы оффтопика:", error);
            return "";
        }
    }

    function getOfftopicNameFromPage() {
        if (window.location.pathname === "/forums/8/" || window.location.pathname === "/forums/8") {
            const h1Element = document.querySelector('h1[title]');
            if (h1Element && h1Element.textContent.trim()) {
                return h1Element.textContent.trim();
            }
        }

        for (const selector of OFFTOPIC_LINK_SELECTORS) {
            const element = document.querySelector(selector);
            if (element && element.textContent.trim()) {
                return element.textContent.trim();
            }
        }

        return "";
    }

    function processTextNodes(node) {
        if (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE' || processedElements.has(node)) {
            return;
        }

        if (node.nodeType === Node.TEXT_NODE) {
            if (node.nodeValue.includes(originalOfftopicName)) {
                node.nodeValue = replaceOfftopicName(node.nodeValue);
                processedElements.add(node);
            }
        } else {
            for (let i = 0; i < node.childNodes.length; i++) {
                processTextNodes(node.childNodes[i]);
            }
        }
    }

    function updateDOMElements() {
        if (!originalOfftopicName || originalOfftopicName === NEW_OFFTOPIC_NAME) {
            return;
        }

        processTextNodes(document.body);

        OFFTOPIC_LINK_SELECTORS.forEach(selector => {
            document.querySelectorAll(selector).forEach(link => {
                if (!processedElements.has(link) && link.textContent.trim() === originalOfftopicName) {
                    link.textContent = NEW_OFFTOPIC_NAME;
                    processedElements.add(link);
                }
            });
        });

        TEXT_ELEMENT_SELECTORS.forEach(selector => {
            document.querySelectorAll(selector).forEach(element => {
                if (!processedElements.has(element) && element.textContent.trim() === originalOfftopicName) {
                    element.textContent = NEW_OFFTOPIC_NAME;
                    processedElements.add(element);
                }
            });
        });

        if (window.location.pathname === "/forums/8/" || window.location.pathname === "/forums/8") {
            document.querySelectorAll('h1').forEach(h1 => {
                if (!processedElements.has(h1) && h1.textContent.trim() === originalOfftopicName) {
                    h1.textContent = NEW_OFFTOPIC_NAME;
                    h1.setAttribute("title", NEW_OFFTOPIC_NAME);
                    processedElements.add(h1);
                }
            });

            if (document.title.includes(originalOfftopicName)) {
                document.title = replaceOfftopicName(document.title);
            }
        }

        document.querySelectorAll(`[data-cachedtitle*="${originalOfftopicName}"], [title*="${originalOfftopicName}"]`).forEach(el => {
            if (!processedElements.has(el)) {
                if (el.dataset.cachedtitle && el.dataset.cachedtitle.includes(originalOfftopicName)) {
                    el.dataset.cachedtitle = replaceOfftopicName(el.dataset.cachedtitle);
                }
                if (el.title && el.title.includes(originalOfftopicName)) {
                    el.title = replaceOfftopicName(el.title);
                }
                processedElements.add(el);
            }
        });
    }

    function patchDOMMethods() {
        const originalSetAttr = Element.prototype.setAttribute;
        Element.prototype.setAttribute = function(name, value) {
            if ((name === 'data-cachedtitle' || name === 'title') &&
                typeof value === 'string' &&
                originalOfftopicName) {
                value = replaceOfftopicName(value);
            }
            return originalSetAttr.call(this, name, value);
        };

        const originalGetAttr = Element.prototype.getAttribute;
        Element.prototype.getAttribute = function(name) {
            let value = originalGetAttr.call(this, name);
            if ((name === 'data-cachedtitle' || name === 'title') &&
                typeof value === 'string' &&
                originalOfftopicName) {
                value = replaceOfftopicName(value);
            }
            return value;
        };

        const originalTextContent = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent');
        if (originalTextContent && originalTextContent.set) {
            Object.defineProperty(Node.prototype, 'textContent', {
                set(value) {
                    if (typeof value === 'string' && originalOfftopicName) {
                        value = replaceOfftopicName(value);
                    }
                    return originalTextContent.set.call(this, value);
                },
                get: originalTextContent.get
            });
        }
    }

    function observeDOMChanges() {
        const observer = new MutationObserver(() => {
            updateDOMElements();
        });

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

    async function initialize() {
        originalOfftopicName = getOfftopicNameFromPage();

        if (!originalOfftopicName) {
            originalOfftopicName = await fetchOfftopicName();
        }

        if (originalOfftopicName && originalOfftopicName !== NEW_OFFTOPIC_NAME) {
            patchDOMMethods();
            updateDOMElements();
            observeDOMChanges();
        }
    }

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