// ==UserScript== // @name GitHub镜像加速 // @namespace http://tampermonkey.net/ // @version 1.0.4 // @description 自动检测GitHub连通性并重定向到镜像站点,支持文件下载加速 // @author Your Name // @match *://github.com/* // @match *://raw.githubusercontent.com/* // @match *://*.github.com/* // @match *://www.githubstatus.com/* // @match https://github.* // @exclude *kkgithub.com* // @exclude *bgithub.xyz* // @exclude *gitclone.com* // @exclude *github.ur1.fun* // @run-at document-start // @inject-into page // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_openInTab // @grant GM_addStyle // @grant GM_getTab // @grant GM_saveTab // @grant unsafeWindow // @connect github.com // @connect raw.githubusercontent.com // @connect kkgithub.com // @connect bgithub.xyz // @connect gitclone.com // @connect github.ur1.fun // @connect moeyy.cn // @connect gh-proxy.com // @connect ghproxy.net // @connect ghp.ci // @connect toolwa.com // @connect ghproxy.homeboyc.cn // ==/UserScript== (function() { 'use strict'; // 立即检查URL是否为github.com域名 const hostname = window.location.hostname; const isGithubDomain = hostname === 'github.com' || hostname.endsWith('.github.com') || (hostname.includes('github') && !hostname.includes('kkgithub') && !hostname.includes('bgithub') && !hostname.includes('gitclone') && !hostname.includes('github.ur1.fun')); // 是否为错误页面的快速检测 const isErrorPage = typeof document !== 'undefined' && (document.title.includes('无法访问') || document.title.includes('can\'t be reached') || document.title.includes('timeout') || document.title.includes('timed out') || document.title.includes('ERR_') || document.title.includes('无法连接') || document.documentElement.innerHTML.includes('ERR_CONNECTION_TIMED_OUT') || document.documentElement.innerHTML.includes('无法访问此网站')); // 默认配置 const defaultConfig = { enabled: true, autoMode: true, lastCheck: 0, isGitHubAccessible: false, // 默认不可访问,安全起见 checkInterval: 5 * 60 * 1000, // 检查间隔,默认5分钟 selectedMirror: 'kkgithub.com', mirrors: [ { name: 'BGitHub', url: 'bgithub.xyz' }, { name: 'KKGitHub', url: 'kkgithub.com' }, { name: 'GitClone', url: 'gitclone.com/github.com' }, { name: 'GitHub加速下载', url: 'github.ur1.fun' } ], selectedFileProxy: 'https://moeyy.cn/gh-proxy/', fileProxies: [ { name: 'Moeyy', url: 'https://moeyy.cn/gh-proxy/' }, { name: 'GHProxy.com', url: 'https://gh-proxy.com/' }, { name: 'GHProxy.net', url: 'https://ghproxy.net/' }, { name: 'GHProxy.ci', url: 'https://ghp.ci/' }, { name: 'TOOLWA', url: 'http://toolwa.com/github/' }, { name: 'HomeBoyCi', url: 'https://ghproxy.homeboyc.cn/' } ] }; // 获取配置 let config = GM_getValue('config', defaultConfig); // 如果是GitHub域名,直接执行重定向逻辑 if (isGithubDomain) { // 检查是否是错误页面 if (isErrorPage) { // 错误页面直接重定向 redirectToMirror(); } else { // 普通页面走检测逻辑 tryRedirect(); } } // 尝试重定向 function tryRedirect() { // 只在启用状态下执行 if (!config.enabled) return; // 如果非自动模式,或者自动模式下GitHub不可访问,执行重定向 if (!config.autoMode || (config.autoMode && !config.isGitHubAccessible)) { redirectToMirror(); return; } // 在自动模式下,且没有明确判断GitHub不可访问时,进行快速检测 fastCheckAndRedirect(); } // 执行镜像重定向 function redirectToMirror() { try { const currentUrl = window.location.href; const url = new URL(currentUrl); // 检查是否已经是镜像站点 if (url.hostname === config.selectedMirror || url.hostname.includes(config.selectedMirror.split('/')[0])) { return; } // 构建新的镜像URL url.hostname = config.selectedMirror; // 使用replace以避免留在历史记录中 console.log("正在重定向到: " + url.toString()); window.location.replace(url.toString()); } catch (e) { console.error('重定向时出错:', e); } } // 快速检测GitHub可访问性并重定向 function fastCheckAndRedirect() { const now = Date.now(); // 如果近期检查过,使用缓存结果 if (now - config.lastCheck < config.checkInterval) { if (!config.isGitHubAccessible) { redirectToMirror(); } return; } // 更新检查时间 config.lastCheck = now; // 设置1秒超时 const timeoutId = setTimeout(() => { // 超时认为不可访问 config.isGitHubAccessible = false; GM_setValue('config', config); redirectToMirror(); }, 1000); // 尝试访问favicon const img = new Image(); img.onload = function() { clearTimeout(timeoutId); config.isGitHubAccessible = true; GM_setValue('config', config); // 可访问,不重定向 }; img.onerror = function() { clearTimeout(timeoutId); config.isGitHubAccessible = false; GM_setValue('config', config); redirectToMirror(); }; img.src = 'https://github.com/favicon.ico?' + new Date().getTime(); } // 检查GitHub可访问性 (用于其他操作) function checkGitHubAccessibility() { return new Promise((resolve) => { // 如果距离上次检查的时间不足checkInterval,则使用上次的结果 const now = Date.now(); if (now - config.lastCheck < config.checkInterval) { resolve(config.isGitHubAccessible); return; } // 更新上次检查时间 config.lastCheck = now; // 设置超时处理 const timeout = setTimeout(() => { config.isGitHubAccessible = false; GM_setValue('config', config); updateUI(); resolve(false); }, 2000); // 2秒超时 // 使用GM_xmlhttpRequest进行网络测试 GM_xmlhttpRequest({ method: 'HEAD', url: 'https://github.com/favicon.ico', timeout: 2000, onload: function(response) { clearTimeout(timeout); config.isGitHubAccessible = true; GM_setValue('config', config); updateUI(); console.log('GitHub 可访问,不需要使用镜像'); resolve(true); }, onerror: function(error) { clearTimeout(timeout); config.isGitHubAccessible = false; GM_setValue('config', config); updateUI(); console.log('GitHub 不可访问,将使用镜像', error); resolve(false); } }); }); } // 更新UI显示 function updateUI() { const status = document.getElementById('github-mirror-status'); if (status) { if (config.isGitHubAccessible) { status.textContent = 'GitHub 可正常访问'; status.className = 'github-mirror-status good'; } else { status.textContent = 'GitHub 无法访问,使用镜像'; status.className = 'github-mirror-status bad'; } } } // 添加状态显示元素 function addStatusElement() { try { // 尝试添加到Header const header = document.querySelector('.Header'); if (header && !document.getElementById('github-mirror-status')) { const status = document.createElement('div'); status.id = 'github-mirror-status'; status.className = 'github-mirror-status'; status.textContent = '检测中...'; header.appendChild(status); return; } // 如果没有找到Header,则创建一个悬浮元素 if (!document.getElementById('github-mirror-status') && document.body) { const status = document.createElement('div'); status.id = 'github-mirror-status'; status.className = 'github-mirror-status floating'; status.textContent = '检测中...'; document.body.appendChild(status); } } catch (e) { console.error('添加状态元素时出错:', e); } } // 修改下载链接 function modifyDownloadLinks() { try { // 查找所有指向GitHub资源的链接 const links = document.querySelectorAll('a[href*="github.com"], a[href*="raw.githubusercontent.com"], a[href*="releases/download"]'); links.forEach(link => { const href = link.getAttribute('href'); // 检查是否为文件下载链接 if (isFileDownloadLink(href) && config.selectedFileProxy) { // 使用文件代理替换链接 link.setAttribute('original-href', href); link.setAttribute('href', `${config.selectedFileProxy}${href}`); link.setAttribute('data-gh-proxy', 'true'); // 添加视觉提示 link.style.color = '#1e88e5'; } }); } catch (e) { console.error('修改下载链接时出错:', e); } } // 判断是否为文件下载链接 function isFileDownloadLink(url) { // 检查是否是常见的GitHub资源下载链接 const patterns = [ /github\.com\/.*\/releases\/download\//, /raw\.githubusercontent\.com\//, /github\.com\/.*\/archive\//, /github\.com\/.*\/blob\//, /codeload\.github\.com\// ]; return patterns.some(pattern => pattern.test(url)); } // 注册菜单命令 function registerMenuCommands() { try { // 启用/禁用开关 GM_registerMenuCommand( config.enabled ? '禁用GitHub镜像加速' : '启用GitHub镜像加速', function() { config.enabled = !config.enabled; GM_setValue('config', config); GM_notification({ text: config.enabled ? '已启用GitHub镜像加速' : '已禁用GitHub镜像加速', timeout: 3000 }); } ); // 自动模式开关 GM_registerMenuCommand( config.autoMode ? '关闭自动检测模式' : '开启自动检测模式', function() { config.autoMode = !config.autoMode; GM_setValue('config', config); GM_notification({ text: config.autoMode ? '已开启自动检测模式' : '已关闭自动检测模式', timeout: 3000 }); } ); // 立即检测 GM_registerMenuCommand('立即检测GitHub连通性', function() { checkGitHubAccessibility(); }); // 直接进入镜像站点 GM_registerMenuCommand('直接进入镜像站点', function() { const currentUrl = window.location.href; const url = new URL(currentUrl); url.hostname = config.selectedMirror; window.location.href = url.toString(); }); // 打开设置面板 GM_registerMenuCommand('打开设置面板', function() { openSettingsPanel(); }); } catch (e) { console.error('注册菜单时出错:', e); } } // 设置面板 function openSettingsPanel() { try { // 关闭已存在的面板 const existingPanel = document.getElementById('github-mirror-settings-panel'); if (existingPanel) { document.body.removeChild(existingPanel); return; } // 创建面板容器 const panel = document.createElement('div'); panel.id = 'github-mirror-settings-panel'; panel.className = 'github-mirror-settings-panel'; // 面板内容 panel.innerHTML = `
开启后,只在GitHub不可访问时自动切换到镜像站点