您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动代理GitHub链接,支持自定义代理服务器和域名
// ==UserScript== // @name GitHub Proxy Redirector | GitHub 代理自动选择 // @namespace https://github.com/DingerBtn/GithubAutoProxy // @version 2.0 // @description 自动代理GitHub链接,支持自定义代理服务器和域名 // @author DingerBtn // @homepage https://github.com/DingerBtn/GithubAutoProxy // @license GPL-3.0 // @match *://github.com/* // @match *://gist.github.com/* // @match *://raw.githubusercontent.com/* // @match *://*.github.io/* // @match *://githubassets.com/* // @match *://github.dev/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @grant GM_addStyle // @run-at document-start // @icon https://github.githubassets.com/favicons/favicon.png // @thanks https://github.akams.cn/ // ==/UserScript== (function() { 'use strict'; // 只在 github 相关域名下启用脚本 const GITHUB_DOMAINS = [ 'github.com', 'gist.github.com', 'raw.githubusercontent.com', 'github.io', 'githubassets.com', 'github.dev' ]; const isGithubSite = GITHUB_DOMAINS.some(domain => { const host = window.location.hostname.toLowerCase(); return host === domain || host.endsWith('.' + domain); }); if (!isGithubSite) return; // ========== 默认配置 ========== const DEFAULT_DOMAINS = [ "github.com", "gist.github.com", "raw.githubusercontent.com", "github.io", "githubassets.com", "github.dev" ]; const DEFAULT_CONFIG = { enabled: true, proxyList: [ { id: 1, name: "默认代理", prefix: "https://github.akams.cn/", active: true, domains: [...DEFAULT_DOMAINS] } ] }; // ========== 配置管理 ========== let config = GM_getValue('proxyConfig', DEFAULT_CONFIG); // 保证配置结构完整 if (!config.proxyList) config.proxyList = DEFAULT_CONFIG.proxyList; if (typeof config.enabled !== 'boolean') config.enabled = DEFAULT_CONFIG.enabled; // 兼容老配置 if (config.proxyList && config.proxyList.length > 0 && !config.proxyList[0].domains) { const oldDomains = config.targetDomains || DEFAULT_DOMAINS; config.proxyList.forEach(p => p.domains = [...oldDomains]); delete config.targetDomains; } const saveConfig = () => GM_setValue('proxyConfig', config); const getActiveProxy = () => config.proxyList.find(p => p.active) || config.proxyList[0]; // ========== 代理核心 ========== // 只代理特定类型的 GitHub 链接 const shouldProxy = (url) => { if (!config.enabled) return false; if (!url) return false; try { const u = new URL(url); const host = u.hostname.toLowerCase(); const path = u.pathname; // 1. 分支源码 if (host === 'github.com' && (/\/archive\/(master\.zip|main\.zip|[\w.-]+\.(zip|tar\.gz))$/.test(path))) { return true; } // 2. release源码 if (host === 'github.com' && /\/archive\/(v[\w.-]+\.(zip|tar\.gz))$/.test(path)) { return true; } // 3. release文件 if (host === 'github.com' && /\/releases\/download\//.test(path)) { return true; } // 4. commit文件 if (host === 'github.com' && /\/blob\/[\w\d]+\//.test(path)) { return true; } // 5. gist if (host === 'gist.githubusercontent.com' && /\/raw\//.test(path)) { return true; } // 6. api if (host === 'api.github.com') { return true; } return false; } catch { return false; } }; const proxyUrl = (original) => { const proxyPrefix = getActiveProxy().prefix; if (original.startsWith(proxyPrefix)) return original; return proxyPrefix + original; }; // ========== 代理逻辑 ========== // 1. 拦截a标签点击 document.addEventListener('click', event => { const link = event.target.closest && event.target.closest('a'); if (!link || !shouldProxy(link.href)) return; // 忽略新窗口/标签页 if (event.ctrlKey || event.shiftKey || event.metaKey || event.button !== 0) return; event.preventDefault(); window.location.href = proxyUrl(link.href); }, true); // 2. 拦截AJAX请求 const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { if (shouldProxy(url)) { arguments[1] = proxyUrl(url); } return originalOpen.apply(this, arguments); }; // 3. 处理动态内容 const processLinks = () => { document.querySelectorAll('a[href]').forEach(link => { if (shouldProxy(link.href) && !link.dataset.proxied) { link.dataset.proxied = true; // 防止右键菜单直接跳转 link.addEventListener('click', e => { if (e.ctrlKey || e.shiftKey || e.metaKey || e.button !== 0) return; e.preventDefault(); window.location.href = proxyUrl(link.href); }); } }); }; // 4. 监听DOM变化 const observer = new MutationObserver(processLinks); window.addEventListener('DOMContentLoaded', () => { observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['href'] }); processLinks(); }); // 5. 处理页面初始加载 window.addEventListener('load', processLinks); // ========== 设置界面 ========== function createSettingsUI() { GM_addStyle(` /* 脚本名称样式 */ .settings-title { font-size: 18px; font-weight: 600; } .manage-domains-btn { background: #0366d6; color: #fff; border: none; border-radius: 4px; padding: 6px 14px; font-size: 14px; margin-left: 14px; cursor: pointer; transition: background 0.2s; } .manage-domains-btn:hover { background: #024fa2; } .proxy-domains { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 0 0; } .proxy-domain-tag { background: #f1f8ff; border: 1px solid #c8e1ff; border-radius: 4px; padding: 2px 7px; font-size: 12px; display: flex; align-items: center; } .remove-proxy-domain { margin-left: 4px; cursor: pointer; color: #cb2431; } .add-proxy-domain { display: flex; margin-top: 4px; } .add-proxy-domain-input { flex: 1; padding: 4px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; } .add-proxy-domain-btn { background: #28a745; color: white; border: none; border-radius: 4px; padding: 4px 10px; margin-left: 6px; cursor: pointer; } .proxy-settings { position: fixed; top: 20px; right: 20px; z-index: 9999; background: white; border: 1px solid #ddd; border-radius: 8px; padding: 20px; width: 400px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); font-family: system-ui, sans-serif; color: #333; } .settings-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 10px; border-bottom: 1px solid #eee; } .settings-title { font-size: 18px; font-weight: 600; } .close-btn { background: none; border: none; font-size: 20px; cursor: pointer; color: #666; } .section-title { margin: 15px 0 8px 0; font-weight: 500; color: #0366d6; font-size: 15px; } .proxy-list { margin: 10px 0; } .proxy-item { display: flex; align-items: center; padding: 8px; border: 1px solid #eee; border-radius: 4px; margin-bottom: 8px; } .proxy-radio { margin-right: 10px; } .proxy-input { flex: 1; padding: 6px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; } .domain-list { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; } .domain-tag { background: #f1f8ff; border: 1px solid #c8e1ff; border-radius: 4px; padding: 4px 8px; font-size: 13px; display: flex; align-items: center; } .remove-domain { margin-left: 6px; cursor: pointer; color: #cb2431; } .add-domain { display: flex; margin-top: 10px; } .domain-input { flex: 1; padding: 6px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; } .add-btn { background: #28a745; color: white; border: none; border-radius: 4px; padding: 6px 12px; margin-left: 8px; cursor: pointer; } .save-btn { background: #0366d6; color: white; border: none; border-radius: 4px; padding: 8px 16px; width: 100%; margin-top: 15px; font-weight: 500; cursor: pointer; } `); const settingsPanel = document.createElement('div'); settingsPanel.className = 'proxy-settings'; settingsPanel.innerHTML = ` <div class="settings-header"> <div class="settings-title">GitHub 代理选择</div> <button class="close-btn">×</button> </div> <div style="margin-bottom: 10px;"> <label style="display: flex; align-items: center; gap: 8px; font-size: 15px;"> <input type="checkbox" id="proxyEnabled" ${config.enabled ? 'checked' : ''}> <span>启用代理</span> </label> </div> <div class="section-title">代理服务器</div> <div class="proxy-list" id="proxyList"></div> <div class="section-title">目标域名</div> <div class="domain-list" id="domainList"></div> <div class="add-domain"> <input type="text" class="domain-input" id="newDomain" placeholder="添加新域名 (如: github.com)"> <button class="add-btn" id="addDomainBtn">+ 添加</button> </div> <button class="save-btn" id="saveConfigBtn">保存设置</button> `; document.body.appendChild(settingsPanel); // 关闭按钮 settingsPanel.querySelector('.close-btn').addEventListener('click', () => { document.body.removeChild(settingsPanel); }); // 渲染代理服务器列表 const renderProxyList = () => { const container = settingsPanel.querySelector('#proxyList'); container.innerHTML = ''; config.proxyList.forEach(proxy => { const proxyItem = document.createElement('div'); proxyItem.className = 'proxy-item'; proxyItem.innerHTML = ` <input type="radio" name="activeProxy" class="proxy-radio" ${proxy.active ? 'checked' : ''} data-id="${proxy.id}"> <input type="text" class="proxy-input" value="${proxy.prefix}" data-id="${proxy.id}" placeholder="https://代理地址/"> <button class="manage-domains-btn" data-id="${proxy.id}">管理域名</button> `; container.appendChild(proxyItem); }); }; // 域名管理弹窗 function openDomainManager(proxyId) { const proxy = config.proxyList.find(p => p.id === proxyId); if (!proxy) return; let modal = document.createElement('div'); modal.style = 'position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.25);z-index:10000;display:flex;align-items:center;justify-content:center;'; modal.innerHTML = ` <div style="background:#fff;padding:24px 28px;border-radius:10px;min-width:340px;max-width:90vw;box-shadow:0 4px 16px rgba(0,0,0,0.18);"> <div style="font-size:17px;font-weight:600;margin-bottom:12px;">管理代理域名</div> <div id="domain-list-modal" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;"></div> <div style="display:flex;gap:8px;"> <input id="add-domain-modal-input" type="text" placeholder="添加域名 (如: github.com)" style="flex:1;padding:6px;border:1px solid #ddd;border-radius:4px;font-size:14px;"> <button id="add-domain-modal-btn" style="background:#28a745;color:#fff;border:none;border-radius:4px;padding:6px 14px;cursor:pointer;">+ 添加</button> </div> <div style="text-align:right;margin-top:18px;"> <button id="close-domain-modal-btn" style="background:#0366d6;color:#fff;border:none;border-radius:4px;padding:7px 18px;font-size:15px;cursor:pointer;">完成</button> </div> </div> `; document.body.appendChild(modal); const renderModalList = () => { const list = modal.querySelector('#domain-list-modal'); list.innerHTML = ''; proxy.domains.forEach(domain => { const tag = document.createElement('div'); tag.style = 'background:#f1f8ff;border:1px solid #c8e1ff;border-radius:4px;padding:4px 10px;font-size:13px;display:flex;align-items:center;'; tag.innerHTML = `${domain}<span data-domain="${domain}" style="margin-left:6px;cursor:pointer;color:#cb2431;font-size:15px;">×</span>`; tag.querySelector('span').onclick = () => { proxy.domains = proxy.domains.filter(d => d !== domain); renderModalList(); renderProxyDomainsSelect(proxy); }; list.appendChild(tag); }); }; renderModalList(); modal.querySelector('#add-domain-modal-btn').onclick = () => { const input = modal.querySelector('#add-domain-modal-input'); const domain = input.value.trim().toLowerCase(); if (domain && !proxy.domains.includes(domain)) { proxy.domains.push(domain); input.value = ''; renderModalList(); renderProxyDomainsSelect(proxy); } }; modal.querySelector('#close-domain-modal-btn').onclick = () => { document.body.removeChild(modal); }; } // 渲染域名列表 const renderDomainList = () => { const container = settingsPanel.querySelector('#domainList'); container.innerHTML = ''; config.targetDomains.forEach(domain => { const domainTag = document.createElement('div'); domainTag.className = 'domain-tag'; domainTag.innerHTML = ` ${domain} <span class="remove-domain" data-domain="${domain}">×</span> `; container.appendChild(domainTag); }); }; // 初始渲染 renderProxyList(); // 代理服务器单选、域名选择、管理域名按钮 settingsPanel.addEventListener('change', e => { if (e.target.classList.contains('proxy-radio')) { const id = parseInt(e.target.dataset.id); config.proxyList.forEach(p => p.active = (p.id === id)); } if (e.target.classList.contains('proxy-domain-checkbox')) { const id = parseInt(e.target.dataset.id); const domain = e.target.dataset.domain; const proxy = config.proxyList.find(p => p.id === id); if (!proxy) return; if (e.target.checked) { if (!proxy.domains.includes(domain)) proxy.domains.push(domain); } else { proxy.domains = proxy.domains.filter(d => d !== domain); } } }); settingsPanel.addEventListener('click', e => { if (e.target.classList.contains('manage-domains-btn')) { const id = parseInt(e.target.dataset.id); openDomainManager(id); } }); // 兼容保留原有域名管理(可选:如不需要可移除) // settingsPanel.querySelector('#addDomainBtn').addEventListener('click', ...) // settingsPanel.addEventListener('click', ...) // 启用/禁用代理 settingsPanel.querySelector('#proxyEnabled').addEventListener('change', e => { config.enabled = e.target.checked; }); // 保存配置 settingsPanel.querySelector('#saveConfigBtn').addEventListener('click', () => { saveConfig(); alert('设置已保存!页面将刷新应用更改'); location.reload(); }); } // ========== 菜单与按钮 ========== GM_registerMenuCommand("GitHub 代理设置", createSettingsUI); // 页面右下角设置按钮 function createSettingsButton() { const btn = document.createElement('button'); btn.innerHTML = config.enabled ? '⚙️' : '⚙️❌'; btn.title = config.enabled ? 'GitHub 代理已启用' : 'GitHub 代理已禁用'; btn.style = ` position: fixed; bottom: 20px; right: 20px; z-index: 9999; width: 40px; height: 40px; border-radius: 50%; background: #0366d6; color: white; border: none; font-size: 20px; cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,0.2); `; btn.addEventListener('click', createSettingsUI); document.body.appendChild(btn); } // 仅在 github 相关域名下插入设置按钮 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createSettingsButton); } else { createSettingsButton(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址