Greasy Fork

来自缓存

Greasy Fork is available in English.

south-plus域名自动替换 (v2.0)

自动替换域名并支持自定义替换规则

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         south-plus域名自动替换 (v2.0)
// @namespace    https://github.com/qgdyyg/automatically-replace-southplus-domain
// @version      2.0
// @description  自动替换域名并支持自定义替换规则
// @author       qgdyyg
// @match        *://*/*
// @grant        GM_openInTab
// @grant        GM_registerMenuCommand
// @grant        GM_webRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    // 初始化存储的替换规则
    const DEFAULT_RULES = [
        { source: 'south-plus.net', target: 'bbs.imoutolove.me' },
        { source: 'north-plus.net', target: 'bbs.imoutolove.me' },
        { source: 'white-plus.net', target: 'bbs.imoutolove.me' },
        { source: 'blue-plus.net', target: 'bbs.imoutolove.me' },
        { source: 'snow-plus.net', target: 'bbs.imoutolove.me' },
        { source: 'spring-plus.net', target: 'bbs.imoutolove.me' }
    ];

    // 从存储加载用户规则,如果没有则使用默认规则
    let REPLACEMENT_RULES = GM_getValue('replacementRules', DEFAULT_RULES);

    // 配置区域
    const CONFIG = {
        debug: false,
        autoRefresh: true,
        refreshDelay: 1500
    };

    // 保存规则到存储
    const saveRules = () => {
        GM_setValue('replacementRules', REPLACEMENT_RULES);
        if (CONFIG.debug) {
            console.log('[规则保存] 替换规则已保存', REPLACEMENT_RULES);
        }
    };

    // 重置为默认规则
    const resetToDefault = () => {
        REPLACEMENT_RULES = [...DEFAULT_RULES];
        saveRules();
        alert('已重置为默认替换规则');
    };

    // 添加新规则
    const addRule = () => {
        const source = prompt('请输入要替换的源域名 (例如: example.com)', '');
        if (!source) return;
        
        const target = prompt('请输入替换后的目标域名 (例如: newdomain.com)', 'bbs.imoutolove.me');
        if (!target) return;
        
        // 确保域名格式正确
        const cleanSource = source.replace(/^https?:\/\//, '').replace(/\/.*$/, '').trim();
        const cleanTarget = target.replace(/^https?:\/\//, '').replace(/\/.*$/, '').trim();
        
        if (!cleanSource || !cleanTarget) {
            alert('域名格式不正确,请重新输入');
            return;
        }
        
        // 检查是否已存在相同源域名的规则
        const exists = REPLACEMENT_RULES.some(rule => rule.source === cleanSource);
        if (exists) {
            if (!confirm(`已存在源域名为 "${cleanSource}" 的规则,是否覆盖?`)) {
                return;
            }
            REPLACEMENT_RULES = REPLACEMENT_RULES.filter(rule => rule.source !== cleanSource);
        }
        
        REPLACEMENT_RULES.push({ source: cleanSource, target: cleanTarget });
        saveRules();
        alert(`已添加新规则:\n${cleanSource} → ${cleanTarget}`);
    };

    // 编辑现有规则
    const editRule = () => {
        if (REPLACEMENT_RULES.length === 0) {
            alert('当前没有可用的替换规则');
            return;
        }
        
        const ruleList = REPLACEMENT_RULES.map((rule, i) => 
            `${i + 1}. ${rule.source} → ${rule.target}`
        ).join('\n');
        
        const index = prompt(
            '请输入要编辑的规则编号:\n\n' + ruleList, 
            '1'
        );
        
        if (!index) return;
        
        const ruleIndex = parseInt(index) - 1;
        if (isNaN(ruleIndex) || ruleIndex < 0 || ruleIndex >= REPLACEMENT_RULES.length) {
            alert('无效的规则编号');
            return;
        }
        
        const currentRule = REPLACEMENT_RULES[ruleIndex];
        const newSource = prompt('修改源域名:', currentRule.source);
        if (newSource === null) return; // 用户点击了取消
        
        const newTarget = prompt('修改目标域名:', currentRule.target);
        if (newTarget === null) return; // 用户点击了取消
        
        // 确保域名格式正确
        const cleanSource = newSource.replace(/^https?:\/\//, '').replace(/\/.*$/, '').trim();
        const cleanTarget = newTarget.replace(/^https?:\/\//, '').replace(/\/.*$/, '').trim();
        
        if (!cleanSource || !cleanTarget) {
            alert('域名格式不正确,请重新输入');
            return;
        }
        
        // 检查是否已存在相同源域名的规则(除了当前规则)
        const exists = REPLACEMENT_RULES.some((rule, i) => 
            i !== ruleIndex && rule.source === cleanSource
        );
        
        if (exists) {
            if (!confirm(`已存在源域名为 "${cleanSource}" 的规则,是否覆盖?`)) {
                return;
            }
            REPLACEMENT_RULES = REPLACEMENT_RULES.filter((_, i) => i !== ruleIndex);
            REPLACEMENT_RULES.push({ source: cleanSource, target: cleanTarget });
        } else {
            REPLACEMENT_RULES[ruleIndex] = { 
                source: cleanSource, 
                target: cleanTarget 
            };
        }
        
        saveRules();
        alert(`规则已更新:\n${cleanSource} → ${cleanTarget}`);
    };

    // 删除规则
    const deleteRule = () => {
        if (REPLACEMENT_RULES.length === 0) {
            alert('当前没有可用的替换规则');
            return;
        }
        
        const ruleList = REPLACEMENT_RULES.map((rule, i) => 
            `${i + 1}. ${rule.source} → ${rule.target}`
        ).join('\n');
        
        const index = prompt(
            '请输入要删除的规则编号:\n\n' + ruleList, 
            '1'
        );
        
        if (!index) return;
        
        const ruleIndex = parseInt(index) - 1;
        if (isNaN(ruleIndex) || ruleIndex < 0 || ruleIndex >= REPLACEMENT_RULES.length) {
            alert('无效的规则编号');
            return;
        }
        
        const rule = REPLACEMENT_RULES[ruleIndex];
        if (confirm(`确定要删除规则吗?\n${rule.source} → ${rule.target}`)) {
            REPLACEMENT_RULES = REPLACEMENT_RULES.filter((_, i) => i !== ruleIndex);
            saveRules();
            alert('规则已删除');
        }
    };

    // 显示当前规则
    const showCurrentRules = () => {
        if (REPLACEMENT_RULES.length === 0) {
            alert('当前没有配置替换规则');
            return;
        }
        
        const ruleList = REPLACEMENT_RULES.map(rule => 
            `• ${rule.source} → ${rule.target}`
        ).join('\n');
        
        alert(
            `当前替换规则 (${REPLACEMENT_RULES.length}条):\n\n` +
            ruleList + 
            '\n\n点击 plus.net 域名链接将自动替换为目标域名'
        );
    };

    // 注册右键菜单
    GM_registerMenuCommand('🛠️ 配置自动替换规则', () => {
        const options = [
            '1. 查看当前规则',
            '2. 添加新规则',
            '3. 编辑现有规则',
            '4. 删除规则',
            '5. 重置为默认规则',
            '6. 退出'
        ].join('\n');
        
        const choice = prompt(
            `请选择操作:\n\n${options}`, 
            '1'
        );
        
        switch (choice) {
            case '1':
                showCurrentRules();
                break;
            case '2':
                addRule();
                break;
            case '3':
                editRule();
                break;
            case '4':
                deleteRule();
                break;
            case '5':
                if (confirm('确定要重置为默认规则吗?当前自定义规则将丢失')) {
                    resetToDefault();
                }
                break;
            default:
                // 任何其他选择或取消都视为退出
                break;
        }
    });

    // 1. 点击链接时替换域名
    document.addEventListener('click', function (e) {
        if (e.target.tagName.toLowerCase() === 'a') {
            try {
                const url = new URL(e.target.href);
                const matchedRule = REPLACEMENT_RULES.find(rule => 
                    url.hostname.endsWith(rule.source)
                );

                if (matchedRule) {
                    const oldUrl = e.target.href;
                    url.hostname = matchedRule.target;
                    const newUrl = url.toString();
                    
                    if (CONFIG.debug) {
                        console.log(`[自动替换] ${oldUrl} → ${newUrl}`);
                    }
                    
                    e.preventDefault();
                    GM_openInTab(newUrl, {
                        active: true,
                        insert: true,
                        setParent: true
                    });
                }
            } catch (error) {
                console.warn('[链接解析失败]', e.target.href, error);
            }
        }
    });

    // 2. 使用 webRequest API 重定向请求
    const rules = REPLACEMENT_RULES.map(rule => ({
        selector: `*://*.${rule.source}/*`,
        action: {
            type: "redirect",
            redirectUrl: (details) => {
                const url = new URL(details.url);
                url.hostname = rule.target;
                const newUrl = url.toString();
                
                if (CONFIG.debug) {
                    console.log(`[请求重定向] ${details.url} → ${newUrl}`);
                }
                
                return newUrl;
            }
        }
    }));

    GM_webRequest(rules);

    // 3. 自动刷新失败页面功能
    if (CONFIG.autoRefresh) {
        const checkPageStatus = () => {
            const isEmpty = !document.body || 
                           (document.body.textContent || '').trim() === '' ||
                           document.body.innerHTML === '';
            
            const hasError = document.body && (
                document.body.textContent.includes('404') ||
                document.body.textContent.includes('Not Found') ||
                document.body.textContent.includes('Connection refused') ||
                document.body.textContent.includes('Unable to connect') ||
                document.body.textContent.includes('This site can’t be reached')
            );
            
            const currentDomain = window.location.hostname;
            const isTargetDomain = REPLACEMENT_RULES.some(rule => 
                currentDomain.endsWith(rule.source)
            );
            
            if (isTargetDomain && (isEmpty || hasError)) {
                if (CONFIG.debug) {
                    console.log('[自动刷新] 检测到加载失败页面,尝试刷新...');
                }
                
                try {
                    const url = new URL(window.location.href);
                    const matchedRule = REPLACEMENT_RULES.find(rule => 
                        currentDomain.endsWith(rule.source)
                    );
                    
                    if (matchedRule) {
                        url.hostname = matchedRule.target;
                        const newUrl = url.toString();
                        
                        if (CONFIG.debug) {
                            console.log(`[自动刷新] 尝试重定向: ${window.location.href} → ${newUrl}`);
                        }
                        
                        setTimeout(() => {
                            window.location.replace(newUrl);
                        }, CONFIG.refreshDelay);
                    }
                } catch (error) {
                    console.error('[自动刷新] 重定向失败:', error);
                }
            }
        };
        
        window.addEventListener('load', checkPageStatus);
        setInterval(checkPageStatus, 3000);
    }
    
    // 4. 添加视觉指示器(脚本运行状态提示)
    GM_addStyle(`
        .vm-plusnet-indicator {
            position: fixed;
            bottom: 20px;
            right: 20px;
            background: #4CAF50;
            color: white;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 12px;
            z-index: 9999;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            cursor: pointer;
            animation: vm-pulse 2s infinite;
            user-select: none;
        }
        @keyframes vm-pulse {
            0% { opacity: 0.7; }
            50% { opacity: 1; }
            100% { opacity: 0.7; }
        }
    `);
    
    const indicator = document.createElement('div');
    indicator.className = 'vm-plusnet-indicator';
    indicator.textContent = `自动替换已启用 (${REPLACEMENT_RULES.length}条规则) ✅`;
    indicator.title = '点击显示当前规则';
    indicator.addEventListener('click', showCurrentRules);
    document.body.appendChild(indicator);
})();