// ==UserScript== // @name GitHub镜像 // @name:en GitHub Mirror // @description GitHub镜像,加速访问GitHub,支持Clone、Release、Raw、Zip加速。 // @description:en GitHub mirror. Accelerate access to GitHub. Support Clone, Release, RAW and ZIP acceleration. // @namespace https://github.com/HaleShaw // @version 1.3.0 // @author HaleShaw // @copyright 2021+, HaleShaw (https://github.com/HaleShaw) // @license AGPL-3.0-or-later // @homepage https://github.com/HaleShaw/TM-GitHubMirror // @supportURL https://github.com/HaleShaw/TM-GitHubMirror/issues // @contributionURL https://www.jianwudao.com/ // @icon https://github.githubassets.com/favicon.ico // @require https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js // @include *://github.com/* // @include *://github* // @compatible Chrome // @run-at document-end // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @downloadURL none // ==/UserScript== // ==OpenUserJS== // @author HaleShaw // @collaborator HaleShaw // ==/OpenUserJS== (function () { ('use strict'); const style = ` /* The menu container */ .menuContainer { width: 600px; } .menuBlock { padding: 4px 0; color: #990000; } .menuLeftIcon{ margin-right:5px; } .menuButtonLabel{ margin-right: 2rem; } .menuButtonCheck{ vertical-align: text-bottom; margin: 0 3px; } .clone { padding-left: 0 !important; width: calc(100% - 21px) !important; } `; const mirrors = [ { id: 0, name: 'CnpmJS', url: 'https://github.com.cnpmjs.org', description: 'cnpmjs.org' }, { id: 1, name: 'FastGit', url: 'https://hub.fastgit.org', description: 'KevinZonda' }, { id: 2, name: 'FastGit', url: 'https://download.fastgit.org', description: 'KevinZonda' }, { id: 3, name: 'FastGit', url: 'https://raw.fastgit.org', description: 'KevinZonda' }, { id: 4, name: 'WuYanZheShui', url: 'https://github.wuyanzheshui.workers.dev', description: 'WuYanZheShui. Maximum of 100,000 calls per day' }, { id: 5, name: 'RC1844', url: 'https://github.rc1844.workers.dev', description: 'RC1844. Maximum of 100,000 calls per day' }, { id: 6, name: 'jsDelivr', url: 'https://cdn.jsdelivr.net/gh', description: 'The total file size of the current branch of the project cannot exceed 50MB' }, { id: 7, name: 'IAPK', url: 'https://github.iapk.cc', description: 'IAPK' }, { id: 8, name: 'Ecalose', url: 'https://gh.haval.gq', description: 'Ecalose. Maximum of 100,000 calls per day' }, { id: 9, name: 'IAPK', url: 'https://iapk.cc/github?url=https://github.com', description: 'IAPK' }, { id: 10, name: 'Statically', url: 'https://cdn.staticaly.com/gh', description: 'Only images and source code files are supported, and the file size is limited to 30MB' } ]; //添加对应索引即可使用 const cloneSet = [0, 1, 4]; const browseSet = [0, 1, 4, 5, 7, 8]; const downloadSet = [2, 4, 5, 8, 9]; const rawSet = [3, 4, 5, 6, 8, 9, 10]; const messages = { en: { menuButton: { name: 'CloneMirror', title: 'Open List', header: 'Quickly clone and Mirror sites', block: 'Please do not login in the mirror site. I will not be responsible for any loss caused by this.' } }, zh: { menuButton: { name: '克隆与镜像', title: '打开列表', header: '快速克隆与镜像站点', block: '请不要在镜像网站登录账号,若因此造成任何损失本人概不负责' } } }; const icons = { closeIcon: ` `, copyIcon: ` `, commandIcon: ` `, linkIcon: ` ` }; const clonePrefix = 'git clone '; const depthPrefix = '--depth=1 '; let message; let settingHtml; main(); $(document).on('pjax:success', function () { $('#mirror-menu').remove(); main(); }); function main() { GM_addStyle(style); logInfo(GM_info.script.name, GM_info.script.version); initSetting(); message = getMessage(true, true); settingHtml = getSettingHtml(); let menuButtonHtml = getMenuButtonPrefix() + getCloneList() + getBrowseList() + getMenuButtonSuffix(); $('h1.flex-wrap.break-word.text-normal').append(menuButtonHtml); if (location.pathname.split('/')[3] == 'releases') { addReleasesList(); } if (isPC()) { addDownloadZip(); } addRawList(); } /** * Initialize setting. */ function initSetting() { let lang = GM_getValue('lang'); let clone = GM_getValue('clone'); let depth = GM_getValue('depth'); if (lang == undefined) { GM_setValue('lang', 'zh'); } if (clone == undefined) { GM_setValue('clone', true); } if (depth == undefined) { GM_setValue('depth', true); } } function getMenuButtonPrefix() { return `
${message.menuButton.name}
`; } /** * Get the clone command prefix. */ function getClonePrefix() { let prefix = ''; let clone = GM_getValue('clone'); let depth = GM_getValue('depth'); if (clone) { prefix += 'git clone '; } if (depth) { prefix += '--depth=1 '; } return prefix; } /** * Get the clone button html string. * @param {String} url url. * @param {tip} tip tip. */ function getCloneHtml(url, tip) { return `
${icons.commandIcon}
${icons.copyIcon}
`; } /** * Get the browse list. */ function getBrowseList() { let menuButtonHtml = ``; const href = window.location.href.split('/'); const path = window.location.pathname; browseSet.forEach(id => { menuButtonHtml += getBrowseHtml( mirrors[id]['url'] + path, mirrors[id]['name'], mirrors[id]['description'] ); }); if (href.length == 5 || path.includes('/tree/') || path.includes('/blob/')) { var html = mirrors[5]['url'] + path.replace('/tree/', '@').replace('/blob/', '@'); if (!path.includes('/blob/')) { html += '/'; } menuButtonHtml += getBrowseHtml(html, mirrors[5]['name'], mirrors[5]['description']); } if (location.hostname != 'github.com') { menuButtonHtml += getBrowseHtml(`https://github.com${path}`, '返回GitHub'); } return menuButtonHtml; } /** * Get browse html string. * @param {String} url url. * @param {String} name name. * @param {String} tip tip. * @returns */ function getBrowseHtml(url, name, tip = '') { return ` ${icons.linkIcon} ${url} ${name} `; } /** * Add Release list. */ function addReleasesList() { $('.Box--condensed') .find('[href]') .each(function () { const href = $(this).attr('href'); $(this) .parent() .after(`
` + getReleaseDownloadHtml(href) + `
`); $(this).parent().removeClass('Box-body'); }); } /** * Get Release download button html string. * @param {String} href href. * @returns html. */ function getReleaseDownloadHtml(href) { let html = ''; downloadSet.forEach(id => { html += `${mirrors[id]['name']}`; }); return html; } /** * Add download zip button. */ function addDownloadZip() { $("a[data-open-app='link']").each(function () { var li = $(`
  • `); const downloadHref = $(this).attr('href'); var aElement = $(this) .clone() .removeAttr('data-hydro-click data-hydro-click-hmac data-ga-click'); aElement.addClass('Box-row Box-row--hover-gray'); downloadSet.forEach(id => { let tempA = aElement.clone(); tempA.attr({ href: mirrors[id]['url'] + downloadHref, title: mirrors[id]['description'] }); tempA.html( tempA.html().replace('Download ZIP', `Download ZIP(${mirrors[id]['name']})`) ); li = li.clone().append(tempA); }); $(this).parent().after(li); }); } /** * Add Raw list. */ function addRawList() { $('#raw-url').each(function () { var href = $(this).attr('href'); rawSet.forEach(id => { if (id == 3 || id == 10) { getRawHtml(id, mirrors[id]['url'] + href.replace('/raw', '')); } else if (id == 6) { getRawHtml(id, mirrors[id]['url'] + href.replace('/raw/', '@')); } else { getRawHtml(id, mirrors[id]['url'] + href); } }); }); } /** * * @param {Number} id id of mirrors. * @param {String} url url. */ function getRawHtml(id, url) { var span = $('#raw-url').clone().removeAttr('id'); span.attr({ href: url, title: mirrors[id]['description'], target: '_blank' }); span.text(mirrors[id]['name']); $('#raw-url').before(span); } /** * Get message by setting. */ function getMessage() { return 'zh' == GM_getValue('lang') ? messages.zh : messages.en; } /** * Log the title and version at the front of the console. * @param {String} title title. * @param {String} version script version. */ function logInfo(title, version) { const titleStyle = 'color:white;background-color:#606060'; const versionStyle = 'color:white;background-color:#1475b2'; const logTitle = ' ' + title + ' '; const logVersion = ' ' + version + ' '; console.log('%c' + logTitle + '%c' + logVersion, titleStyle, versionStyle); } /** * Check if the visitor is PC. */ function isPC() { var userAgentInfo = navigator.userAgent; var agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']; var isPC = true; const len = agents.length; for (var v = 0; v < len; v++) { if (userAgentInfo.indexOf(agents[v]) > 0) { isPC = false; break; } } return isPC; } })();