Expanded download acceleration support to over 20 platforms including npm, PyPI, Maven, RubyGems, CRAN, SourceForge, arXiv, F-Droid, and more. Refactored platform configuration into a dedicated file, updated content/background scripts for broader detection and redirection, and redesigned the popup UI for categorized platform toggles. Updated manifest, package metadata, and documentation to reflect the new capabilities and version 2.0.0.
321 lines
7.7 KiB
JavaScript
321 lines
7.7 KiB
JavaScript
// 平台配置
|
|
const PLATFORMS = {
|
|
// 代码托管平台
|
|
gh: {
|
|
base: "https://github.com",
|
|
name: "GitHub",
|
|
pattern: /^https:\/\/github\.com\//,
|
|
},
|
|
gl: {
|
|
base: "https://gitlab.com",
|
|
name: "GitLab",
|
|
pattern: /^https:\/\/gitlab\.com\//,
|
|
},
|
|
gitea: {
|
|
base: "https://gitea.com",
|
|
name: "Gitea",
|
|
pattern: /^https:\/\/gitea\.com\//,
|
|
},
|
|
codeberg: {
|
|
base: "https://codeberg.org",
|
|
name: "Codeberg",
|
|
pattern: /^https:\/\/codeberg\.org\//,
|
|
},
|
|
sf: {
|
|
base: "https://sourceforge.net",
|
|
name: "SourceForge",
|
|
pattern: /^https:\/\/sourceforge\.net\//,
|
|
},
|
|
aosp: {
|
|
base: "https://android.googlesource.com",
|
|
name: "AOSP",
|
|
pattern: /^https:\/\/android\.googlesource\.com\//,
|
|
},
|
|
|
|
// AI/ML 平台
|
|
hf: {
|
|
base: "https://huggingface.co",
|
|
name: "Hugging Face",
|
|
pattern: /^https:\/\/huggingface\.co\//,
|
|
},
|
|
|
|
// 包管理平台
|
|
npm: {
|
|
base: "https://registry.npmjs.org",
|
|
name: "npm",
|
|
pattern: /^https:\/\/registry\.npmjs\.org\//,
|
|
},
|
|
pypi: {
|
|
base: "https://pypi.org",
|
|
name: "PyPI",
|
|
pattern: /^https:\/\/pypi\.org\//,
|
|
},
|
|
"pypi-files": {
|
|
base: "https://files.pythonhosted.org",
|
|
name: "PyPI Files",
|
|
pattern: /^https:\/\/files\.pythonhosted\.org\//,
|
|
},
|
|
conda: {
|
|
base: "https://repo.anaconda.com",
|
|
name: "Conda",
|
|
pattern: /^https:\/\/repo\.anaconda\.com\//,
|
|
},
|
|
"conda-community": {
|
|
base: "https://conda.anaconda.org",
|
|
name: "Conda Community",
|
|
pattern: /^https:\/\/conda\.anaconda\.org\//,
|
|
},
|
|
maven: {
|
|
base: "https://repo1.maven.org",
|
|
name: "Maven",
|
|
pattern: /^https:\/\/repo1\.maven\.org\//,
|
|
},
|
|
apache: {
|
|
base: "https://downloads.apache.org",
|
|
name: "Apache",
|
|
pattern: /^https:\/\/downloads\.apache\.org\//,
|
|
},
|
|
gradle: {
|
|
base: "https://plugins.gradle.org",
|
|
name: "Gradle",
|
|
pattern: /^https:\/\/plugins\.gradle\.org\//,
|
|
},
|
|
rubygems: {
|
|
base: "https://rubygems.org",
|
|
name: "RubyGems",
|
|
pattern: /^https:\/\/rubygems\.org\//,
|
|
},
|
|
cran: {
|
|
base: "https://cran.r-project.org",
|
|
name: "CRAN",
|
|
pattern: /^https:\/\/cran\.r-project\.org\//,
|
|
},
|
|
cpan: {
|
|
base: "https://www.cpan.org",
|
|
name: "CPAN",
|
|
pattern: /^https:\/\/www\.cpan\.org\//,
|
|
},
|
|
ctan: {
|
|
base: "https://tug.ctan.org",
|
|
name: "CTAN",
|
|
pattern: /^https:\/\/tug\.ctan\.org\//,
|
|
},
|
|
golang: {
|
|
base: "https://proxy.golang.org",
|
|
name: "Go Modules",
|
|
pattern: /^https:\/\/proxy\.golang\.org\//,
|
|
},
|
|
nuget: {
|
|
base: "https://api.nuget.org",
|
|
name: "NuGet",
|
|
pattern: /^https:\/\/api\.nuget\.org\//,
|
|
},
|
|
crates: {
|
|
base: "https://crates.io",
|
|
name: "Crates.io",
|
|
pattern: /^https:\/\/crates\.io\//,
|
|
},
|
|
packagist: {
|
|
base: "https://repo.packagist.org",
|
|
name: "Packagist",
|
|
pattern: /^https:\/\/repo\.packagist\.org\//,
|
|
},
|
|
|
|
// 其他平台
|
|
arxiv: {
|
|
base: "https://arxiv.org",
|
|
name: "arXiv",
|
|
pattern: /^https:\/\/arxiv\.org\//,
|
|
},
|
|
fdroid: {
|
|
base: "https://f-droid.org",
|
|
name: "F-Droid",
|
|
pattern: /^https:\/\/f-droid\.org\//,
|
|
},
|
|
};
|
|
|
|
// 转换URL为Xget格式
|
|
function transformUrl(url, xgetDomain, enabledPlatforms) {
|
|
try {
|
|
const platform = detectPlatform(url);
|
|
if (!platform || !enabledPlatforms[platform]) {
|
|
return null;
|
|
}
|
|
|
|
const urlObj = new URL(url);
|
|
const path = urlObj.pathname + urlObj.search + urlObj.hash;
|
|
|
|
return `https://${xgetDomain}/${platform}${path}`;
|
|
} catch (error) {
|
|
console.error("转换 URL 时出错:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 检测平台
|
|
function detectPlatform(url) {
|
|
for (const [key, platform] of Object.entries(PLATFORMS)) {
|
|
if (platform.pattern.test(url)) {
|
|
return key;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
const DEFAULT_SETTINGS = {
|
|
enabled: true,
|
|
xgetDomain: "xget.xi-xu.me",
|
|
enabledPlatforms: {
|
|
// 代码托管平台
|
|
gh: true,
|
|
gl: true,
|
|
gitea: true,
|
|
codeberg: true,
|
|
sf: true,
|
|
aosp: true,
|
|
|
|
// AI/ML 平台
|
|
hf: true,
|
|
|
|
// 包管理平台
|
|
npm: true,
|
|
pypi: true,
|
|
"pypi-files": true,
|
|
conda: true,
|
|
"conda-community": true,
|
|
maven: true,
|
|
apache: true,
|
|
gradle: true,
|
|
rubygems: true,
|
|
cran: true,
|
|
cpan: true,
|
|
ctan: true,
|
|
golang: true,
|
|
nuget: true,
|
|
crates: true,
|
|
packagist: true,
|
|
|
|
// 其他平台
|
|
arxiv: true,
|
|
fdroid: true,
|
|
},
|
|
};
|
|
|
|
// 初始化扩展
|
|
chrome.runtime.onInstalled.addListener(async () => {
|
|
console.log("Xget for Chromium 已安装");
|
|
|
|
// 如果尚未设置,则设置默认设置
|
|
const settings = await chrome.storage.sync.get(DEFAULT_SETTINGS);
|
|
await chrome.storage.sync.set(settings);
|
|
});
|
|
|
|
// 监听下载事件
|
|
chrome.downloads.onDeterminingFilename.addListener((downloadItem, suggest) => {
|
|
handleDownload(downloadItem, suggest);
|
|
});
|
|
|
|
async function handleDownload(downloadItem, suggest) {
|
|
try {
|
|
const settings = await chrome.storage.sync.get(DEFAULT_SETTINGS);
|
|
|
|
// 检查扩展是否已启用并配置了域名
|
|
if (!settings.enabled || !settings.xgetDomain) {
|
|
suggest();
|
|
return;
|
|
}
|
|
|
|
const url = downloadItem.url;
|
|
const redirectedUrl = transformUrl(
|
|
url,
|
|
settings.xgetDomain,
|
|
settings.enabledPlatforms
|
|
);
|
|
|
|
if (redirectedUrl && redirectedUrl !== url) {
|
|
console.log("重定向下载:", url, "->", redirectedUrl);
|
|
|
|
// 取消原始下载
|
|
chrome.downloads.cancel(downloadItem.id);
|
|
|
|
// 使用重定向的 URL 开始新下载
|
|
chrome.downloads.download({
|
|
url: redirectedUrl,
|
|
filename: downloadItem.filename || undefined,
|
|
conflictAction: "uniquify",
|
|
});
|
|
|
|
// 通过内容脚本显示通知
|
|
try {
|
|
await chrome.tabs.sendMessage(downloadItem.tabId, {
|
|
action: "showNotification",
|
|
message: "下载已通过 Xget 重定向",
|
|
});
|
|
} catch (error) {
|
|
console.log("无法向标签页发送通知");
|
|
}
|
|
} else {
|
|
suggest();
|
|
}
|
|
} catch (error) {
|
|
console.error("处理下载时出错:", error);
|
|
suggest();
|
|
}
|
|
}
|
|
|
|
function transformUrlLegacy(url, settings) {
|
|
try {
|
|
// 找到匹配的平台
|
|
for (const [platformKey, platform] of Object.entries(PLATFORMS)) {
|
|
if (!settings.enabledPlatforms[platformKey]) continue;
|
|
|
|
if (platform.pattern.test(url)) {
|
|
const urlObj = new URL(url);
|
|
const path = urlObj.pathname + urlObj.search + urlObj.hash;
|
|
|
|
// 使用 Xget 域名转换 URL(添加 https:// 协议)
|
|
const xgetUrl = `https://${settings.xgetDomain}/${platformKey}${path}`;
|
|
return xgetUrl;
|
|
}
|
|
}
|
|
|
|
return null; // 不需要转换
|
|
} catch (error) {
|
|
console.error("转换 URL 时出错:", error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 监听来自弹出窗口/选项的消息
|
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|
if (request.action === "getSettings") {
|
|
chrome.storage.sync.get(DEFAULT_SETTINGS).then(sendResponse);
|
|
return true;
|
|
} else if (request.action === "saveSettings") {
|
|
chrome.storage.sync.set(request.settings).then(async () => {
|
|
// 通知相关标签页刷新
|
|
try {
|
|
const tabs = await chrome.tabs.query({
|
|
url: Object.values(PLATFORMS).map((platform) => platform.base + "/*"),
|
|
});
|
|
|
|
for (const tab of tabs) {
|
|
try {
|
|
await chrome.tabs.sendMessage(tab.id, {
|
|
action: "showNotification",
|
|
message: "设置已更新!点击刷新页面",
|
|
showRefreshButton: true,
|
|
});
|
|
} catch (error) {
|
|
// 标签页可能没有加载内容脚本,忽略
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.log("无法通知标签页设置更新");
|
|
}
|
|
|
|
sendResponse({ success: true });
|
|
});
|
|
return true;
|
|
}
|
|
});
|