Github Download

高速下载gihthub

  1. // ==UserScript==
  2. // @name Github Download
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description 高速下载gihthub
  6. // @author Joye-bot
  7. // @license GPL-3.0 License
  8. // @match *://github.com/*
  9. // @match *://github*
  10. // @icon https://github.githubassets.com/favicon.ico
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. // Your code here...
  18. const cloneUrl = [
  19. ["https://kgithub.com", "kGithub", "该公益加速源由 [kGithub] 提供

 - 缓存: 无(时间很短)"],
  20. ["https://ghproxy.com/https://github.com", "ghproxy", "该公益加速源由 [ghproxy] 提供"],
  21. ["https://hub.njuu.cf", "njuu", "该公益加速源由 [LibraryCloud] 提供"],
  22. ["https://hub.yzuu.cf", "yzuu", "该公益加速源由 [LibraryCloud] 提供"],
  23. ];
  24.  
  25. const downloadUrl = [
  26. // ["https://download.fastgit.org", "FastGit", "由KevinZonda推动的FastGit项目"],
  27. ["https://ghproxy.com/https://github.com", "ghproxy", "由 [ghproxy] 提供"],
  28. // ["https://gh.gh2233.ml/https://github.com", "gh2333", "由 [@X.I.U/XIU2] 提供"],
  29. // ["https://gh.ddlc.top/https://github.com", "ddlc", "由 [@mtr-static-official] 提供"]
  30. // ['https://gh2.yanqishui.work/https://github.com', 'yanqishui', '由 [@HongjieCN] 提供'],
  31. ['https://ghdl.feizhuqwq.cf/https://github.com', 'feizhuqwq', '由 [feizhuqwq.com] 提供'],
  32. // ['https://gh-proxy-misakano7545.koyeb.app/https://github.com', 'koyeb', ''],
  33. ['https://gh.flyinbug.top/gh/https://github.com', 'flyinbug', '由 [Mintimate] 提供'],
  34. ['https://github.91chi.fun/https://github.com', '91chi', ''],
  35. ];
  36.  
  37. const sshUrl = [
  38. ["git@git.zhlh6.cn:", "zhlh6", "利用ucloud提供的GlobalSSH"],
  39. ];
  40.  
  41. const svg = [
  42. '<svg class="octicon octicon-file-zip mr-2" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true"><path fill-rule="evenodd" d="M3.5 1.75a.25.25 0 01.25-.25h3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h2.086a.25.25 0 01.177.073l2.914 2.914a.25.25 0 01.073.177v8.586a.25.25 0 01-.25.25h-.5a.75.75 0 000 1.5h.5A1.75 1.75 0 0014 13.25V4.664c0-.464-.184-.909-.513-1.237L10.573.513A1.75 1.75 0 009.336 0H3.75A1.75 1.75 0 002 1.75v11.5c0 .649.353 1.214.874 1.515a.75.75 0 10.752-1.298.25.25 0 01-.126-.217V1.75zM8.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM6 5.25a.75.75 0 01.75-.75h.5a.75.75 0 010 1.5h-.5A.75.75 0 016 5.25zm2 1.5A.75.75 0 018.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 6.75zm-1.25.75a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM8 9.75A.75.75 0 018.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 9.75zm-.75.75a1.75 1.75 0 00-1.75 1.75v3c0 .414.336.75.75.75h2.5a.75.75 0 00.75-.75v-3a1.75 1.75 0 00-1.75-1.75h-.5zM7 12.25a.25.25 0 01.25-.25h.5a.25.25 0 01.25.25v2.25H7v-2.25z"></path></svg>',
  43. '<svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon d-inline-block"><path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path></svg><svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-inline-block d-sm-none"><path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>',
  44. '<svg class="octicon octicon-cloud-download" aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M9 12h2l-3 3-3-3h2V7h2v5zm3-8c0-.44-.91-3-4.5-3C5.08 1 3 2.92 3 5 1.02 5 0 6.52 0 8c0 1.53 1 3 3 3h3V9.7H3C1.38 9.7 1.3 8.28 1.3 8c0-.17.05-1.7 1.7-1.7h1.3V5c0-1.39 1.56-2.7 3.2-2.7 2.55 0 3.13 1.55 3.2 1.8v1.2H12c.81 0 2.7.22 2.7 2.2 0 2.09-2.25 2.2-2.7 2.2h-2V11h2c2.08 0 4-1.16 4-3.5C16 5.06 14.08 4 12 4z"></path></svg>'
  45. ];
  46.  
  47. const style = [
  48. 'padding:0 6px; margin-right: -1px; border-radius: 2px; background-color: var(--XIU2-back-Color); border-color: rgba(27, 31, 35, 0.1); font-size: 11px; color: var(--XIU2-font-Color);'
  49. ];
  50.  
  51. /**
  52. * 添加克隆列表
  53. */
  54. function addCloneList() {
  55. if (document.querySelector('.XIU2-GC')) return;
  56. let html = document.querySelector('[role="tabpanel"]:nth-child(2) div.input-group');
  57. if (!html) return
  58. let href_split = html.getElementsByTagName('input')[0].getAttribute('value').split(location.host);
  59. let url = '';
  60. let _html = '';
  61.  
  62. for (let i = 0; i < cloneUrl.length; i++) {
  63. url = cloneUrl[i][0] + href_split[1]
  64. _html +=
  65. `<div class="input-group XIU2-GC" style="margin-top: 4px;" title="加速源: ${cloneUrl[i][1]} (点击可直接复制)">` +
  66. `<input value="${url}" aria-label="${url}" title="${cloneUrl[i][2]}" type="text" class="form-control input-monospace input-sm color-bg-subtle" data-autoselect="" readonly="">` +
  67. `<div class="input-group-button">` +
  68. `<clipboard-copy value="${url}" aria-label="Copy to clipboard" class="btn btn-sm js-clipboard-copy tooltipped-no-delay ClipboardButton" tabindex="0" role="button">` +
  69. `${svg[1]}` +
  70. `</clipboard-copy>` +
  71. `</div>` +
  72. `</div>`;
  73. }
  74. html.insertAdjacentHTML('afterend', _html);
  75. }
  76.  
  77. /**
  78. * 添加ssh列表
  79. */
  80. function addSSHList() {
  81. if (document.querySelector('.XIU2-GCS')) return;
  82. let html = document.querySelector('[role="tabpanel"]:nth-child(3) div.input-group');
  83. if (!html) return;
  84. let href_split = html.getElementsByTagName('input')[0].getAttribute('value').split(':');
  85. let _html = '';
  86. for (let i = 0; i < sshUrl.length; i++) {
  87. _html +=
  88. ` <div class= "input-group XIU2-GCS" style = "margin-top: 4px;" title = "加速源: ${sshUrl[i][1]} (点击可直接复制)"> ` +
  89. ` <input value = "${sshUrl[i][0] + ':' + href_split[1]}" aria - label = "${sshUrl[i][0] + ':' + href_split[1]}" title = "${sshUrl[i][2]}" type = "text" class = "form-control input-monospace input-sm color-bg-subtle" data - autoselect = "" readonly = ""> ` +
  90. ` <div class = "input-group-button" > ` +
  91. ` <clipboard - copy value = "${sshUrl[i][0] + ':' + href_split[1]}" aria - label = "Copy to clipboard" class = "btn btn-sm js-clipboard-copy tooltipped-no-delay ClipboardButton" tabindex = "0" role = "button"> ` +
  92. `${svg[1]}` +
  93. ` </clipboard-copy>` +
  94. `</div>` +
  95. `</div>`;
  96. }
  97. html.insertAdjacentHTML('afterend', _html);
  98. }
  99.  
  100. /**
  101. * 添加download zip
  102. */
  103. function addDownloadZip() {
  104. if (document.querySelector('.XIU2-DZ')) return;
  105. let html = document.querySelectorAll('.Box-row.Box-row--hover-gray.p-3.mt-0')[1];
  106. if (!html) return;
  107. let href = html.getElementsByTagName('a')[0].href;
  108. let url = '';
  109. let _html = '';
  110.  
  111. for (let i = 0; i < downloadUrl.length; i++) {
  112. url = downloadUrl[i][0] + href.split(location.host)[1];
  113. _html +=
  114. `<li class = "Box-row Box-row--hover-gray p-3 mt-0" > ` +
  115. `<a class = "d-flex flex-items-center color-fg-default text-bold no-underline" rel = "nofollow" data - open - app = "link" href = "${url}" title = "${downloadUrl[i][2]}" > ` +
  116. `<svg aria - hidden = "true" height = "16" viewBox = "0 0 16 16" version = "1.1" width = "16" data - view - component = "true" class = "octicon octicon-file-zip mr-2" > ` +
  117. ` <path fill - rule = "evenodd" d = "M3.5 1.75a.25.25 0 01.25-.25h3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h2.086a.25.25 0 01.177.073l2.914 2.914a.25.25 0 01.073.177v8.586a.25.25 0 01-.25.25h-.5a.75.75 0 000 1.5h.5A1.75 1.75 0 0014 13.25V4.664c0-.464-.184-.909-.513-1.237L10.573.513A1.75 1.75 0 009.336 0H3.75A1.75 1.75 0 002 1.75v11.5c0 .649.353 1.214.874 1.515a.75.75 0 10.752-1.298.25.25 0 01-.126-.217V1.75zM8.75 3a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM6 5.25a.75.75 0 01.75-.75h.5a.75.75 0 010 1.5h-.5A.75.75 0 016 5.25zm2 1.5A.75.75 0 018.75 6h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 6.75zm-1.25.75a.75.75 0 000 1.5h.5a.75.75 0 000-1.5h-.5zM8 9.75A.75.75 0 018.75 9h.5a.75.75 0 010 1.5h-.5A.75.75 0 018 9.75zm-.75.75a1.75 1.75 0 00-1.75 1.75v3c0 .414.336.75.75.75h2.5a.75.75 0 00.75-.75v-3a1.75 1.75 0 00-1.75-1.75h-.5zM7 12.25a.25.25 0 01.25-.25h.5a.25.25 0 01.25.25v2.25H7v-2.25z"> </path>` +
  118. `</svg>` +
  119. `Download` +
  120. `ZIP ${downloadUrl[i][1]}` +
  121. `</a>` +
  122. `</li>`;
  123. }
  124. html.insertAdjacentHTML('afterend', _html);
  125. }
  126.  
  127. /**
  128. * 添加Releases列表
  129. */
  130. function addReleasesList() {
  131. let html = document.querySelectorAll('.Box-footer');
  132. let divDisplay = 'margin-left: -90px;';
  133. if (document.documentElement.clientWidth > 755) {
  134. divDisplay = 'margin-top: -3px; margin-left: 15px; display: inherit;';
  135. }
  136.  
  137. for (const current of html) {
  138. if (current.querySelector('.XIU2-RS')) continue;
  139. current.querySelectorAll('li.Box-row a').forEach(function (_this) {
  140. let href = _this.href.split(location.host);
  141. let url = '';
  142. let _html = `<div class = "XIU2-RS" style = "${divDisplay}"></div>`;
  143. for (let i = 0; i < downloadUrl.length; i++) {
  144. url = downloadUrl[i][0] + href[1];
  145. if (location.host !== "github.com") url = url.replace(location.host, "github.com");
  146. _html +=
  147. `<a style="${style[0]}" class="btn" href="${url}" title="${downloadUrl[i][2]}" rel="noreferrer noopener nofollow">${downloadUrl[i][1]}</a>`;
  148. }
  149. _this.parentElement.nextElementSibling.insertAdjacentHTML('beforeend', _html + '</div>');
  150. }
  151. );
  152. }
  153. }
  154.  
  155. /**
  156. * 添加Tags列表
  157. */
  158. function addTagsList() {
  159. let html = document.querySelectorAll('.Box-row.position-relative.d-flex')
  160. let divDisplay = 'margin-left: -90px;';
  161. if (document.documentElement.clientWidth > 755) {
  162. divDisplay = 'margin-top: -3px; margin-left: 15px; display: inherit;';
  163. }
  164.  
  165. for (const current of html) {
  166. let k = 0;
  167. if (current.querySelector('.XIU2-TS')) return;
  168. current.querySelectorAll('li.d-inline-block.mt-1.mr-2 a[rel="nofollow"]').forEach(function (_this) {
  169. let href = _this.href.split(location.host);
  170. let url = '';
  171. let _html = `<div class="XIU2-TS" style="${divDisplay}"></div>`;
  172. for (let i = 0; i < downloadUrl.length; i++) {
  173. url = downloadUrl[i][0] + href[1];
  174. if (location.host !== "github.com") url = url.replace(location.host, "github.com");
  175. _html +=
  176. `<a style="${style[0]}" class="btn" href="${url}" title="${downloadUrl[i][2]}" rel="noreferrer noopener nofollow">${downloadUrl[i][1]}</a>`;
  177. }
  178. if (k == 0) {
  179. _this.parentElement.nextElementSibling.insertAdjacentHTML('afterbegin', _html + '</div>');
  180. k++;
  181. } else {
  182. _this.parentElement.insertAdjacentHTML('beforeend', _html, '</div>')
  183. }
  184.  
  185. });
  186. }
  187. }
  188.  
  189. function run() {
  190. addCloneList();
  191. addSSHList();
  192. addDownloadZip();
  193. if (location.pathname.split("/")[3] === "releases") {
  194. addReleasesList();
  195. }
  196. if (location.pathname.split("/")[3] === "tags") {
  197. addTagsList();
  198. }
  199.  
  200. if (window.onurlchange === undefined) {
  201. addUrlChangeEvent();
  202. }
  203. window.addEventListener('urlchange', function () {
  204. addCloneList();
  205. addSSHList();
  206. addDownloadZip();
  207. if (location.pathname.split("/")[3] === "releases") {
  208. addReleasesList();
  209. }
  210. if (location.pathname.split("/")[3] === "tags") {
  211. addTagsList();
  212. }
  213. });
  214.  
  215. const callback = (mutationsList) => {
  216. if (location.pathname.indexOf('/releases') === -1) return;
  217. for (const mutation of mutationsList) {
  218. for (const target of mutation.addedNodes) {
  219. if (target.nodeType !== 1) return;
  220. if (target.tagName === 'DIV' && target.dataset.viewComponent === 'true' && target.classList[0] === 'Box') {
  221. addReleasesList();
  222. }
  223. }
  224. }
  225. };
  226. const observe = new MutationObserver(callback);
  227. const options = {
  228. childList: true,
  229. subtree: true
  230. };
  231. observe.observe(document, options);
  232. }
  233.  
  234. run();
  235.  
  236. /**
  237. * 添加url地址改变事件
  238. */
  239. function addUrlChangeEvent() {
  240. history.pushState = (f => function pushState() {
  241. let ret = f.apply(this, arguments);
  242. window.dispatchEvent(new Event('pushstate'));
  243. window.dispatchEvent(new Event('urlchange'));
  244. return ret;
  245. })(history.pushState);
  246.  
  247. history.replaceState = (f => function replaceState() {
  248. let ret = f.apply(this, arguments);
  249. window.dispatchEvent(new Event('replacestate'));
  250. window.dispatchEvent(new Event('urlchange'));
  251. return ret;
  252. })(history.replaceState);
  253.  
  254. window.addEventListener('popstate', () => {
  255. window.dispatchEvent(new Event('urlchange'));
  256. });
  257. }
  258. })();