福利吧百家姓暗号转换器

自动识别页面中的福利吧百家姓暗号并转换为磁力链接

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         福利吧百家姓暗号转换器
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  自动识别页面中的福利吧百家姓暗号并转换为磁力链接
// @author       MR.Z
// @match        https://fuliba2023.net/*
// @grant        GM_setClipboard
// ==/UserScript==

// ==UserScript==
// @name        百家姓暗号
// @namespace   http://tampermonkey.net/
// @version     1.0
// @description 识别和转换网页中的"百家姓暗号"
// @license    MIT
// ==/UserScript==

(function() {
    'use strict';

    // 百家姓映射表
    const surnameMap = {
        "赵":"0", "钱":"1", "孙":"2", "李":"3", "周":"4", "吴":"5", "郑":"6", "王":"7", "冯":"8", "陈":"9",
        "褚":"a", "卫":"b", "蒋":"c", "沈":"d", "韩":"e", "杨":"f", "朱":"g", "秦":"h", "尤":"i", "许":"j",
        "何":"k", "吕":"l", "施":"m", "张":"n", "孔":"o", "曹":"p", "严":"q", "华":"r", "金":"s", "魏":"t",
        "陶":"u", "姜":"v", "戚":"w", "谢":"x", "邹":"y", "喻":"z", "福":"A", "水":"B", "窦":"C", "章":"D",
        "云":"E", "苏":"F", "潘":"G", "葛":"H", "奚":"I", "范":"J", "彭":"K", "郎":"L", "鲁":"M", "韦":"N",
        "昌":"O", "马":"P", "苗":"Q", "凤":"R", "花":"S", "方":"T", "俞":"U", "任":"V", "袁":"W", "柳":"X",
        "唐":"Y", "罗":"Z", "薛":".", "伍":"-", "余":"_", "米":"+", "贝":"=", "姚":"/", "孟":"?", "顾":"#",
        "尹":"%", "江":"&", "钟":"*"
    };

    // 获取评论区元素
    function findCommentContainer() {
        // 常见评论区选择器
        const commentSelectors = [
            '#comments',
            '#comment',
            '.comments',
            '.comment',
            '.comment-list',
            '.comment-section',
            '.comment-container',
            '.comment-area',
            '.article-comments',
            '.post-comments'
        ];
        
        for (const selector of commentSelectors) {
            const element = document.querySelector(selector);
            if (element) {
                return element;
            }
        }
        return document.body; // 如果找不到则返回整个body
    }

    // 自动扫描页面文本节点
    function scanTextNodes() {
        console.log('开始扫描页面文本节点...');
        const commentContainer = findCommentContainer();
        const walker = document.createTreeWalker(
            commentContainer,
            NodeFilter.SHOW_TEXT,
            {
                acceptNode: function(node) {
                    // 跳过script、style、textarea等元素
                    if (node.parentNode.nodeName === 'SCRIPT' || 
                        node.parentNode.nodeName === 'STYLE' ||
                        node.parentNode.nodeName === 'TEXTAREA' ||
                        node.parentNode.nodeName === 'INPUT' ||
                        node.parentNode.hasAttribute('data-surname-ignore')) {
                        return NodeFilter.FILTER_REJECT;
                    }
                    // 检查是否已处理过
                    if (node.parentNode.hasAttribute('data-surname-processed')) {
                        return NodeFilter.FILTER_REJECT;
                    }
                    return NodeFilter.FILTER_ACCEPT;
                }
            },
            false
        );

        let node;
        let foundCount = 0;
        while (node = walker.nextNode()) {
            const text = node.nodeValue.trim();
            if (text.length === 0) continue;

            console.log('扫描到文本:', text.substring(0, 50) + (text.length > 50 ? '...' : ''));
            
            if (isSurnameCode(text)) {
                console.log('发现百家姓暗号:', text);
                foundCount++;
                processSurnameCode(node, text);
            }
        }
        console.log(`扫描完成,共发现${foundCount}处百家姓暗号`);
    }

    // 检查是否是百家姓暗号
    function isSurnameCode(text) {
        // 检查是否包含至少3个百家姓字符,提高准确性
        let surnameCount = 0;
        const surnames = Object.keys(surnameMap);
        
        for (const surname of surnames) {
            if (text.includes(surname)) {
                surnameCount++;
                if (surnameCount >= 3) {
                    return true;
                }
            }
        }
        return false;
    }

    // 处理找到的百家姓暗号
    function processSurnameCode(textNode, text) {
        // 双重检查是否已经处理过
        if (textNode.parentNode.hasAttribute('data-surname-processed') ||
            textNode.parentNode.querySelector('button[data-surname-button]')) {
            return;
        }
        
        const span = document.createElement('span');
        span.textContent = text;
        
        const button = document.createElement('button');
        button.textContent = '识别暗号';
        button.setAttribute('data-surname-button', 'true');
        button.style.cssText = `
            margin-left: 8px;
            padding: 4px 12px;
            font-size: 13px;
            font-weight: 500;
            color: #fff;
            background-color: #4a6cf7;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.2s ease;
            box-shadow: 0 1px 2px rgba(0,0,0,0.1);
            min-width: 80px;
            min-height: 32px;
        `;

        // 移动端样式调整
        const mobileStyle = document.createElement('style');
        mobileStyle.textContent = `
            @media (max-width: 768px) {
                button[data-surname-button] {
                    padding: 8px 16px;
                    font-size: 15px;
                    min-width: 90px;
                    min-height: 36px;
                }
                
                div[data-surname-toast] {
                    font-size: 16px;
                    padding: 16px 28px;
                    bottom: 30px;
                    max-width: 80%;
                }
            }
        `;
        document.head.appendChild(mobileStyle);
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = '#3a5ce9';
            button.style.transform = 'translateY(-1px)';
        });
        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = '#4a6cf7';
            button.style.transform = 'none';
        });
        
        // 创建美观的提示函数
        function showToast(message) {
            const toast = document.createElement('div');
            toast.textContent = message;
            toast.setAttribute('data-surname-toast', 'true');
            toast.style.cssText = `
                position: fixed;
                bottom: 20px;
                left: 50%;
                transform: translateX(-50%);
                background-color: #4a6cf7;
                color: white;
                padding: 12px 24px;
                border-radius: 4px;
                font-size: 14px;
                box-shadow: 0 4px 12px rgba(0,0,0,0.15);
                z-index: 9999;
                opacity: 0;
                transition: opacity 0.3s ease;
                white-space: nowrap;
            `;
            document.body.appendChild(toast);
            
            // 显示动画
            setTimeout(() => {
                toast.style.opacity = '1';
            }, 10);
            
            // 3秒后自动消失
            setTimeout(() => {
                toast.style.opacity = '0';
                setTimeout(() => {
                    document.body.removeChild(toast);
                }, 300);
            }, 3000);
        }

        button.addEventListener('click', function() {
            const magnetLink = 'magnet:?xt=urn:btih:' + encodeToCipher(text);
            GM_setClipboard(magnetLink);
            showToast('磁力链接已复制');
        });

        const wrapper = document.createElement('span');
        wrapper.setAttribute('data-surname-processed', 'true');
        wrapper.appendChild(span);
        wrapper.appendChild(button);
        
        textNode.parentNode.replaceChild(wrapper, textNode);
    }

    // 转换函数
    function encodeToCipher(text) {
        const chars = text.split('');
        let result = '';
        for(let i = 0; i < chars.length; i++) {
            const cipher = getValueByKey(surnameMap, chars[i]);
            result += cipher || '';
        }
        return result;
    }

    function getValueByKey(obj, key) {
        for(let k in obj) {
            if(k === key) {
                return obj[k];
            }
        }
        return '';
    }

    // 初始化扫描 - 优化性能版本
    let isScanning = false;
    let scanQueue = [];
    let debounceTimer;

    function throttledScan() {
        if (isScanning) {
            return;
        }

        isScanning = true;
        const startTime = performance.now();
        
        // 每次最多处理50个节点
        const nodesToProcess = scanQueue.splice(0, 50);
        for (const node of nodesToProcess) {
            // 跳过已处理的节点
            if (node.parentNode && node.parentNode.hasAttribute('data-surname-processed')) {
                continue;
            }
            
            const text = node.nodeValue.trim();
            if (text.length > 0 && isSurnameCode(text)) {
                processSurnameCode(node, text);
            }
        }

        isScanning = false;
        console.log(`扫描完成,耗时${(performance.now() - startTime).toFixed(2)}ms`);

        if (scanQueue.length > 0) {
            setTimeout(throttledScan, 100);
        }
    }

    function handleMutations(mutations) {
        // 暂停期间不处理
        if (!observer) return;
        
        mutations.forEach(mutation => {
            if (mutation.addedNodes.length) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const walker = document.createTreeWalker(
                            node,
                            NodeFilter.SHOW_TEXT,
                            {
                                acceptNode: function(n) {
                                    // 跳过已处理节点
                                    if (processedNodes.has(n)) {
                                        return NodeFilter.FILTER_REJECT;
                                    }
                                    if (n.parentNode.nodeName === 'SCRIPT' || 
                                        n.parentNode.nodeName === 'STYLE' ||
                                        n.parentNode.nodeName === 'TEXTAREA' ||
                                        n.parentNode.nodeName === 'INPUT') {
                                        return NodeFilter.FILTER_REJECT;
                                    }
                                    return NodeFilter.FILTER_ACCEPT;
                                }
                            },
                            false
                        );

                        let textNode;
                        while (textNode = walker.nextNode()) {
                            // 检查是否已存在相同内容的按钮
                            if (!textNode.parentNode.querySelector('button[data-surname-button]')) {
                                scanQueue.push(textNode);
                            }
                        }
                    }
                });
            }
        });

        // 防抖处理
        clearTimeout(debounceTimer);
        debounceTimer = setTimeout(throttledScan, 300); // 缩短防抖时间
    }

    // 延迟初始化扫描
    setTimeout(() => {
        try {
            console.log('开始初始扫描...');
            const initialWalker = document.createTreeWalker(
                document.body,
                NodeFilter.SHOW_TEXT,
                {
                    acceptNode: function(node) {
                        if (node.parentNode.nodeName === 'SCRIPT' || 
                            node.parentNode.nodeName === 'STYLE' ||
                            node.parentNode.nodeName === 'TEXTAREA' ||
                            node.parentNode.nodeName === 'INPUT') {
                            return NodeFilter.FILTER_REJECT;
                        }
                        return NodeFilter.FILTER_ACCEPT;
                    }
                },
                false
            );

            let initialNode;
            while (initialNode = initialWalker.nextNode()) {
                scanQueue.push(initialNode);
            }
            
            throttledScan();

            // 监听DOM变化,使用防抖
            const observer = new MutationObserver(handleMutations);
            observer.observe(document.body, {
                childList: true,
                subtree: true,
                attributes: false,
                characterData: false
            });
        } catch (e) {
            console.error('初始化扫描出错:', e);
        }
    }, 2000); // 延长初始延迟
})();