-
Notifications
You must be signed in to change notification settings - Fork 0
/
gh-proxy.user.js
398 lines (372 loc) · 15.7 KB
/
gh-proxy.user.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
// ==UserScript==
// @name GitHub 访问代理助手
// @namespace lzwme.github.fast
// @author renxia (https://lzw.me)
// @homepageURL https://github.com/lzwme/vm-gh-proxy-cn
// @supportURL https://github.com/lzwme/vm-gh-proxy-cn/issues
// @updateURL https://mirror.ghproxy.com/github.com/lzwme/vm-gh-proxy-cn/blob/main/gh-proxy.user.js
// @downloadURL https://mirror.ghproxy.com/github.com/lzwme/vm-gh-proxy-cn/blob/main/gh-proxy.user.js
// @license MIT License
// @description GitHub 访问加速助手。支持 GitHub 的 clone、release/raw/zip 下载加速
// @include *://github.com/*
// @include *://github*
// @include *://hub.fastgit.xyz/*
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.slim.min.js
// @icon https://github.githubassets.com/favicon.ico
// @version 1.1.2
// @update 2024.05.23
// ==/UserScript==
(function () {
const clonePrefix = 'git clone --depth 1 ';
const Mirrors = {
ghproxynet: {
url: 'https://ghproxy.net/github.com',
name: 'gh-net',
desc: 'ghproxy.net 代理',
types: ['clone', 'download', 'raw'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
ghproxy: {
url: 'https://mirror.ghproxy.com/github.com',
name: 'ghproxy',
desc: 'ghproxy 代理',
types: ['clone', 'download', 'raw'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
ghpscc: {
url: 'https://ghps.cc/github.com',
name: 'ghproxy',
desc: '基于 gh-proxy 的代理',
types: ['clone', 'download', 'raw'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
ddlctop: {
url: 'https://gh.ddlc.top/github.com',
name: 'ghproxy',
desc: '基于 gh-proxy 的代理',
types: ['clone', 'download', 'raw'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
ghproxy1: {
url: 'https://gh.api.99988866.xyz/github.com',
name: 'gh-xyz',
desc: 'ghproxy 代理(演示站)',
types: ['clone', 'download', 'raw'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
xyz201704: {
url: 'https://scoop.201704.xyz/github.com',
name: '201704.xyz',
desc: '开源的 scoop 国内镜像方案',
types: ['raw', 'download'],
format(url) {
return `${this.url}/${url.replace(/^(https:\/\/github.com)?\//, '')}`;
},
},
gitclone: {
"url": "https://gitclone.com/github.com",
"name": "gitclone加速",
"desc": "gitclone加速",
types: ['clone'],
},
jsDelivr: {
"url": "https://cdn.jsdelivr.net/gh",
"name": "jsDelivr",
"desc": "项目当前分支总文件大小不可超过 50MB",
types: ['raw'], // download
},
staticaly: {
"url": "https://cdn.staticaly.com/gh",
"name": "Statically",
"desc": "只能浏览图片和源代码文件,文件大小限制为30MB",
types: ['raw'],
},
gitmirror: {
name: 'gitmirror',
url: 'https://hub.gitmirror.com',
home: 'https://www.7ed.net/gitmirror/hub.html',
desc: '加速下载 Github Release、Archive 等文件',
types: ['download', 'raw'],
},
fastgitSsh: {
"url": "git@ssh.fastgit.org",
"name": "FastGit",
"desc": "fastgit ssh",
types: ['clone'],
},
// fastgitSsh: {
// "url": "https://raw.fastgit.org",
// "name": "FastGit-raw",
// "desc": "fastgit raw",
// types: ['raw'],
// },
zhlh6: {
"url": "git@git.zhlh6.cn",
"name": "加速你的Github",
"desc": "利用ucloud提供的GlobalSSH",
types: ['clone'],
},
netnr: {
"url": "https://cors.zme.ink/https://github.com",
"name": "netnr",
"desc": "由@netnr提供",
types: ['mirror', 'download'], // 'raw'
},
// fastgitdl: {
// url: 'https://download.fastgit.org', // todo: only release files、zip
// name: 'fastgit-dl',
// desc: 'fastgit download',
// types: ['download'],
// },
// wuyanzheshui: {
// url: 'https://github.wuyanzheshui.workers.dev',
// name: 'CF加速 1',
// desc: '【CF加速】每日10万次调用上限,由 wuyanzheshui 提供',
// types: ['mirror', 'clone', 'download'],
// },
// rc1844: {
// "url": "https://github.rc1844.workers.dev",
// "name": "CF加速 2",
// "desc": "【CF加速】每日10万次调用上限,由 @rc1844 提供",
// types: ['clone', 'download', 'raw'],
// },
// lzwme: {
// "url": "https://gh.lzwme.workers.dev",
// "name": "CF加速 2",
// "desc": "【CF加速】每日10万次调用上限,由 @renxia 提供",
// types: ['clone', 'download', 'raw', 'mirror'],
// },
// gitclone: {
// "url": "https://gitclone.com/github.com",
// "name": "GitClone",
// "desc": "GitHub clone 缓存加速网站",
// types: ['clone'],
// },
};
const OtherUrl = [
["https://github.com/lzwme/vm-gh-proxy-cn", "脚本Github仓库地址,点个赞谢谢"],
["https://greasyfork.org/zh-CN/scripts/461115", "GreasyFork 地址,请评分收藏"],
["https://doc.fastgit.org/", "FastGit,请仔细甄别"],
["https://d.serctl.com", "GitHub中转下载"],
["https://gitee.com/organizations/mirrors/projects", "Gitee 极速下载"],
["https://lzw.me/tools/", '忒有趣工具箱']
];
const MirrorsList = Object.values(Mirrors);
MirrorsList.forEach(item => {
if (!item.format) {
item.format = (href, type) => {
if (type === 'download') {
if (['gitmirror'].includes(item.name)) {
if (href.startsWith('/')) href = `github.com${href}`;
}
}
if (type === 'raw' && ['Statically', 'jsDelivr', 'gh-xyz'].includes(item.name)) {
return item.url + href.replace(`${repo}/raw/`, `${repo}@`).replace('https://github.com', '');
}
const sep = item.url.includes('@') ? ':' : '/';
if (item.url.includes('github.com')) return `${item.url}${sep}${href.replace(/^(https:\/\/github.com)?\//, '')}`;
return `${item.url}${sep}${href.replace(/^\//, '')}`;
};
}
if (!item.types) item.types = ['raw'];
if (!item.name) item.name = item.url.split('.')[1];
if (!item.desc) item.desc = item.name;
});
const CloneSet = MirrorsList.filter(d => d.types.includes('clone'));
const MirrorSet = MirrorsList.filter(d => d.types.includes('mirror'));
const DownloadSet = MirrorsList.filter(d => d.types.includes('download'));
const RawSet = MirrorsList.filter(d => d.types.includes('raw'));
const isPC = !/Android|iPhone|iPad|iPod|Windows Phone|SymbianOS/i.test(navigator.userAgent);
const observer = new MutationObserver(() => setTimeout(run, 1500));
observer.observe(document.querySelector('head'), { attributes: true, childList: true });
let pathname = '';
let repo = '';
function run() {
if (location.pathname != pathname) {
pathname = location.pathname;
repo = location.href.match(/github.com\/([^\/]+\/[^\/]+)\/?/)?.[1];
addMenus();
addRawList();
if (location.pathname.split("/")[3] == "releases") addReleasesList();
if (isPC) addDownloadZip();
}
}
run();
initProxyButton();
initEvents();
/**
* 添加Raw列表
*/
function addRawList() {
let rawUrl = $("#raw-url");
if (!rawUrl.length) rawUrl = $(`a[data-testid="raw-button"]:last`);
const rawHref = rawUrl.attr('href');
if (!rawHref) return;
$('.raw-btn-proxy').remove();
RawSet.forEach((item) => {
const span = rawUrl.clone().removeAttr('id');
span.attr({
href: item.format(rawHref, 'raw'),
title: item.desc,
target: "_blank",
});
span.text(item.name).addClass('raw-btn-proxy');
rawUrl.before(span);
});
}
/**
* Fast Download ZIP
*/
function addDownloadZip() {
$("a[data-open-app='link']").each(function () {
const span = $(`<li class="Box-row p-0"></li>`);
const href = $(this).attr("href");
const clone = $(this)
.clone()
.removeAttr("data-hydro-click data-hydro-click-hmac data-ga-click")
.addClass("Box-row Box-row--hover-gray");
DownloadSet.forEach(item => {
const span1 = $(clone.html().replace("Download ZIP", `Download ZIP(${item.name})`)).attr({
href: item.format(href, 'download'),
title: item.desc,
});
span.append(span1);
});
$(this).parent().after(span);
});
}
/**
* 添加Releases列表
*/
function addReleasesList(retry = 3) {
const $alist = $(".Box--condensed").find("[href]");
if (!$alist.length && retry) return setTimeout(() => addReleasesList(--retry), 1000);
$alist.each(function() {
const $el = $(this);
const href = $el.attr('href');
$el.parent()
.after(`<div style="position: absolute; right: 180px; top: 0;">${
DownloadSet.map((item) => {
return `<a class="flex-1 btn btn-outline get-repo-btn BtnGroup-item" style="float: none; border-color: var(--color-btn-outline-text)"
href="${item.format(href, 'download')}" title="${item.desc}">${item.name}</a>`;
}).join('')
}</div>`);
$el.parent().parent().css({ position: 'relative' });
});
}
/**
* 添加菜单列表
*/
function addMenus() {
if (!repo) return;
const repoGit = `${repo}.git`;
const info = `<details class="details-reset details-overlay mr-0 mb-0" id="mirror-menu">
<summary class="btn ml-2 btn-primary" data-hotkey="m" title="打开列表" aria-haspopup="menu" role="button">
<span class="css-truncate-target" data-menu-button="">克隆与镜像</span>
<span class="dropdown-caret"></span>
</summary>
<details-menu class="SelectMenu SelectMenu--hasFilter" role="menu">
<div class="SelectMenu-modal" style="width: 400px;">
<header class="SelectMenu-header">
<span class="SelectMenu-title">镜像站点与快速克隆</span>
<button class="SelectMenu-closeButton" type="button" data-toggle-for="mirror-menu"><svg aria-label="Close menu"
class="octicon octicon-x" width="16" height="16" role="img">
<path fill-rule="evenodd"
d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z">
</path>
</svg></button>
</header>
<tab-container class="d-flex flex-column js-branches-tags-tabs" style="min-height: 0;">
<div class="SelectMenu-tabs" role="tablist">
<button class="SelectMenu-tab" type="button" role="tab"
aria-selected="true" tabindex="0">主要</button>
<button class="SelectMenu-tab" type="button" role="tab"
aria-selected="false" tabindex="-1">其他</button>
</div>
<div role="tabpanel" class="flex-column flex-auto overflow-auto" tabindex="0">
<div class="SelectMenu-list" data-filter-list="">
<div class="btn-block" style="padding: 4px;background-color: #ffffdd;color: #996600;" role="alert">clone、depth命令的插入可手动编辑代码关闭</div>
<div class="btn-block flash-error" style="padding: 4px;color: #990000;" role="alert">请不要在镜像网站登录账号,若因此造成任何损失本人概不负责</div> ${
CloneSet.map((item) => cloneHtml(`${clonePrefix}${item.format(repoGit, 'clone')}`, item.name)).join('')
}${
cloneHtml("git remote set-url origin https://github.com/" + repoGit, "还原GitHub仓库地址")
} ${
addBrowseList()
}</div>
</div>
<div role="tabpanel" class="flex-column flex-auto overflow-auto" tabindex="0" hidden="">
<div class="SelectMenu-list">${
OtherUrl.map((d) => listHtml(d[0], d[1])).join('')
}</div>
</div>
</tab-container>
</div>
</details-menu>
</details>`;
$('#mirror-menu').remove(); // remove old
$(".pagehead-actions").before(info);
function cloneHtml(Url, Tip) {
return `<div class="input-group notranslate" title="${Tip}">
<input type="text" class="form-control input-monospace input-sm" value="${Url}" readonly=""
data-autoselect="">
<div class="input-group-button">
<clipboard-copy value="${Url}" class="btn btn-sm"><svg class="octicon octicon-clippy"
viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true">
<path fill-rule="evenodd"
d="M5.75 1a.75.75 0 00-.75.75v3c0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75v-3a.75.75 0 00-.75-.75h-4.5zm.75 3V2.5h3V4h-3zm-2.874-.467a.75.75 0 00-.752-1.298A1.75 1.75 0 002 3.75v9.5c0 .966.784 1.75 1.75 1.75h8.5A1.75 1.75 0 0014 13.25v-9.5a1.75 1.75 0 00-.874-1.515.75.75 0 10-.752 1.298.25.25 0 01.126.217v9.5a.25.25 0 01-.25.25h-8.5a.25.25 0 01-.25-.25v-9.5a.25.25 0 01.126-.217z">
</path>
</svg></clipboard-copy>
</div>
</div>`;
}
}
/**
* 添加镜像浏览列表
*/
function addBrowseList() {
const path = window.location.pathname;
const info = MirrorSet.map(item => listHtml(item.format(path, 'mirror'), `镜像浏览(${item.name})`, item.desc));
if (location.hostname != "github.com") info.push(listHtml(`https://github.com${path}`, "返回GitHub"));
return info.join('');
}
function initProxyButton() {
$('#js-repo-pjax-container').off('mouseenter', 'a').on('mouseenter', 'a', function(ev) {
const $el = $(this);
if ($el.attr('id') === 'gh-proxy-btn') return;
const preBtn = $('#gh-proxy-btn');
const href =$el.attr('href').replace(/^https:\/\/github\.com/, '');
const proxyHref = `${Mirrors.ghproxy.url}${href}`;
if (!/\/(blob|release|archive)\//.test(href) || href.startsWith('http') || preBtn.attr('href') === proxyHref) return;
$('#gh-proxy-btn').remove();
const $btn = $(`<a class="btn" href="${proxyHref}" target="_blank" title="proxy link" id="gh-proxy-btn">🚀</a>`);
$el.parent().append($btn).css({ position: 'relative', overflow: 'visible' });
$btn.css({ position: 'absolute', left: 120, top: 2 });
$btn.on('mouseleave', () => $btn.remove());
});
}
function initEvents() {
$(document).on('click', 'a', function(ev) {
const $el = $(this);
const href = $el.attr('href');
if (['cors.zme.ink'].includes(location.host) && href.startsWith('/')) {
ev.preventDefault();
const hrefFixed = `${location.origin}/https://github.com${href}`;
$el.attr('target') === '_blank' ? window.open(hrefFixed) : location.href = hrefFixed;
}
});
}
function listHtml(url, name, desc = "") {
return `<a class="SelectMenu-item" href="${url}" target="_blank" title="${desc}" role="menuitemradio" aria-checked="false" rel="nofollow">
<span class="css-truncate css-truncate-overflow" style="text-align:center;">${name}</span></a>`;
}
})();