// ==UserScript==
// @name GitHub加速下载
// @namespace https://github.com/laboratorys/github-fast
// @version 1.0.0
// @author Libs
// @description 可自定义配置的GitHub加速下载脚本
// @license MIT License
// @icon https://github.githubassets.com/favicon.ico
// @include *://github.com/*
// @include *://github*
// @require https://scriptcat.org/lib/513/2.0.1/ElementGetter.js#sha256=V0EUYIfbOrr63nT8+W7BP1xEmWcumTLWu2PXFJHh5dg=
// @require data:application/javascript,window.elmGetter%3DelmGetter
// @require https://registry.npmmirror.com/vue/3.5.13/files/dist/vue.global.prod.js
// @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require https://registry.npmmirror.com/jquery/3.7.1/files
// @require https://unpkg.com/[email protected]/dist/index.prod.js
// @require https://registry.npmmirror.com/pinia/2.3.0/files/dist/pinia.iife.prod.js
// @grant GM.notification
// @grant GM.registerMenuCommand
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
(function (vue, pinia$1, naiveUi, $) {
"use strict";
const useStore = pinia$1.defineStore("main", {
state: () => ({
showConfig: false,
}),
});
const _hoisted_1 = { class: "centered-content" };
const _hoisted_2 = {
style: { display: "flex", "align-items": "center", width: "100%" },
};
const _sfc_main$1 = {
__name: "GitHub",
setup(__props) {
const store = useStore();
const proxyUrlList = vue.ref([]);
const projectFileDownloadUrl = vue.ref(null);
const bypassDownload = vue.ref(false);
const clone = vue.ref(true);
const depth = vue.ref(false);
const projectFileUrlList = vue.computed(() => {
var hasVal = false;
proxyUrlList.value.find(function (value) {
if (value.url == projectFileDownloadUrl.value && value.isCheck) {
hasVal = true;
}
});
if (!hasVal) {
projectFileDownloadUrl.value = null;
}
return proxyUrlList.value.map((u) => ({
label: u.url,
value: u.url,
disabled: !u.isCheck,
}));
});
const onCreate = () => {
return {
isCheck: true,
name: "",
url: "",
};
};
const handleUpdateCloneValue = (value) => {
if (!value) {
depth.value = false;
}
};
const handleUpdateDepthValue = (value) => {
if (value) {
clone.value = true;
}
};
const saveConfig = () => {
GM_setValue("githubFastConfig", {
projectFileDownloadUrl: projectFileDownloadUrl.value,
proxyUrlList: proxyUrlList.value,
bypassDownload: bypassDownload.value,
clone: clone.value,
depth: depth.value,
});
GM.notification("配置更新成功,请刷新页面!");
};
const initData = () => {
const config = GM_getValue("githubFastConfig");
if (config) {
projectFileDownloadUrl.value = config.projectFileDownloadUrl;
proxyUrlList.value = config.proxyUrlList;
bypassDownload.value = config.bypassDownload;
clone.value = config.clone;
depth.value = config.depth;
}
};
initData();
return (_ctx, _cache) => {
return (
vue.openBlock(),
vue.createBlock(
vue.unref(naiveUi.NDrawer),
{
show: vue.unref(store).showConfig,
"onUpdate:show":
_cache[6] ||
(_cache[6] = ($event) =>
(vue.unref(store).showConfig = $event)),
width: 502,
},
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NDrawerContent),
{
title: "GitHub加速配置",
closable: "",
},
{
default: vue.withCtx(() => [
vue.createElementVNode("div", _hoisted_1, [
vue.createVNode(
vue.unref(naiveUi.NForm),
{
"label-placement": "left",
"label-width": "auto",
},
{
default: vue.withCtx(() => [
vue.createVNode(vue.unref(naiveUi.NH3), null, {
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NText),
{ type: "primary" },
{
default: vue.withCtx(
() =>
_cache[7] ||
(_cache[7] = [
vue.createTextVNode(" 负载均衡 "),
])
),
_: 1,
}
),
]),
_: 1,
}),
vue.createVNode(
vue.unref(naiveUi.NFormItem),
null,
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NSwitch),
{
value: bypassDownload.value,
"onUpdate:value":
_cache[0] ||
(_cache[0] = ($event) =>
(bypassDownload.value = $event)),
size: "large",
round: false,
},
{
checked: vue.withCtx(
() =>
_cache[8] ||
(_cache[8] = [
vue.createTextVNode(" 开启 "),
])
),
unchecked: vue.withCtx(
() =>
_cache[9] ||
(_cache[9] = [
vue.createTextVNode(" 关闭 "),
])
),
_: 1,
},
8,
["value"]
),
]),
_: 1,
}
),
vue.createVNode(vue.unref(naiveUi.NH3), null, {
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NText),
{ type: "primary" },
{
default: vue.withCtx(
() =>
_cache[10] ||
(_cache[10] = [
vue.createTextVNode(" 克隆 "),
])
),
_: 1,
}
),
]),
_: 1,
}),
vue.createVNode(
vue.unref(naiveUi.NFormItem),
null,
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NSpace),
{ "item-style": "display: flex;" },
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NCheckbox),
{
size: "large",
checked: clone.value,
"onUpdate:checked": [
_cache[1] ||
(_cache[1] = ($event) =>
(clone.value = $event)),
handleUpdateCloneValue,
],
label: "git clone",
},
null,
8,
["checked"]
),
vue.createVNode(
vue.unref(naiveUi.NCheckbox),
{
size: "large",
checked: depth.value,
"onUpdate:checked": [
_cache[2] ||
(_cache[2] = ($event) =>
(depth.value = $event)),
handleUpdateDepthValue,
],
label: "--depth=1",
},
null,
8,
["checked"]
),
]),
_: 1,
}
),
]),
_: 1,
}
),
vue.createVNode(vue.unref(naiveUi.NH3), null, {
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NText),
{ type: "primary" },
{
default: vue.withCtx(
() =>
_cache[11] ||
(_cache[11] = [
vue.createTextVNode(
" 列表文件加速 "
),
])
),
_: 1,
}
),
]),
_: 1,
}),
vue.createVNode(
vue.unref(naiveUi.NFormItem),
null,
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NSelect),
{
value: projectFileDownloadUrl.value,
"onUpdate:value":
_cache[3] ||
(_cache[3] = ($event) =>
(projectFileDownloadUrl.value =
$event)),
options: projectFileUrlList.value,
placeholder: "选择加速地址",
},
null,
8,
["value", "options"]
),
]),
_: 1,
}
),
vue.createVNode(vue.unref(naiveUi.NH3), null, {
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NText),
{ type: "primary" },
{
default: vue.withCtx(
() =>
_cache[12] ||
(_cache[12] = [
vue.createTextVNode(" 加速列表 "),
])
),
_: 1,
}
),
]),
_: 1,
}),
vue.createVNode(
vue.unref(naiveUi.NFormItem),
null,
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NDynamicInput),
{
value: proxyUrlList.value,
"onUpdate:value":
_cache[4] ||
(_cache[4] = ($event) =>
(proxyUrlList.value = $event)),
"show-sort-button": "",
"on-create": onCreate,
},
{
"create-button-default": vue.withCtx(
() =>
_cache[13] ||
(_cache[13] = [
vue.createTextVNode(" 添加 "),
])
),
default: vue.withCtx(({ value }) => [
vue.createElementVNode(
"div",
_hoisted_2,
[
vue.createVNode(
vue.unref(naiveUi.NCheckbox),
{
checked: value.isCheck,
"onUpdate:checked": (
$event
) => (value.isCheck = $event),
style: {
"margin-right": "12px",
},
},
null,
8,
["checked", "onUpdate:checked"]
),
vue.createVNode(
vue.unref(naiveUi.NInput),
{
class: "mr-2",
value: value.name,
"onUpdate:value": ($event) =>
(value.name = $event),
type: "text",
placeholder: "名称",
style: { width: "40%" },
},
null,
8,
["value", "onUpdate:value"]
),
vue.createVNode(
vue.unref(naiveUi.NInput),
{
value: value.url,
"onUpdate:value": ($event) =>
(value.url = $event),
type: "text",
placeholder: "加速地址",
},
null,
8,
["value", "onUpdate:value"]
),
]
),
]),
_: 1,
},
8,
["value"]
),
]),
_: 1,
}
),
vue.createVNode(
vue.unref(naiveUi.NSpace),
{ justify: "center" },
{
default: vue.withCtx(() => [
vue.createVNode(
vue.unref(naiveUi.NButton),
{
type: "primary",
size: "medium",
strong: "",
onClick: saveConfig,
},
{
default: vue.withCtx(
() =>
_cache[14] ||
(_cache[14] = [
vue.createTextVNode(" 保存配置 "),
])
),
_: 1,
}
),
vue.createVNode(
vue.unref(naiveUi.NButton),
{
type: "default",
size: "medium",
strong: "",
onClick:
_cache[5] ||
(_cache[5] = ($event) =>
(vue.unref(
store
).showConfig = false)),
},
{
default: vue.withCtx(
() =>
_cache[15] ||
(_cache[15] = [
vue.createTextVNode(" 关闭 "),
])
),
_: 1,
}
),
]),
_: 1,
}
),
]),
_: 1,
}
),
]),
]),
_: 1,
}
),
]),
_: 1,
},
8,
["show"]
)
);
};
},
};
const colorMode = vue.ref(
document.querySelector("html").getAttribute("data-color-mode")
);
const currentTheme = vue.ref(naiveUi.lightTheme);
const updateThemeMode = () => {
currentTheme.value = mql.matches ? naiveUi.darkTheme : naiveUi.lightTheme;
};
const mql = window.matchMedia("(prefers-color-scheme: dark)");
mql.addEventListener("change", updateThemeMode);
const initThemeMode = (mode) => {
if (mode === "dark") {
currentTheme.value = naiveUi.darkTheme;
} else if (mode === "auto") {
updateThemeMode();
} else {
currentTheme.value = naiveUi.lightTheme;
}
};
initThemeMode(colorMode.value);
new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (
mutation.type === "attributes" &&
mutation.attributeName === "data-color-mode"
) {
colorMode.value = document
.querySelector("html")
.getAttribute("data-color-mode");
initThemeMode(colorMode.value);
}
}
}).observe(document.querySelector("html"), { attributes: true });
const _sfc_main = {
__name: "App",
setup(__props) {
return (_ctx, _cache) => {
return (
vue.openBlock(),
vue.createBlock(
vue.unref(naiveUi.NConfigProvider),
{ theme: vue.unref(currentTheme) },
{
default: vue.withCtx(() => [vue.createVNode(_sfc_main$1)]),
_: 1,
},
8,
["theme"]
)
);
};
},
};
function run(elmGetter) {
const config = GM_getValue("githubFastConfig");
const store = useStore();
GM.registerMenuCommand("加速配置", () => {
store.showConfig = true;
});
var MirrorUrl = pollingUrl();
if (MirrorUrl.length == 0) {
return;
}
function setListDownBtn(elmGetter2) {
elmGetter2
.get("table[aria-labelledby='folders-and-files']")
.then((table) => {
$(table)
.find("tr")
.each(function (index, item) {
var rowType = $(item)
.find("td:eq(1)")
.find("div[class='react-directory-filename-column']")
.find("svg")
.attr("class");
if (rowType && rowType === "color-fg-muted") {
addListDownBtn($(item));
}
});
});
}
function setRawBtn() {
if (window.location.pathname.split("/")[3] == "blob") {
addRawBtn();
}
}
function setReleaseBtn() {
if (window.location.pathname.split("/")[3] == "releases") {
addReleaseList($('div[class="Box Box--condensed mt-3"]'));
}
}
setListDownBtn(elmGetter);
setRawBtn();
setReleaseBtn();
function callback(mutations, _observer) {
mutations.forEach((mutation) => {
if (mutation.type == "childList" && mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach((node) => {
try {
if (
node.className != void 0 &&
node.className &&
node.className.includes("react-directory-commit-age")
) {
setListDownBtn(elmGetter);
}
} catch (exceptionVar) {}
});
}
if (
mutation.target &&
mutation.target.tagName === "BUTTON" &&
mutation.target.getAttribute("class").includes("TabNav-item") &&
mutation.target.getAttribute("aria-selected") === "true" &&
$(mutation.target).find("span").find("span").text() === "Local"
) {
$(".fast-zip").remove();
addDownZipList();
if (
isShow($("#clone-with-https")) &&
$("#clone-with-https").length > 0
) {
$(".fast-clone").remove();
addCloneList();
}
}
if (
mutation.target &&
mutation.target.tagName === "DIV" &&
mutation.target.getAttribute("data-view-component") === "true"
) {
setReleaseBtn();
}
if (
mutation.target &&
mutation.target.tagName === "A" &&
mutation.target.getAttribute("data-testid") === "raw-button"
) {
setRawBtn();
}
});
}
function isShow(target) {
if (target.is(":visible")) {
return true;
} else {
return false;
}
}
const observer = new MutationObserver(callback);
observer.observe(document.querySelector("body"), {
attributes: true,
childList: true,
subtree: true,
});
function addCloneList() {
var href = window.location.href.split("/");
var git = href[3] + "/" + href[4] + ".git";
let inputGit = $("#__primerPortalRoot__").find("input").parent();
var InputDivClass = inputGit.attr("class");
inputGit.parent().find("span:last").attr("class");
var info = ` <span class="fast-clone" style="color:palegreen">加速列表</span>`;
MirrorUrl.forEach((u) => {
var Url = u.url + "/https://github.com/" + git;
if (config && config.clone) {
if (config.depth) {
Url = "git clone --depth=1 " + Url;
} else {
Url = "git clone " + Url;
}
}
info += cloneHtml(InputDivClass, Url);
});
function cloneHtml(InputDivClass2, Url) {
return `
<div class="${InputDivClass2} fast-clone mr-2">
<input
type="text"
class="form-control input-monospace input-sm color-bg-subtle"
data-autoselect="true"
aria-label="${Url}"
readonly=""
value="${Url}"
tabindex="0"
style="flex-grow: 1" />
<clipboard-copy
value="${Url}"
aria-label="Copy url to clipboard"
class="ml-1 mr-0 js-clipboard-copy tooltipped-no-delay"
data-copy-feedback="Copied!"
data-tooltip-direction="n"
role="button"
><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
d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path>
<path
d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></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
d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
</clipboard-copy>
</div>
`;
}
$("#__primerPortalRoot__")
.find("input")
.parent()
.parent()
.find("p")
.filter(function () {
if (!$(this).attr("class")) {
return false;
}
return $(this).attr("class").includes("text-normal");
})
.before($(info));
}
function addDownZipList() {
MirrorUrl.forEach((u) => {
let downZipClone = $("#__primerPortalRoot__")
.find("ul:last")
.find("li:eq(1)")
.clone();
downZipClone.addClass("fast-zip");
var zipPath = downZipClone.find("a").attr("href");
var Url = u.url + "/https://github.com/" + zipPath;
var zipText = u.name;
downZipClone.find("a").attr("href", Url);
downZipClone.find("span:last").text(`Fast Download Zip [${zipText}]`);
$("#__primerPortalRoot__").find("ul:last").append(downZipClone);
});
}
function addReleaseList(target) {
target.find(".fast-release").remove();
let releaseLi = target.find("ul").find("li");
releaseLi.each(function () {
var releasePath = $(this).find("a:eq(0)").attr("href");
var urls = new Array();
MirrorUrl.forEach((u) => {
var Url = u.url + "/https://github.com" + releasePath;
urls.push(Url);
});
$(this).append(releaseHtml(urls));
});
function releaseHtml(urls) {
var aHtml = "";
urls.forEach((u, index) => {
var title = "下载";
if (urls.length > 1) {
title = MirrorUrl[index].name;
}
aHtml += `<a
href="${u}"
rel="nofollow"
data-turbo="false"
data-view-component="true"
class="Truncate ml-1">
<span data-view-component="true" class="Truncate-text text-bold">${title}</span>
</a>`;
});
return `
<div data-view-component="true" class="d-flex ml-md-3 fast-release">
<svg
t="1668210029451"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2795"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16">
<path
d="M508.746667 299.2L485.333333 452.373333a5.333333 5.333333 0 0 0 4 5.973334l217.386667 53.333333a5.333333 5.333333 0 0 1 2.72 8.693333l-184.906667 208.8a5.333333 5.333333 0 0 1-9.28-4.32l23.413334-153.226666a5.333333 5.333333 0 0 0-4-5.973334L317.173333 512a5.333333 5.333333 0 0 1-2.506666-8.48l184.8-208.693333a5.333333 5.333333 0 0 1 9.28 4.373333z m-329.493334 256l271.253334 66.666667a5.333333 5.333333 0 0 1 4 5.973333l-51.04 335.68a5.333333 5.333333 0 0 0 9.226666 4.32l434.773334-490.346667a5.333333 5.333333 0 0 0-2.72-8.693333l-271.253334-66.666667a5.333333 5.333333 0 0 1-4-5.973333l51.04-335.626667a5.333333 5.333333 0 0 0-9.226666-4.373333L176.533333 546.506667a5.333333 5.333333 0 0 0 2.72 8.693333z"
p-id="2796"
fill="#57606a"></path>
</svg>
${aHtml}
</div>
`;
}
}
function addRawBtn() {
var rawUrl = $('a[data-testid="raw-button"]').attr("href");
if (rawUrl != void 0) {
$(".fast-raw").remove();
MirrorUrl.forEach((u, index) => {
var url = u.url + "/" + rawUrl;
var rawCloneBtn = $('a[data-testid="raw-button"]').first().clone();
rawCloneBtn.addClass("fast-raw");
rawCloneBtn.text(u.name);
rawCloneBtn.attr("href", url);
$('a[data-testid="raw-button"]').eq(index).after(rawCloneBtn);
});
}
}
function addListDownBtn(target) {
target.find(".fileDownLink").remove();
var dLink = target.find('a[class="Link--primary"]').attr("href");
target
.find('div[class="react-directory-filename-column"]')
.find("svg:first")
.after(
listDownHtml(
(config && config.projectFileDownloadUrl
? config.projectFileDownloadUrl
: MirrorUrl[0].url) +
"/https://github.com" +
dLink,
"main.go"
)
);
function listDownHtml(Url, Name) {
return `<a href="${Url}" download="${Name}" target="_blank" rel="noreferrer noopener nofollow" class="fileDownLink" title="${Url}" style='display:none'><svg
t="1668210029451"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2795"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16">
<path
d="M508.746667 299.2L485.333333 452.373333a5.333333 5.333333 0 0 0 4 5.973334l217.386667 53.333333a5.333333 5.333333 0 0 1 2.72 8.693333l-184.906667 208.8a5.333333 5.333333 0 0 1-9.28-4.32l23.413334-153.226666a5.333333 5.333333 0 0 0-4-5.973334L317.173333 512a5.333333 5.333333 0 0 1-2.506666-8.48l184.8-208.693333a5.333333 5.333333 0 0 1 9.28 4.373333z m-329.493334 256l271.253334 66.666667a5.333333 5.333333 0 0 1 4 5.973333l-51.04 335.68a5.333333 5.333333 0 0 0 9.226666 4.32l434.773334-490.346667a5.333333 5.333333 0 0 0-2.72-8.693333l-271.253334-66.666667a5.333333 5.333333 0 0 1-4-5.973333l51.04-335.626667a5.333333 5.333333 0 0 0-9.226666-4.373333L176.533333 546.506667a5.333333 5.333333 0 0 0 2.72 8.693333z"
p-id="2796"
fill="#57606a"></path>
</svg></a>`;
}
target
.find('div[class="react-directory-filename-column"]')
.find("svg:first")
.hover(
function () {
$(this).css("display", "none");
$(this).parent().find(".fileDownLink").css("display", "inline");
},
function () {
$(this).css("display", "inline");
$(this).parent().find(".fileDownLink").css("display", "none");
}
);
target.find(".fileDownLink").hover(
function () {
$(this).css("display", "inline");
$(this).parent().find("svg:first").css("display", "none");
},
function () {
$(this).css("display", "none");
$(this).parent().find("svg:first").css("display", "inline");
}
);
}
function pollingUrl() {
var proxyUrl = config ? config.proxyUrlList : new Array();
if (config && config.bypassDownload && proxyUrl.length > 0) {
var index = GM_getValue("MirrorUrlIndex");
if (
index != null &&
index != void 0 &&
index + 1 <= proxyUrl.length - 1
) {
index = index + 1;
} else {
index = 0;
}
var newUrlArr = new Array();
newUrlArr[0] = proxyUrl[index];
GM_setValue("MirrorUrlIndex", index);
return newUrlArr;
}
return proxyUrl;
}
}
var _monkeyWindow = /* @__PURE__ */ (() => window)();
const pinia = pinia$1.createPinia();
const app = vue.createApp(_sfc_main);
app.use(pinia);
app.mount(
(() => {
const app2 = document.createElement("div");
document.body.append(app2);
run(_monkeyWindow.elmGetter);
return app2;
})()
);
})(Vue, Pinia, naive, jQuery);