替换 Linux.do 文本和跳转链接

将 https://linux.do/ 上的所有文本替换为“牛逼”,并将所有跳转链接指向特定帖子。

目前为 2025-05-10 提交的版本。查看 最新版本

// ==UserScript==
// @name         替换 Linux.do 文本和跳转链接
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  将 https://linux.do/ 上的所有文本替换为“牛逼”,并将所有跳转链接指向特定帖子。
// @author       你
// @match        https://linux.do/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    'use strict';

    const newLinkUrl = 'https://linux.do/t/topic/640506';
    const newTextContent = '牛逼';

    // 替换节点内的文本内容
    function replaceTextInNode(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            // 只替换包含可见字符的文本节点
            // 避免替换掉 <script> 或 <style> 标签内部的纯文本(虽然下面有标签名检查,但这里多一层保护)
            if (node.parentNode && node.parentNode.tagName &&
                node.parentNode.tagName.toLowerCase() !== 'script' &&
                node.parentNode.tagName.toLowerCase() !== 'style' &&
                node.textContent.trim().length > 0) {
                node.textContent = newTextContent;
            }
        } else if (node.nodeType === Node.ELEMENT_NODE) {
            // 不处理脚本和样式标签,以及它们的子节点
            if (node.tagName.toLowerCase() === 'script' || node.tagName.toLowerCase() === 'style') {
                return;
            }
            // 遍历所有子节点
            for (let i = 0; i < node.childNodes.length; i++) {
                replaceTextInNode(node.childNodes[i]);
            }
        }
    }

    // 替换所有跳转链接 (<a> 标签)
    function replaceNavigationalLinks() {
        const links = document.getElementsByTagName('a');
        for (let i = 0; i < links.length; i++) {
            links[i].href = newLinkUrl;
        }
    }

    // 执行初始替换
    function performReplacements() {
        replaceTextInNode(document.body);
        replaceNavigationalLinks();
    }

    // 初次执行
    performReplacements();

    // 使用 MutationObserver 来处理动态加载的内容
    const observer = new MutationObserver(function(mutationsList, observer) {
        let needsReProcessing = false;
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                // 如果有新的节点被添加到DOM中,我们标记需要重新处理
                needsReProcessing = true;
                break;
            } else if (mutation.type === 'attributes' && mutation.target.tagName === 'A' && mutation.attributeName === 'href') {
                // 如果一个<a>标签的href属性被动态修改了(非我们脚本修改的),也重新处理
                if (mutation.target.href !== newLinkUrl) {
                    needsReProcessing = true;
                    break;
                }
            }
        }

        if (needsReProcessing) {
            // console.log('Dynamic content change detected, re-applying modifications.');
            performReplacements();
        }
    });

    // 配置观察选项:
    // - childList: 监控目标节点(及其子树中节点)的直接子节点的添加或删除。
    // - subtree:   监控目标节点及其所有后代节点的变动。
    // - attributes: 监控链接的href属性变化。
    const observerConfig = {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ['href'] // 只关注href属性的变化,主要用于<a>标签
    };

    // 传入目标节点 (document.body) 和观察选项
    observer.observe(document.body, observerConfig);

    // (可选) 你可以在脚本卸载时停止观察,但这通常由浏览器扩展自动处理
    // window.addEventListener('unload', function() {
    //     observer.disconnect();
    // });

})();