// ==UserScript== // @name 多平台镜像站自动转换(带开关) // @namespace http://tampermonkey.net/ // @version 1.4 // @description 可开关的镜像站转换:支持GreasyFork、GitHub、Chrome商店,带红色标记 // @author 平凡的世界 // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-end // ==/UserScript== (function() { 'use strict'; const DEFAULT_SETTINGS = { greasyforkEnabled: true, githubEnabled: true, chromeEnabled: true }; let settings = GM_getValue('mirrorSettings', DEFAULT_SETTINGS); const PLATFORMS = [ { original: 'greasyfork.org', mirror: 'greasyfork.icu', regex: /^https:\/\/greasyfork\.org(\/.*)?$/ }, { original: 'github.com', mirror: 'kkgithub.com', regex: /^https:\/\/github\.com(\/.*)?$/ }, { original: 'chrome.google.com', mirror: 'www.crxsoso.com/webs/det', regex: /^https:\/\/chrome\.google\.com\/webstore\/detail\/[^\/]+\/([a-zA-Z0-9]+)$/ } ]; function replaceLink(link) { const href = link.href; if (link.dataset.linkReplaced) return; for (const platform of PLATFORMS) { let isEnabled = true; if (platform.original === 'greasyfork.org') isEnabled = settings.greasyforkEnabled; if (platform.original === 'github.com') isEnabled = settings.githubEnabled; if (platform.original === 'chrome.google.com') isEnabled = settings.chromeEnabled; if (!isEnabled) continue; if (platform.regex.test(href)) { let mirrorUrl; if (platform.original === 'chrome.google.com') { const match = href.match(platform.regex); mirrorUrl = `https://${platform.mirror}/${match[1]}`; } else { mirrorUrl = href.replace(platform.original, platform.mirror); } link.href = mirrorUrl; const tag = document.createElement('span'); tag.textContent = '(已转换)'; tag.style.color = 'red'; tag.style.marginLeft = '5px'; tag.style.fontSize = '0.8em'; link.parentNode.insertBefore(tag, link.nextSibling); link.dataset.linkReplaced = 'true'; break; } } } function replaceAllLinks() { document.querySelectorAll('a[href]').forEach(replaceLink); } const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { node.tagName === 'A' ? replaceLink(node) : node.querySelectorAll('a[href]').forEach(replaceLink); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); replaceAllLinks(); GM_registerMenuCommand('镜像站转换开关', showSettingsDialog); function showSettingsDialog() { const dialog = document.createElement('div'); dialog.style.cssText = ` position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); background:#fff; padding:20px; border:1px solid #ccc; z-index:9999; box-shadow:0 0 10px rgba(0,0,0,0.3); width:300px; font-family:Arial,sans-serif; `; const title = document.createElement('div'); title.textContent = '镜像站转换开关'; title.style.cssText = 'font-size:16px; font-weight:bold; margin-bottom:15px;'; const createSwitch = (label, key) => { const div = document.createElement('div'); const input = document.createElement('input'); input.type = 'checkbox'; input.checked = settings[key]; input.onchange = () => (settings[key] = input.checked); const span = document.createElement('span'); span.textContent = label; span.style.marginLeft = '5px'; div.appendChild(input); div.appendChild(span); return div; }; const items = [ createSwitch('GreasyFork 转换', 'greasyforkEnabled'), createSwitch('GitHub 转换', 'githubEnabled'), createSwitch('Chrome商店 转换', 'chromeEnabled') ]; const saveBtn = document.createElement('button'); saveBtn.textContent = '保存'; saveBtn.style.cssText = 'margin-top:15px; padding:5px 10px;'; saveBtn.onclick = () => { GM_setValue('mirrorSettings', settings); dialog.remove(); mask.remove(); }; const mask = document.createElement('div'); mask.style.cssText = ` position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.3); z-index:9998; `; mask.onclick = () => { dialog.remove(); mask.remove(); }; dialog.appendChild(title); items.forEach(item => dialog.appendChild(item)); dialog.appendChild(saveBtn); document.body.appendChild(mask); document.body.appendChild(dialog); } })();