// ==UserScript== // @name GitHub Fast // @namespace http://tampermonkey.net/ // @version 1.2 // @description GitHub 中国大陆优化:智能反代、自动汉化、加速下载、优化体验 // @author You // @match *://github.com/* // @match *://www.github.com/* // @match *://raw.githubusercontent.com/* // @match *://gist.github.com/* // @match *://gh.072103.xyz/* // @match *://raw.gh.072103.xyz/* // @match *://gist.gh.072103.xyz/* // @match *://github.githubassets.com/* // @match *://codeload.github.com/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_registerMenuCommand // @grant GM_setClipboard // @grant GM_notification // @run-at document-start // ==/UserScript== (function() { 'use strict'; const config = { excludePaths: [ '/login', '/signup', '/session', '/password_reset', '/join', '/pricing', '/features/copilot', '/github-copilot', '/copilot', '/settings/copilot', '/billing/copilot', '/oauth', '/auth' ], downloadMirrors: [ 'https://ghproxy.com/', 'https://mirror.ghproxy.com/', 'https://gh.api.99988866.xyz/', 'https://download.fastgit.org/', 'https://gh.gh2233.ml/' ], imageMirrors: { 'avatars.githubusercontent.com': 'avatars.gh.072103.xyz', 'user-images.githubusercontent.com': 'user-images.gh.072103.xyz', 'raw.githubusercontent.com': 'raw.gh.072103.xyz', 'repository-images.githubusercontent.com': 'repository-images.gh.072103.xyz', 'camo.githubusercontent.com': 'camo.gh.072103.xyz' }, enabledFeatures: GM_getValue('githubFastFeatures', { autoTranslate: true, downloadAcceleration: true, imageAcceleration: true, codeHighlight: true, quickCopy: true, fileTree: true, sizeDisplay: true, timeLocalization: true, layoutOptimization: true, darkModeEnhancement: true }) }; const currentPath = window.location.pathname; const currentUrl = window.location.href; function shouldRedirect() { for (let path of config.excludePaths) { if (currentPath.startsWith(path)) { return false; } } if (window.location.hostname.includes('072103.xyz')) { return false; } return true; } if (shouldRedirect()) { let newUrl = currentUrl .replace('github.com', 'gh.072103.xyz') .replace('raw.githubusercontent.com', 'raw.gh.072103.xyz') .replace('gist.github.com', 'gist.gh.072103.xyz'); if (newUrl !== currentUrl) { window.location.replace(newUrl); return; } } const translations = { 'Dashboard': '仪表盘', 'Pull requests': '拉取请求', 'Issues': '议题', 'Marketplace': '应用市场', 'Explore': '探索', 'Sponsors': '赞助', 'Settings': '设置', 'Sign out': '退出登录', 'Sign in': '登录', 'Sign up': '注册', 'Your profile': '个人资料', 'Your repositories': '你的仓库', 'Your projects': '你的项目', 'Your stars': '你的星标', 'Your gists': '你的代码片段', 'Your organizations': '你的组织', 'Your enterprises': '你的企业', 'Upgrade': '升级', 'Feature preview': '功能预览', 'Help': '帮助', 'Code': '代码', 'Actions': '操作', 'Projects': '项目', 'Wiki': '维基', 'Security': '安全', 'Insights': '统计', 'Discussions': '讨论', 'Fork': '复刻', 'Forked from': '复刻自', 'Star': '星标', 'Unstar': '取消星标', 'Watch': '关注', 'Unwatch': '取消关注', 'Watching': '关注中', 'Not watching': '未关注', 'Ignoring': '已忽略', 'Edit': '编辑', 'Delete': '删除', 'Archive': '归档', 'Create new file': '新建文件', 'Upload files': '上传文件', 'Find file': '查找文件', 'Clone': '克隆', 'Download ZIP': '下载 ZIP', 'Open with GitHub Desktop': '使用 GitHub Desktop 打开', 'Open in Visual Studio': '在 Visual Studio 中打开', 'Open with Visual Studio Code': '使用 VS Code 打开', 'Copy path': '复制路径', 'Copy permalink': '复制永久链接', 'Commits': '提交', 'Commit': '提交', 'Branches': '分支', 'Tags': '标签', 'Contributors': '贡献者', 'Compare': '比较', 'Commit changes': '提交更改', 'Commit directly to': '直接提交到', 'Create a new branch': '创建新分支', 'Cancel': '取消', 'Propose changes': '提议更改', 'View all commits': '查看所有提交', 'View all branches': '查看所有分支', 'View all tags': '查看所有标签', 'Default branch': '默认分支', 'New issue': '新建议题', 'New pull request': '新建拉取请求', 'Labels': '标签', 'Milestones': '里程碑', 'Assignees': '受理人', 'Sort': '排序', 'Open': '开启', 'Closed': '已关闭', 'Merged': '已合并', 'Draft': '草稿', 'Filters': '筛选器', 'Author': '作者', 'Label': '标签', 'Reviews': '审查', 'Assignee': '受理人', 'Comment': '评论', 'Leave a comment': '发表评论', 'Close issue': '关闭议题', 'Reopen issue': '重新打开议题', 'Close pull request': '关闭拉取请求', 'Reopen pull request': '重新打开拉取请求', 'Merge pull request': '合并拉取请求', 'merged': '已合并', 'commented': '评论了', 'committed': '提交了', 'opened this issue': '创建了此议题', 'opened this pull request': '创建了此拉取请求', 'Public': '公开', 'Private': '私有', 'Internal': '内部', 'Description': '描述', 'Website': '网站', 'Topics': '主题', 'License': '许可证', 'Releases': '发布', 'Packages': '包', 'Deployments': '部署', 'Environments': '环境', 'Used by': '使用者', 'Languages': '语言', 'README': '自述文件', 'Activity': '活动', 'Star this repository': '星标此仓库', 'Starred': '已加星标', 'Fork your own copy': '复刻你自己的副本', 'Code review': '代码审查', 'Integrations': '集成', 'GitHub Pages': 'GitHub 页面', 'Learn more': '了解更多', 'Dismiss': '忽略', 'Get started': '开始使用', 'Documentation': '文档', 'Community': '社区', 'Support': '支持', 'Notifications': '通知', 'Account': '账户', 'Organizations': '组织', 'Saved replies': '保存的回复', 'Applications': '应用程序', 'Developer settings': '开发者设置', 'Personal access tokens': '个人访问令牌', 'Appearance': '外观', 'Accessibility': '无障碍', 'Billing and plans': '账单和计划', 'Emails': '电子邮件', 'Password and authentication': '密码和身份验证', 'SSH and GPG keys': 'SSH 和 GPG 密钥', 'Blocked users': '已屏蔽的用户', 'Code security and analysis': '代码安全与分析', 'Webhooks': 'Webhooks', 'Installed GitHub Apps': '已安装的 GitHub 应用', 'Scheduled reminders': '定时提醒', 'Security log': '安全日志', 'Sponsorship log': '赞助日志', 'now': '刚刚', 'just now': '刚刚', 'minutes ago': '分钟前', 'minute ago': '分钟前', 'hours ago': '小时前', 'hour ago': '小时前', 'days ago': '天前', 'day ago': '天前', 'months ago': '个月前', 'month ago': '个月前', 'years ago': '年前', 'year ago': '年前', 'yesterday': '昨天', 'last week': '上周', 'last month': '上个月', 'last year': '去年', 'on': '在', 'Edit file': '编辑文件', 'Edit in place': '就地编辑', 'Edit this file': '编辑此文件', 'Delete file': '删除文件', 'Delete this file': '删除此文件', 'View raw': '查看原始文件', 'View blame': '查看追溯', 'View history': '查看历史', 'Raw': '原始', 'Blame': '追溯', 'History': '历史', 'Open in GitHub Desktop': '在 GitHub Desktop 中打开', 'You must be signed in to change notification settings': '您必须登录才能更改通知设置', 'Browse files': '浏览文件', 'Loading...': '加载中...', 'Copy': '复制', 'Copied!': '已复制!', 'Quote reply': '引用回复', 'Reference in new issue': '在新议题中引用', 'Reference in new pull request': '在新拉取请求中引用', 'Submit new issue': '提交新议题', 'Submit new pull request': '提交新拉取请求', 'Add file': '添加文件', 'Add files': '添加文件', 'Create new...': '新建...', 'Jump to': '跳转到', 'Go to file': '转到文件', 'Go to line': '转到行', 'Go to definition': '转到定义', 'Switch branches/tags': '切换分支/标签', 'Drop to upload your files': '拖放文件以上传', 'We found potential security vulnerabilities in your dependencies.': '我们在您的依赖项中发现了潜在的安全漏洞。', 'Only the owner of this repository can see this message.': '只有此仓库的所有者才能看到此消息。', 'Create': '创建', 'Save': '保存', 'Saving...': '保存中...', 'Submit': '提交', 'Comment on this commit': '对此提交发表评论', 'Add a comment': '添加评论', 'Add your comment here...': '在此添加您的评论...', 'Attach files by dragging & dropping, selecting or pasting them.': '通过拖放、选择或粘贴来附加文件。', 'Styling with Markdown is supported': '支持 Markdown 格式', 'Write': '编写', 'Preview': '预览', 'Nothing to preview': '没有可预览的内容', 'Logged in as': '登录身份', 'Commit directly to the': '直接提交到', 'branch.': '分支。', 'Create a new branch for this commit and start a pull request.': '为此提交创建一个新分支并发起拉取请求。', 'Learn more about pull requests.': '了解更多关于拉取请求的信息。', 'Choose a license': '选择许可证', 'Add a README': '添加 README', 'Add .gitignore': '添加 .gitignore', 'Choose .gitignore': '选择 .gitignore', 'Filter...': '筛选...', 'Nothing to show': '没有可显示的内容', 'Loading complete': '加载完成', 'Fetching contributors': '正在获取贡献者', 'Loading branches': '正在加载分支', 'Loading tags': '正在加载标签', 'Could not load branches': '无法加载分支', 'Could not load tags': '无法加载标签', 'Confirm password to continue': '确认密码以继续', 'Confirm access': '确认访问', 'Password': '密码', 'Forgot password?': '忘记密码?', 'New to GitHub?': 'GitHub 新用户?', 'Create an account': '创建账户', 'Username or email address': '用户名或邮箱地址', 'Email address': '邮箱地址', 'Username': '用户名', 'Sign in to GitHub': '登录 GitHub', 'Code of conduct': '行为准则', 'Contact GitHub': '联系 GitHub', 'Pricing': '价格', 'API': 'API', 'Training': '培训', 'Blog': '博客', 'About': '关于', 'Repository': '仓库', 'Organization': '组织', 'Team': '团队', 'Project': '项目', 'Package': '包', 'Security policy': '安全政策', 'Security advisories': '安全公告', 'Code scanning': '代码扫描', 'Dependabot': 'Dependabot', 'Dependency graph': '依赖关系图', 'Verified': '已验证', 'This commit was signed with a verified signature.': '此提交使用已验证的签名进行签名。', 'Browse code': '浏览代码', 'Download': '下载', 'This repository': '此仓库', 'Owner': '所有者', 'Type to search': '输入以搜索', 'Search': '搜索', 'Clear': '清除', 'View all': '查看全部', 'Sponsor': '赞助', 'Report abuse': '举报滥用', 'Contact support': '联系支持', 'Manage access': '管理访问权限', 'Add people': '添加人员', 'You': '你', 'Write access': '写入权限', 'Read access': '读取权限', 'Admin access': '管理员权限', 'Collaborators': '协作者', 'Pending invitations': '待处理的邀请', 'Manage': '管理', 'Direct access': '直接访问', 'Invite a collaborator': '邀请协作者', 'Integrations & services': '集成和服务', 'Deploy keys': '部署密钥', 'Add deploy key': '添加部署密钥', 'Secrets': '密钥', 'Add secret': '添加密钥', 'Options': '选项', 'Rename': '重命名', 'Transfer': '转移', 'Transfer ownership': '转移所有权', 'Delete this repository': '删除此仓库', 'Archive this repository': '归档此仓库', 'Unarchive this repository': '取消归档此仓库', 'General': '常规', 'Access': '访问', 'Code and automation': '代码和自动化', 'Pages': '页面', 'Moderation options': '管理选项', 'Repository name': '仓库名称', 'Visibility': '可见性', 'Change visibility': '更改可见性', 'Change repository visibility': '更改仓库可见性', 'Features': '功能', 'Wikis': 'Wikis', 'Sponsorships': '赞助', 'Discussions': '讨论', 'Projects': '项目', 'Enable': '启用', 'Disable': '禁用', 'Data services': '数据服务', 'Vulnerability alerts': '漏洞警报', 'Automated security fixes': '自动安全修复', 'GitHub Pages': 'GitHub 页面', 'Build and deployment': '构建和部署', 'Source': '源', 'Branch': '分支', 'Root': '根目录', 'Folder': '文件夹', 'Save': '保存', 'Danger Zone': '危险区域', 'Make private': '设为私有', 'Make public': '设为公开', 'Transfer ownership of this repository': '转移此仓库的所有权', 'Delete this repository': '删除此仓库', 'You cannot undo this action': '此操作无法撤消', 'Please type': '请输入', 'to confirm.': '以确认。', 'I understand, delete this repository': '我明白,删除此仓库', 'New repository': '新建仓库', 'Import repository': '导入仓库', 'New gist': '新建代码片段', 'New organization': '新建组织', 'New project': '新建项目', 'This repository has been archived by the owner. It is now read-only.': '此仓库已被所有者归档。现在它是只读的。', 'Pinned': '已固定', 'Popular repositories': '热门仓库', 'Contribution activity': '贡献活动', 'Contribution settings': '贡献设置', 'Search repositories...': '搜索仓库...', 'Search issues and pull requests...': '搜索议题和拉取请求...', 'Search all of GitHub': '搜索整个 GitHub', 'Search code': '搜索代码', 'Search commits': '搜索提交', 'Search issues': '搜索议题', 'Search packages': '搜索包', 'Search people': '搜索用户', 'Search projects': '搜索项目', 'Search repositories': '搜索仓库', 'Search topics': '搜索主题', 'Search wikis': '搜索维基', 'In this repository': '在此仓库中', 'In this organization': '在此组织中', 'In this user': '在此用户中', 'All GitHub': '整个 GitHub', 'Advanced search': '高级搜索', 'Cheat sheet': '速查表', 'Sort by': '排序方式', 'Best match': '最佳匹配', 'Most stars': '最多星标', 'Fewest stars': '最少星标', 'Most forks': '最多复刻', 'Fewest forks': '最少复刻', 'Recently updated': '最近更新', 'Least recently updated': '最久未更新', 'Archived': '已归档', 'Unarchived': '未归档', 'Topics': '主题', 'Topic': '主题', 'Add topics': '添加主题', 'Manage topics': '管理主题', 'Done': '完成', 'No description provided': '未提供描述', 'Edit details': '编辑详情', 'Add a description': '添加描述', 'No description, website, or topics provided.': '未提供描述、网站或主题。', 'Provide feedback': '提供反馈', 'Saved': '已保存', 'Saving': '保存中', 'Loading': '加载中', 'Error': '错误', 'Retry': '重试', 'Homepage': '主页', 'No releases published': '未发布任何版本', 'Create a new release': '创建新版本', 'No packages published': '未发布任何包', 'Publish your first package': '发布你的第一个包', 'Members': '成员', 'People': '人员', 'Teams': '团队', 'Repositories': '仓库', 'Language': '语言', 'Type': '类型', 'All': '全部', 'Sources': '源', 'Forks': '复刻', 'Mirrors': '镜像', 'Templates': '模板', 'View all repositories': '查看所有仓库', 'New repository': '新建仓库', 'Create a new team': '创建新团队', 'Team name': '团队名称', 'Team description': '团队描述', 'Parent team': '父团队', 'Team visibility': '团队可见性', 'Visible': '可见', 'Secret': '保密', 'Add member': '添加成员', 'Remove member': '移除成员', 'Team settings': '团队设置', 'Delete team': '删除团队', 'Are you sure?': '你确定吗?', 'Billing': '账单', 'Plans and usage': '计划和使用情况', 'Payments': '付款', 'Payment methods': '付款方式', 'Payment history': '付款历史', 'Billing address': '账单地址', 'Payment information': '付款信息', 'Current plan': '当前计划', 'Free': '免费', 'Pro': '专业版', 'Team': '团队版', 'Enterprise': '企业版', 'Change plan': '更改计划', 'Cancel plan': '取消计划', 'Next billing date': '下次计费日期', 'Add payment method': '添加付款方式', 'Card number': '卡号', 'Expiration date': '到期日期', 'Security code': '安全码', 'Postal code': '邮政编码', 'Coupon, credit, or promo code': '优惠券、信用或促销代码', 'Apply': '应用', 'Summary': '摘要', 'Subtotal': '小计', 'Tax': '税', 'Total': '总计', 'per month': '每月', 'per year': '每年', 'Get started for free': '免费开始', 'Contact sales': '联系销售', 'Compare plans': '比较计划', 'FAQ': '常见问题', 'Status': '状态', 'Terms': '条款', 'Privacy': '隐私', 'Docs': '文档', 'Roadmap': '路线图', 'Careers': '招聘', 'Press': '新闻', 'Shop': '商店', 'Product': '产品', 'Solutions': '解决方案', 'Open Source': '开源', 'Enterprise': '企业', 'Customer stories': '客户案例', 'Resources': '资源', 'Platform': '平台', 'Professional services': '专业服务', 'Skills': '技能', 'What is Git?': '什么是 Git?', 'Get started': '开始使用', 'Quickstart': '快速入门', 'Learning Lab': '学习实验室', 'Guides': '指南', 'Webinars': '网络研讨会', 'What\'s new': '新功能', 'Customer Stories': '客户案例', 'Partners': '合作伙伴', 'Executive Insights': '高管洞察', 'Analyst Reports': '分析师报告', 'eBooks': '电子书', 'Whitepapers': '白皮书', 'Learn': '学习', 'Connect': '连接', 'Subscribe': '订阅', 'Thank you!': '谢谢!', 'Check your email': '检查您的电子邮件', 'Verification email sent': '验证邮件已发送', 'Email verified': '邮箱已验证', 'Email verification required': '需要邮箱验证', 'Please verify your email address': '请验证您的邮箱地址', 'Resend verification email': '重新发送验证邮件', 'Your email is verified': '您的邮箱已验证', 'Profile': '个人资料', 'Account': '账户', 'Emails': '电子邮件', 'Change password': '更改密码', 'Old password': '旧密码', 'New password': '新密码', 'Confirm new password': '确认新密码', 'Update password': '更新密码', 'I forgot my password': '我忘记了密码', 'Password changed successfully': '密码更改成功', 'Enable two-factor authentication': '启用双因素认证', 'Disable two-factor authentication': '禁用双因素认证', 'Two-factor authentication': '双因素认证', 'Recovery codes': '恢复代码', 'Generate new recovery codes': '生成新的恢复代码', 'Download': '下载', 'Print': '打印', 'Copy': '复制', 'Close': '关闭', 'Confirm': '确认', 'Enable': '启用', 'Disable': '禁用', 'Update': '更新', 'Remove': '移除', 'Required': '必填', 'Optional': '可选', 'Recommended': '推荐', 'Current': '当前', 'Default': '默认', 'Custom': '自定义', 'None': '无', 'Low': '低', 'Medium': '中', 'High': '高', 'Critical': '严重', 'Unknown': '未知', 'Pending': '待处理', 'Running': '运行中', 'Success': '成功', 'Failure': '失败', 'Cancelled': '已取消', 'Skipped': '已跳过', 'All checks have passed': '所有检查已通过', 'Some checks were not successful': '某些检查未成功', 'Some checks haven\'t completed yet': '某些检查尚未完成', 'This branch is out-of-date with the base branch': '此分支与基础分支不同步', 'Update branch': '更新分支', 'Merge pull request': '合并拉取请求', 'Squash and merge': '压缩并合并', 'Rebase and merge': '变基并合并', 'Close pull request': '关闭拉取请求', 'Reopen pull request': '重新打开拉取请求', 'Ready for review': '准备好审查', 'Convert to draft': '转换为草稿', 'Still in progress?': '仍在进行中?', 'Mark as ready for review': '标记为准备好审查', 'Request': '请求', 'Request review': '请求审查', 'Request changes': '请求更改', 'Approve': '批准', 'Review changes': '审查更改', 'Viewed': '已查看', 'Hide': '隐藏', 'Show': '显示', 'Mark as viewed': '标记为已查看', 'Mark as unviewed': '标记为未查看', 'Conversation': '对话', 'Files changed': '文件更改', 'Checks': '检查', 'Build': '构建', 'Test': '测试', 'Deploy': '部署', 'Deploy preview': '部署预览', 'Deploy to production': '部署到生产环境', 'Release': '发布', 'Pre-release': '预发布', 'Draft release': '草稿发布', 'Tag': '标签', 'Target': '目标', 'Assets': '资源', 'Source code': '源代码', 'Upload assets': '上传资源', 'Download assets': '下载资源', 'Edit release': '编辑发布', 'Delete release': '删除发布', 'Latest release': '最新发布', 'Latest': '最新', 'Draft': '草稿', 'Compare & pull request': '比较并创建拉取请求', 'New pull request': '新建拉取请求', 'base': '基础', 'compare': '比较', 'Create pull request': '创建拉取请求', 'Able to merge': '可以合并', 'Can\'t automatically merge': '无法自动合并', 'Everything up-to-date': '所有内容都是最新的', 'This branch is': '此分支', 'ahead': '领先', 'behind': '落后', 'Contribute': '贡献', 'Fetch upstream': '获取上游', 'Merge': '合并', 'Rebase': '变基', 'Push': '推送', 'Pull': '拉取', 'Checkout': '检出', 'Cherry-pick': '遴选', 'Revert': '还原', 'Reset': '重置', 'Stash': '储藏', 'Apply': '应用', 'Pop': '弹出', 'Drop': '丢弃', 'Conflict': '冲突', 'Resolve conflicts': '解决冲突', 'Mark as resolved': '标记为已解决', 'Resolved': '已解决', 'Unresolved': '未解决', 'All conflicts fixed': '所有冲突已修复', 'Commit merge': '提交合并', 'Abandon merge': '放弃合并', 'Restart merge': '重新开始合并' }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeFeatures); } else { initializeFeatures(); } function initializeFeatures() { if (config.enabledFeatures.autoTranslate) translatePage(); if (config.enabledFeatures.downloadAcceleration) addDownloadAcceleration(); if (config.enabledFeatures.imageAcceleration) accelerateImages(); if (config.enabledFeatures.quickCopy) addQuickCopyButtons(); if (config.enabledFeatures.fileTree) enhanceFileTree(); if (config.enabledFeatures.sizeDisplay) displayRepoSize(); if (config.enabledFeatures.timeLocalization) localizeTime(); if (config.enabledFeatures.layoutOptimization) optimizeLayout(); if (config.enabledFeatures.darkModeEnhancement) enhanceDarkMode(); addCustomStyles(); addKeyboardShortcuts(); addQuickJump(); observePageChanges(); setupMenuCommands(); } function translatePage() { const walker = document.createTreeWalker( document.body, NodeFilter.SHOW_TEXT, { acceptNode: function(node) { const parent = node.parentElement; if (parent && (parent.tagName === 'SCRIPT' || parent.tagName === 'STYLE' || parent.tagName === 'CODE' || parent.tagName === 'PRE' || parent.classList.contains('notranslate'))) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } } ); const textNodes = []; while (walker.nextNode()) { textNodes.push(walker.currentNode); } textNodes.forEach(node => { let text = node.textContent.trim(); if (text && translations[text]) { node.textContent = node.textContent.replace(text, translations[text]); } }); const elementsWithAttrs = document.querySelectorAll('[placeholder], [title], [aria-label], [data-original-title]'); elementsWithAttrs.forEach(elem => { ['placeholder', 'title', 'aria-label', 'data-original-title'].forEach(attr => { const value = elem.getAttribute(attr); if (value && translations[value]) { elem.setAttribute(attr, translations[value]); } }); }); } function addDownloadAcceleration() { const downloadButton = document.querySelector('[data-test-selector="download-zip-button"]'); if (downloadButton) { const accelContainer = document.createElement('div'); accelContainer.className = 'Box-row Box-row--hover-gray p-3 mt-0'; accelContainer.innerHTML = `
加速下载
`; downloadButton.parentElement.appendChild(accelContainer); accelContainer.querySelectorAll('[data-mirror]').forEach(link => { link.addEventListener('click', (e) => { e.preventDefault(); const mirrorIndex = parseInt(e.target.dataset.mirror); const mirror = config.downloadMirrors[mirrorIndex]; const repoPath = window.location.pathname.split('/').slice(1, 3).join('/'); window.open(mirror + 'https://github.com/' + repoPath + '/archive/refs/heads/main.zip'); }); }); } const releaseAssets = document.querySelectorAll('.Box-row a[href*="/releases/download/"]'); releaseAssets.forEach(asset => { if (!asset.parentElement.querySelector('.accel-download')) { const accelLink = document.createElement('a'); accelLink.className = 'ml-2 accel-download'; accelLink.href = '#'; accelLink.textContent = '[加速]'; accelLink.style.fontSize = '12px'; accelLink.onclick = (e) => { e.preventDefault(); window.open(config.downloadMirrors[0] + asset.href); }; asset.parentElement.appendChild(accelLink); } }); } function accelerateImages() { const images = document.querySelectorAll('img'); images.forEach(img => { let newSrc = img.src; for (let [original, mirror] of Object.entries(config.imageMirrors)) { if (img.src.includes(original)) { newSrc = img.src.replace(original, mirror); break; } } if (newSrc !== img.src) { img.src = newSrc; if (img.srcset) { img.srcset = img.srcset.split(',').map(src => { for (let [original, mirror] of Object.entries(config.imageMirrors)) { src = src.replace(original, mirror); } return src; }).join(','); } } }); } function addQuickCopyButtons() { const cloneButton = document.querySelector('[data-testid="code-button"]'); if (cloneButton && !document.querySelector('.quick-copy-buttons')) { const quickCopyContainer = document.createElement('div'); quickCopyContainer.className = 'quick-copy-buttons ml-2'; quickCopyContainer.style.display = 'inline-flex'; quickCopyContainer.style.gap = '4px'; const httpsUrl = document.querySelector('[data-testid="https-url-input"]'); const sshUrl = document.querySelector('[data-testid="ssh-url-input"]'); if (httpsUrl) { const httpsBtn = createCopyButton('HTTPS', httpsUrl.value); quickCopyContainer.appendChild(httpsBtn); } if (sshUrl) { const sshBtn = createCopyButton('SSH', sshUrl.value); quickCopyContainer.appendChild(sshBtn); } cloneButton.parentElement.appendChild(quickCopyContainer); } function createCopyButton(label, value) { const btn = document.createElement('button'); btn.className = 'btn btn-sm'; btn.textContent = `复制 ${label}`; btn.onclick = () => { GM_setClipboard(value); btn.textContent = '已复制!'; setTimeout(() => { btn.textContent = `复制 ${label}`; }, 2000); }; return btn; } } function enhanceFileTree() { const fileNavigation = document.querySelector('.file-navigation'); if (fileNavigation && !document.querySelector('.file-tree-toggle')) { const treeToggle = document.createElement('button'); treeToggle.className = 'btn btn-sm file-tree-toggle ml-2'; treeToggle.innerHTML = ` 文件树 `; const goToFile = fileNavigation.querySelector('[data-hotkey="t"]'); if (goToFile) { goToFile.parentElement.appendChild(treeToggle); } treeToggle.onclick = () => { toggleFileTree(); }; } } function toggleFileTree() { let fileTree = document.querySelector('.github-fast-file-tree'); if (fileTree) { fileTree.style.display = fileTree.style.display === 'none' ? 'block' : 'none'; return; } fileTree = document.createElement('div'); fileTree.className = 'github-fast-file-tree'; fileTree.style.cssText = ` position: fixed; left: 0; top: 60px; bottom: 0; width: 300px; background: var(--color-canvas-default); border-right: 1px solid var(--color-border-default); overflow-y: auto; z-index: 100; padding: 16px; `; fileTree.innerHTML = '
加载文件树中...
'; document.body.appendChild(fileTree); loadFileTree(); } function loadFileTree() { const apiPath = window.location.pathname.split('/').slice(1, 3).join('/'); const branch = document.querySelector('[data-testid="breadcrumb-current-branch"]')?.textContent || 'main'; GM_xmlhttpRequest({ method: 'GET', url: `https://api.github.com/repos/${apiPath}/git/trees/${branch}?recursive=1`, headers: { 'Accept': 'application/vnd.github.v3+json' }, onload: function(response) { if (response.status === 200) { const data = JSON.parse(response.responseText); renderFileTree(data.tree); } } }); } function renderFileTree(tree) { const fileTree = document.querySelector('.github-fast-file-tree'); if (!fileTree) return; const structure = buildTreeStructure(tree); fileTree.innerHTML = renderTreeNodes(structure); } function buildTreeStructure(flatTree) { const root = { name: '/', children: {}, type: 'tree' }; flatTree.forEach(item => { const parts = item.path.split('/'); let current = root; parts.forEach((part, index) => { if (!current.children[part]) { current.children[part] = { name: part, children: {}, type: index === parts.length - 1 ? item.type : 'tree', path: item.path }; } current = current.children[part]; }); }); return root; } function renderTreeNodes(node, level = 0) { let html = ''; const entries = Object.entries(node.children).sort((a, b) => { if (a[1].type === 'tree' && b[1].type !== 'tree') return -1; if (a[1].type !== 'tree' && b[1].type === 'tree') return 1; return a[0].localeCompare(b[0]); }); entries.forEach(([name, child]) => { const icon = child.type === 'tree' ? '📁' : '📄'; const padding = level * 20; if (child.type === 'tree') { html += `
${icon} ${name}
${renderTreeNodes(child, level + 1)}
`; } else { const filePath = child.path; const currentRepo = window.location.pathname.split('/').slice(1, 3).join('/'); const branch = document.querySelector('[data-testid="breadcrumb-current-branch"]')?.textContent || 'main'; const fileUrl = `/${currentRepo}/blob/${branch}/${filePath}`; html += `
${icon} ${name}
`; } }); return html; } function displayRepoSize() { const repoHeader = document.querySelector('[itemprop="name"]'); if (!repoHeader || document.querySelector('.repo-size-display')) return; const apiPath = window.location.pathname.split('/').slice(1, 3).join('/'); GM_xmlhttpRequest({ method: 'GET', url: `https://api.github.com/repos/${apiPath}`, headers: { 'Accept': 'application/vnd.github.v3+json' }, onload: function(response) { if (response.status === 200) { const data = JSON.parse(response.responseText); const sizeInMB = (data.size / 1024).toFixed(2); const sizeDisplay = document.createElement('span'); sizeDisplay.className = 'repo-size-display ml-2 text-small color-fg-muted'; sizeDisplay.textContent = `${sizeInMB} MB`; repoHeader.parentElement.appendChild(sizeDisplay); } } }); } function localizeTime() { const timeElements = document.querySelectorAll('time, relative-time'); timeElements.forEach(elem => { const datetime = elem.getAttribute('datetime'); if (datetime) { const date = new Date(datetime); const now = new Date(); const diff = now - date; const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); let relativeTime; if (minutes < 1) { relativeTime = '刚刚'; } else if (minutes < 60) { relativeTime = `${minutes} 分钟前`; } else if (hours < 24) { relativeTime = `${hours} 小时前`; } else if (days < 30) { relativeTime = `${days} 天前`; } else if (days < 365) { relativeTime = `${Math.floor(days / 30)} 个月前`; } else { relativeTime = `${Math.floor(days / 365)} 年前`; } elem.textContent = relativeTime; elem.title = date.toLocaleString('zh-CN'); } }); } function optimizeLayout() { const mainContent = document.querySelector('main'); if (mainContent) { mainContent.style.maxWidth = '1400px'; mainContent.style.margin = '0 auto'; } const readmeContent = document.querySelector('.markdown-body'); if (readmeContent) { readmeContent.style.fontSize = '16px'; readmeContent.style.lineHeight = '1.6'; } const codeLines = document.querySelectorAll('.blob-code-inner'); codeLines.forEach(line => { line.style.fontFamily = 'Consolas, "Liberation Mono", Menlo, Courier, monospace'; line.style.fontSize = '14px'; }); } function enhanceDarkMode() { if (document.documentElement.getAttribute('data-color-mode') === 'dark') { GM_addStyle(` :root { --color-canvas-default: #0d1117 !important; --color-canvas-subtle: #161b22 !important; --color-border-default: #30363d !important; --color-border-muted: #21262d !important; } .markdown-body { color: #c9d1d9 !important; } .markdown-body code { background-color: rgba(110, 118, 129, 0.4) !important; } .markdown-body .highlight { background-color: #161b22 !important; } `); } } function addKeyboardShortcuts() { document.addEventListener('keydown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.key === 'g' && e.ctrlKey) { e.preventDefault(); const searchInput = document.querySelector('[data-testid="header-search-input"]'); if (searchInput) searchInput.focus(); } if (e.key === 't' && e.altKey) { e.preventDefault(); toggleFileTree(); } if (e.key === 'd' && e.altKey) { e.preventDefault(); const downloadBtn = document.querySelector('[data-test-selector="download-zip-button"]'); if (downloadBtn) { window.open(config.downloadMirrors[0] + downloadBtn.href); } } if (e.key === '/' && !e.ctrlKey && !e.altKey) { e.preventDefault(); const searchInput = document.querySelector('[data-testid="header-search-input"]'); if (searchInput) searchInput.focus(); } }); } function addQuickJump() { const nav = document.querySelector('.Header'); if (nav && !document.querySelector('.quick-jump')) { const quickJump = document.createElement('div'); quickJump.className = 'quick-jump position-relative ml-3'; quickJump.innerHTML = `
🔥 热门趋势 🔍 探索项目 🏷️ 浏览主题 📚 精选合集 ❤️ 赞助项目 🔔 我的通知 ⚙️ 账户设置
`; const headerActions = nav.querySelector('.Header-actions'); if (headerActions) { headerActions.insertBefore(quickJump, headerActions.firstChild); } loadRecentRepos(); } } function loadRecentRepos() { const recentRepos = GM_getValue('recentRepos', []); const reposContainer = document.getElementById('recent-repos'); if (reposContainer && recentRepos.length > 0) { reposContainer.innerHTML = recentRepos.slice(0, 5).map(repo => ` ${repo.name} `).join(''); } const currentRepo = window.location.pathname.match(/^\/([^\/]+\/[^\/]+)/); if (currentRepo) { const repoUrl = currentRepo[0]; const repoName = currentRepo[1]; const newRecentRepos = [ { name: repoName, url: repoUrl }, ...recentRepos.filter(r => r.url !== repoUrl) ].slice(0, 10); GM_setValue('recentRepos', newRecentRepos); } } function observePageChanges() { const observer = new MutationObserver(function(mutations) { if (config.enabledFeatures.autoTranslate) translatePage(); if (config.enabledFeatures.downloadAcceleration) addDownloadAcceleration(); if (config.enabledFeatures.imageAcceleration) accelerateImages(); if (config.enabledFeatures.quickCopy) addQuickCopyButtons(); if (config.enabledFeatures.timeLocalization) localizeTime(); }); observer.observe(document.body, { childList: true, subtree: true }); } function setupMenuCommands() { GM_registerMenuCommand('⚙️ GitHub Fast 设置', () => { showSettingsDialog(); }); GM_registerMenuCommand('🔄 刷新翻译', () => { translatePage(); GM_notification({ text: '页面翻译已刷新', title: 'GitHub Fast', timeout: 2000 }); }); GM_registerMenuCommand('📊 显示仓库统计', () => { showRepoStats(); }); } function showSettingsDialog() { const dialog = document.createElement('div'); dialog.className = 'github-fast-settings-dialog'; dialog.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--color-canvas-default); border: 1px solid var(--color-border-default); border-radius: 6px; padding: 24px; z-index: 9999; box-shadow: 0 16px 32px rgba(0,0,0,0.15); max-width: 500px; width: 90%; `; dialog.innerHTML = `

GitHub Fast 设置

`; document.body.appendChild(dialog); document.getElementById('save-settings').onclick = () => { dialog.querySelectorAll('input[data-feature]').forEach(input => { config.enabledFeatures[input.dataset.feature] = input.checked; }); GM_setValue('githubFastFeatures', config.enabledFeatures); dialog.remove(); location.reload(); }; } function showRepoStats() { const apiPath = window.location.pathname.split('/').slice(1, 3).join('/'); if (!apiPath.includes('/')) return; GM_xmlhttpRequest({ method: 'GET', url: `https://api.github.com/repos/${apiPath}`, headers: { 'Accept': 'application/vnd.github.v3+json' }, onload: function(response) { if (response.status === 200) { const data = JSON.parse(response.responseText); GM_notification({ text: ` ⭐ Stars: ${data.stargazers_count} 🍴 Forks: ${data.forks_count} 👀 Watchers: ${data.watchers_count} 📊 Size: ${(data.size / 1024).toFixed(2)} MB 🌐 Language: ${data.language || 'Unknown'} 📅 Created: ${new Date(data.created_at).toLocaleDateString('zh-CN')} 🔄 Updated: ${new Date(data.updated_at).toLocaleDateString('zh-CN')} `, title: `${data.full_name} 统计信息`, timeout: 10000 }); } } }); } function addCustomStyles() { GM_addStyle(` body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans CJK SC", "Microsoft YaHei", "微软雅黑", sans-serif !important; } .quick-copy-buttons button { transition: all 0.2s ease; } .quick-copy-buttons button:hover { transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .repo-size-display { font-weight: 600; background: var(--color-neutral-muted); padding: 2px 8px; border-radius: 12px; } .accel-download { color: var(--color-accent-fg); text-decoration: none !important; font-weight: 500; } .accel-download:hover { text-decoration: underline !important; } .github-fast-file-tree { font-size: 14px; line-height: 1.5; } .tree-item { padding: 4px 0; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tree-item:hover { background: var(--color-neutral-subtle); } .tree-item.collapsed + .tree-children { display: none; } .tree-toggle { cursor: pointer; user-select: none; margin-right: 4px; } .tree-name { color: var(--color-fg-default); text-decoration: none; } .tree-name:hover { text-decoration: underline; color: var(--color-accent-fg); } .quick-jump summary { cursor: pointer; list-style: none; } .github-fast-settings-dialog input[type="checkbox"] { margin-right: 8px; } .markdown-body { font-size: 16px !important; line-height: 1.6 !important; } .markdown-body h1, .markdown-body h2, .markdown-body h3 { font-weight: 600 !important; margin-top: 24px !important; margin-bottom: 16px !important; } .blob-code-inner { font-size: 14px !important; line-height: 1.5 !important; } @media (max-width: 768px) { .github-fast-file-tree { width: 80% !important; } .quick-copy-buttons { display: block !important; margin-top: 8px !important; } .repo-size-display { display: block !important; margin-top: 4px !important; margin-left: 0 !important; } } @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } } .Header { backdrop-filter: blur(10px); } .btn-primary { background-color: #238636 !important; border-color: #238636 !important; } .btn-primary:hover { background-color: #2ea043 !important; border-color: #2ea043 !important; } details-menu { animation: fade-in 0.2s ease; } @keyframes fade-in { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .notification-indicator { transition: all 0.2s ease; } .notification-indicator:hover { transform: scale(1.1); } .commit-message { font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace !important; } .Box-row--hover-gray:hover { background-color: var(--color-canvas-subtle) !important; } .timeline-comment { border-radius: 8px !important; } .comment-body { font-size: 14px !important; line-height: 1.5 !important; } .tabnav-tab.selected { font-weight: 600 !important; } .flash { border-radius: 6px !important; margin-bottom: 16px !important; } .file-tree-toggle { transition: all 0.2s ease; } .file-tree-toggle:hover { background-color: var(--color-btn-hover-bg) !important; } .subnav-search-input { font-size: 14px !important; } .Counter { font-weight: 600 !important; } .topic-tag { transition: all 0.2s ease; } .topic-tag:hover { transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .avatar { border: 2px solid transparent; transition: border-color 0.2s ease; } .avatar:hover { border-color: var(--color-accent-emphasis); } .SelectMenu-modal { border-radius: 12px !important; box-shadow: 0 8px 24px rgba(0,0,0,0.12) !important; } .Label { font-weight: 500 !important; } .Progress { height: 8px !important; border-radius: 4px !important; } .Toast { border-radius: 6px !important; box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important; } `); } })();