您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
使用 JSON 格式配置规则,支持多条规则、独立开关
// ==UserScript== // @name 前缀转发 // @namespace http://example.com/ // @license GPL3 // @version 1 // @description 使用 JSON 格式配置规则,支持多条规则、独立开关 // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @run-at document-start // @include http://example.com/ // ==/UserScript== (function () { 'use strict'; /* ------------ 默认配置 ------------ */ const DEFAULT_RULES = [ { "name": "测试规则", "enabled": true, "prefix": "https://dev.com/api/", "replacement": "http://localhost:8080/" }, { "name": "测试规则2", "enabled": false, "prefix": "https://dev.com/api2/", "replacement": "http://localhost:8082/" } ]; /* ------------ 读取和保存规则 ------------ */ function getRules() { const savedRules = GM_getValue('rules'); if (savedRules && typeof savedRules === 'string') { try { return JSON.parse(savedRules); } catch (e) { console.error('加载保存的规则出错:', e); GM_setValue('rules', JSON.stringify(DEFAULT_RULES)); return DEFAULT_RULES; } } return DEFAULT_RULES; } function saveRules(rules) { if (Array.isArray(rules)) { GM_setValue('rules', JSON.stringify(rules)); } else { console.error('无效的规则格式。规则必须是数组格式。'); throw new Error('无效的规则格式。规则必须是数组格式。'); } } /* ------------ 核心替换逻辑 ------------ */ function redirect(url) { if (typeof url !== 'string') return url; const rules = getRules(); const normalizedUrl = url.trim(); for (const rule of rules) { if (rule.enabled) { const normalizedPrefix = rule.prefix.trim(); if (normalizedUrl.startsWith(normalizedPrefix)) { return rule.replacement + normalizedUrl.slice(normalizedPrefix.length); } } } return url; } /* ------------ 拦截 XHR ------------ */ const XHROPEN = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url, ...rest) { url = redirect(url); return XHROPEN.call(this, method, url, ...rest); }; /* ------------ 拦截 fetch ------------ */ const ORIG_FETCH = window.fetch; window.fetch = function (input, init) { if (typeof input === 'string') { input = redirect(input); } else if (input instanceof Request) { const newUrl = redirect(input.url); if (newUrl !== input.url) { input = new Request(newUrl, input); } } else if (typeof input === 'object' && input !== null && 'url' in input) { input.url = redirect(input.url); } return ORIG_FETCH.call(this, input, init); }; /* ------------ 菜单管理 ------------ */ let menuCommands = []; function buildMenu() { menuCommands.forEach(id => GM_unregisterMenuCommand(id)); menuCommands = []; const configCommand = GM_registerMenuCommand('#️⃣ 配置规则', () => { const currentRules = getRules(); const prettyJson = JSON.stringify(currentRules, null, 2); const updatedJson = prompt( '输入 JSON 格式的规则:\n[\n {\n "name": "规则名称",\n "enabled": true,\n "prefix": "原前缀",\n "replacement": "新前缀"\n }\n]', prettyJson ); if (updatedJson !== null) { try { const newRules = JSON.parse(updatedJson); if (Array.isArray(newRules)) { saveRules(newRules); showNotification('已保存,即时生效', 'success'); buildMenu(); } else { alert('规则必须是数组格式,请检查后重试'); } } catch (e) { console.error('解析输入的 JSON 出错:', e); alert('JSON 格式错误,请检查后重试'); } } }); menuCommands.push(configCommand); const rules = getRules(); rules.forEach((rule, index) => { const toggleCommand = GM_registerMenuCommand( `${rule.enabled ? '✅' : '❌'} ${rule.name}`, () => { const newRules = getRules(); if (index >= 0 && index < newRules.length) { newRules[index].enabled = !newRules[index].enabled; saveRules(newRules); showNotification(`${rule.name} 已${newRules[index].enabled ? '启用' : '禁用'},即时生效`, newRules[index].enabled ? 'success' : 'info'); buildMenu(); } } ); menuCommands.push(toggleCommand); }); } buildMenu(); /* ------------ 通知功能增强 ------------ */ function showNotification(message, type = 'info') { if (!document.body) { setTimeout(() => showNotification(message, type), 100); return; } const notification = document.createElement('div'); notification.className = `tm-notification ${type}`; // 添加类型类名 notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.classList.add('show'); }, 10); setTimeout(() => { notification.classList.remove('show'); setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } // 添加样式 const style = document.createElement('style'); style.textContent = ` .tm-notification { position: fixed; top: 20px; right: 20px; padding: 10px 20px; border-radius: 4px; font-family: Arial, sans-serif; font-size: 14px; box-shadow: 0 2px 5px rgba(0,0,0,0.2); transform: translateY(-100%); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; z-index: 9999; pointer-events: none; } .tm-notification.success { background-color: #4CAF50; /* 启用的绿色背景 */ color: white; } .tm-notification.info { background-color: #9E9E9E; /* 禁用的灰色背景 */ color: white; } .tm-notification.show { transform: translateY(0); opacity: 1; } `; document.head.appendChild(style); /* ------------ 页面加载时显示启用的规则(3秒后消失)------------ */ function showEnabledRules() { const rules = getRules(); const enabledRules = rules.filter(rule => rule.enabled); if (enabledRules.length > 0) { const enabledRuleNames = enabledRules.map(rule => rule.name).join(','); showNotification(`当前启用的规则:${enabledRuleNames}`, 'success'); } } // 页面加载完成后显示启用规则提示 window.addEventListener('load', showEnabledRules); })();