Add support for 20+ platforms and UI overhaul

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.
This commit is contained in:
xixu-me committed 2025-08-08 21:17:24 +08:00
1 parent d37b67c320
commit 09e87db44a
9 files changed
+995 -136

No files matched your search

+11 -9
View File
@@ -1,10 +1,10 @@
# 隐私政策
## 生效日期:2025 年 7 月 12 日
## 生效日期:2025 年 8 月 8 日
## 概述
Xget for Chromium 是一个开源浏览器扩展,旨在通过 Xget 代理服务重定向下载链接来加速 GitHub、GitLab 和 Hugging Face 的下载。我们承诺保护您的隐私并确保数据处理的透明度。
Xget for Chromium 是一个开源浏览器扩展,旨在通过 Xget 代理服务重定向下载链接来加速众多软件开发和研究平台的下载,包括 GitHub、GitLab、Hugging Face、npm、PyPI、Maven、RubyGems、CRAN 等 20+ 个平台。我们承诺保护您的隐私并确保数据处理的透明度。
## 我们的隐私承诺
@@ -35,7 +35,7 @@ Xget for Chromium 扩展遵循“隐私优先”的设计原则,所有处理
- **Xget 域名配置**:您设置的自定义 Xget 服务域名
- **扩展启用状态**:扩展是否启用的开关状态
- **平台偏好设置**:为 GitHub、GitLab 和 Hugging Face 启用/禁用的选择
- **平台偏好设置**:为支持的各个平台(GitHub、GitLab、Hugging Face、npm、PyPI、Maven、RubyGems、CRAN 等)启用/禁用的选择
这些设置:
@@ -84,9 +84,11 @@ Xget for Chromium 扩展遵循“隐私优先”的设计原则,所有处理
该扩展在以下平台上运行:
- GitHub (github.com)
- GitLab (gitlab.com)
- Hugging Face (huggingface.co)
- **代码托管平台**:GitHub、GitLab、Gitea、Codeberg、SourceForge、Android Source
- **包管理平台**:npm、PyPI、Anaconda、Maven Central、Gradle Plugin Portal、RubyGems、CRAN、CPAN、CTAN、Go Proxy、NuGet、Crates.io、Packagist
- **AI/ML 平台**:Hugging Face
- **学术平台**:arXiv
- **应用分发**:F-Droid
扩展不会与这些平台共享任何数据,也不会修改您与这些平台的交互,除了重定向下载链接。
@@ -99,14 +101,14 @@ Xget for Chromium 扩展遵循“隐私优先”的设计原则,所有处理
1. **`downloads`**:检测和管理下载以进行重定向
2. **`storage`**:在本地存储您的扩展设置
3. **`activeTab`**:在当前标签页中显示通知
4. **`host_permissions`**:访问受支持平台以检测下载链接
4. **`host_permissions`**:访问受支持的 20+ 个平台以检测下载链接
### 权限使用
- **下载权限**:仅用于检测下载并将其重定向到 Xget
- **存储权限**:仅用于保存您的扩展设置
- **标签页权限**:仅用于显示下载重定向通知
- **主机权限**:仅用于在受支持平台上检测下载链接
- **主机权限**:仅用于在受支持的各个平台上检测下载链接
我们不使用这些权限来收集数据、跟踪您的活动或任何其他目的。
@@ -210,7 +212,7 @@ Xget for Chromium 扩展遵循“隐私优先”的设计原则,所有处理
---
**最后更新**:2025 年 7 月 18 日
**最后更新**:2025 年 8 月 8 日
**联系方式**:[GitHub Issues](https://github.com/xixu-me/Xget-for-Chromium/issues)
此隐私政策是我们对透明度和用户隐私承诺的一部分。我们相信您有权了解您使用的软件如何处理您的数据,以及在这种情况下,确认它不会处理您的个人数据。
+4 -33
View File
@@ -1,11 +1,10 @@
# Xget for Chromium
一个强大的 Chromium 浏览器扩展,通过自动将下载重定向到 [Xget](https://github.com/xixu-me/Xget) 加速引擎,从而加速 GitHub、GitLab 和 Hugging Face 的下载。
为 Chromium 浏览器提供的 [Xget](https://github.com/xixu-me/Xget) 下载加速扩展,支持 GitHub、GitLab、npm、PyPI 等众多平台的文件下载加速。
## 🚀 功能特性
- **🎯 自动下载加速**:无缝重定向下载通过 Xget 获得更快速度
- **🌐 多平台支持**:支持 GitHub、GitLab 和 Hugging Face
- **⚙️ 可配置设置**:自定义你的 Xget 域名和平台偏好
- **🔔 智能通知**:下载重定向时的可视化反馈
- **🛡️ 隐私优先**:所有处理都在你的浏览器本地进行
@@ -70,29 +69,15 @@
- 输入你的 Xget 域名(例如 `xget.xi-xu.me`)
- 启用扩展
2. **选择平台**(可选)
2. **选择平台**
- 根据需要切换各个平台的开关
- 默认启用所有平台(GitHub、GitLab、Hugging Face)
- 默认启用所有平台
3. **开始下载**
- 访问任何受支持的平台
- 像往常一样点击下载链接
- 下载将自动通过 Xget 加速
## 🎯 支持的平台
| 平台 | 状态 | URL 模式 | 扩展 ID |
|----------|---------|-------------|--------------|
| **GitHub** | ✅ 支持 | `github.com/*` | `gh` |
| **GitLab** | ✅ 支持 | `gitlab.com/*` | `gl` |
| **Hugging Face** | ✅ 支持 | `huggingface.co/*` | `hf` |
### 支持的下载类型
- **GitHub**:发布资源、存储库存档、原始文件、Git LFS 文件
- **GitLab**:项目存档、发布下载、存储库导出
- **Hugging Face**:模型文件、数据集文件、模型卡片、分词器
## 🔧 工作原理
1. **检测**:扩展监控受支持平台上的下载链接
@@ -100,19 +85,6 @@
3. **重定向**:下载通过你配置的 Xget 域名路由
4. **加速**:Xget 的全球 CDN 和优化功能提供更快的下载速度
### URL 转换示例
```text
原始: https://github.com/user/repo/archive/main.zip
Xget: https://xget.xi-xu.me/gh/user/repo/archive/main.zip
原始: https://gitlab.com/user/repo/-/archive/main.zip
Xget: https://xget.xi-xu.me/gl/user/repo/-/archive/main.zip
原始: https://huggingface.co/user/model/resolve/main/model.bin
Xget: https://xget.xi-xu.me/hf/user/model/resolve/main/model.bin
```
### 为什么 Xget 让下载更快
- **边缘缓存**:文件在 Cloudflare 的全球边缘位置进行缓存
@@ -146,14 +118,13 @@ Xget: https://xget.xi-xu.me/hf/user/model/resolve/main/model.bin
- **Chrome**:版本 88+(Manifest V3 支持)
- **Xget 服务**:访问 Xget 实例
- 使用公共实例:`xget.xi-xu.me`
- 或部署你自己的:[Xget 存储库](https://github.com/xixu-me/Xget)(推荐)
- 或部署你自己的:[Xget 存储库](https://github.com/xixu-me/Xget)
### 关于 Xget 服务
Xget 是基于 Cloudflare Workers 构建的高性能、安全的代理服务,提供:
- **全球边缘分发**:通过 Cloudflare 的全球网络加快下载速度
- **多平台支持**:针对 GitHub、GitLab 和 Hugging Face 进行优化
- **高级功能**:HTTP/3 支持、智能缓存、自动重试
- **安全性**:全面的安全标头和内容保护
- **可靠性**:内置超时保护和性能监控
+181 -12
View File
@@ -1,33 +1,202 @@
// 与 worker.js 匹配的平台配置
// 平台配置
const PLATFORMS = {
// 代码托管平台
gh: {
base: "https://github.com",
name: "GitHub",
transform: (path) => path.replace(/^\/gh\//, "/"),
pattern: /^https:\/\/github\.com\//,
},
gl: {
base: "https://gitlab.com",
name: "GitLab",
transform: (path) => path.replace(/^\/gl\//, "/"),
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",
transform: (path) => path.replace(/^\/hf\//, "/"),
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,
},
};
@@ -56,7 +225,11 @@ async function handleDownload(downloadItem, suggest) {
}
const url = downloadItem.url;
const redirectedUrl = transformUrl(url, settings);
const redirectedUrl = transformUrl(
url,
settings.xgetDomain,
settings.enabledPlatforms
);
if (redirectedUrl && redirectedUrl !== url) {
console.log("重定向下载:", url, "->", redirectedUrl);
@@ -89,7 +262,7 @@ async function handleDownload(downloadItem, suggest) {
}
}
function transformUrl(url, settings) {
function transformUrlLegacy(url, settings) {
try {
// 找到匹配的平台
for (const [platformKey, platform] of Object.entries(PLATFORMS)) {
@@ -122,11 +295,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
// 通知相关标签页刷新
try {
const tabs = await chrome.tabs.query({
url: [
"https://github.com/*",
"https://gitlab.com/*",
"https://huggingface.co/*",
],
url: Object.values(PLATFORMS).map((platform) => platform.base + "/*"),
});
for (const tab of tabs) {
+213 -2
View File
@@ -1,7 +1,8 @@
// 内容脚本,在支持的平台上注入下载拦截功能
// 平台检测和 URL 转换
// 平台配置
const PLATFORMS = {
// 代码托管平台
gh: {
base: "https://github.com",
name: "GitHub",
@@ -12,11 +13,127 @@ const PLATFORMS = {
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\//,
},
};
// 初始化内容脚本
@@ -221,7 +338,101 @@ function isDownloadLink(link) {
console.error("无效的 URL:", href, e);
}
// 第七检查:明确的下载文本指示器(更具体)
// 第六检查:npm 包下载
const allowedNpmHosts = ["registry.npmjs.org"];
try {
const parsedUrl = new URL(href);
if (allowedNpmHosts.includes(parsedUrl.host)) {
// npm tarball URL 包含 /-/
if (pathname.includes("/-/") && pathname.endsWith(".tgz")) {
return true;
}
}
} catch (e) {
console.error("无效的 URL:", href, e);
}
// 第七检查:PyPI 包下载
const allowedPypiHosts = ["pypi.org", "files.pythonhosted.org"];
try {
const parsedUrl = new URL(href);
if (allowedPypiHosts.includes(parsedUrl.host)) {
// PyPI 包文件下载
if (
pathname.includes("/packages/") &&
(pathname.endsWith(".tar.gz") ||
pathname.endsWith(".whl") ||
pathname.endsWith(".egg"))
) {
return true;
}
}
} catch (e) {
console.error("无效的 URL:", href, e);
}
// 第八检查:SourceForge 下载
const allowedSourceForgeHosts = ["sourceforge.net"];
try {
const parsedUrl = new URL(href);
if (allowedSourceForgeHosts.includes(parsedUrl.host)) {
// SourceForge 下载 URL 包含 /download
if (
pathname.includes("/download") ||
url.searchParams.get("use_mirror")
) {
return true;
}
}
} catch (e) {
console.error("无效的 URL:", href, e);
}
// 第九检查:Conda 包下载
const allowedCondaHosts = ["repo.anaconda.com", "conda.anaconda.org"];
try {
const parsedUrl = new URL(href);
if (allowedCondaHosts.includes(parsedUrl.host)) {
// Conda 包文件
if (pathname.endsWith(".conda") || pathname.endsWith(".tar.bz2")) {
return true;
}
}
} catch (e) {
console.error("无效的 URL:", href, e);
}
// 第十检查:其他包管理平台
const packageManagerHosts = [
"rubygems.org",
"cran.r-project.org",
"crates.io",
"repo.packagist.org",
"api.nuget.org",
"proxy.golang.org",
];
try {
const parsedUrl = new URL(href);
if (packageManagerHosts.includes(parsedUrl.host)) {
// 各种包管理器的下载文件
const packageExtensions = [
".gem",
".tar.gz",
".crate",
".zip",
".nupkg",
".tgz",
".tar.bz2",
];
if (packageExtensions.some((ext) => pathname.endsWith(ext))) {
return true;
}
}
} catch (e) {
console.error("无效的 URL:", href, e);
}
// 第十一检查:明确的下载文本指示器(更具体)
const downloadTextIndicators = ["download", "download file", "get file"];
const linkText = link.textContent.toLowerCase().trim();
if (
+57 -23
View File
@@ -1,10 +1,10 @@
{
"action": {
"default_icon": {
"128": "icons/icon128.png",
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
"48": "icons/icon48.png"
},
"default_popup": "popup.html",
"default_title": "Xget for Chromium"
@@ -14,45 +14,79 @@
},
"content_scripts": [
{
"js": [
"content.js"
],
"js": ["content.js"],
"matches": [
"https://github.com/*",
"https://gitlab.com/*",
"https://huggingface.co/*"
"https://gitea.com/*",
"https://codeberg.org/*",
"https://sourceforge.net/*",
"https://android.googlesource.com/*",
"https://huggingface.co/*",
"https://registry.npmjs.org/*",
"https://pypi.org/*",
"https://files.pythonhosted.org/*",
"https://repo.anaconda.com/*",
"https://conda.anaconda.org/*",
"https://repo1.maven.org/*",
"https://downloads.apache.org/*",
"https://plugins.gradle.org/*",
"https://rubygems.org/*",
"https://cran.r-project.org/*",
"https://www.cpan.org/*",
"https://tug.ctan.org/*",
"https://proxy.golang.org/*",
"https://api.nuget.org/*",
"https://crates.io/*",
"https://repo.packagist.org/*",
"https://arxiv.org/*",
"https://f-droid.org/*"
],
"run_at": "document_end"
}
],
"description": "为 GitHub、GitLab 和 Hugging Face 提供更快的文件下载体验",
"description": "为 Chromium 浏览器提供的 Xget 下载加速扩展,支持 GitHub、GitLab、npm、PyPI 等众多平台的文件下载加速",
"host_permissions": [
"https://github.com/*",
"https://gitlab.com/*",
"https://huggingface.co/*"
"https://gitea.com/*",
"https://codeberg.org/*",
"https://sourceforge.net/*",
"https://android.googlesource.com/*",
"https://huggingface.co/*",
"https://registry.npmjs.org/*",
"https://pypi.org/*",
"https://files.pythonhosted.org/*",
"https://repo.anaconda.com/*",
"https://conda.anaconda.org/*",
"https://repo1.maven.org/*",
"https://downloads.apache.org/*",
"https://plugins.gradle.org/*",
"https://rubygems.org/*",
"https://cran.r-project.org/*",
"https://www.cpan.org/*",
"https://tug.ctan.org/*",
"https://proxy.golang.org/*",
"https://api.nuget.org/*",
"https://crates.io/*",
"https://repo.packagist.org/*",
"https://arxiv.org/*",
"https://f-droid.org/*"
],
"icons": {
"128": "icons/icon128.png",
"16": "icons/icon16.png",
"32": "icons/icon32.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
"48": "icons/icon48.png"
},
"manifest_version": 3,
"name": "Xget for Chromium",
"permissions": [
"downloads",
"storage",
"activeTab"
],
"version": "1.3.0",
"permissions": ["downloads", "storage", "activeTab"],
"version": "2.0.0",
"web_accessible_resources": [
{
"matches": [
"<all_urls>"
],
"resources": [
"icons/*"
]
"matches": ["<all_urls>"],
"resources": ["icons/*"]
}
]
}
}
+43 -19
View File
@@ -1,39 +1,63 @@
{
"author": "Xi Xu",
"browser": "chrome",
"bugs": {
"url": "https://github.com/xixu-me/Xget-for-Chromium/issues"
},
"dependencies": {},
"description": "为 GitHub、GitLab 和 Hugging Face 提供更快的文件下载体验",
"devDependencies": {},
"homepage": "https://github.com/xixu-me/Xget-for-Chromium#readme",
"description": "为 Chromium 浏览器提供的 Xget 下载加速扩展,支持 GitHub、GitLab、npm、PyPI 等众多平台的文件下载加速",
"engines": {
"chrome": ">=88"
},
"homepage": "https://github.com/xixu-me/Xget-for-Chromium",
"keywords": [
"chrome-extension",
"download-accelerator",
"xget",
"proxy",
"github",
"gitlab",
"huggingface"
"npm",
"pypi",
"xget",
"download-proxy"
],
"license": "GPL-3.0",
"main": "background.js",
"manifest_version": 3,
"manifest": {
"platforms": [
"github.com",
"gitlab.com",
"gitea.com",
"codeberg.org",
"sourceforge.net",
"android.googlesource.com",
"huggingface.co",
"registry.npmjs.org",
"pypi.org",
"files.pythonhosted.org",
"repo.anaconda.com",
"conda.anaconda.org",
"repo1.maven.org",
"downloads.apache.org",
"plugins.gradle.org",
"rubygems.org",
"cran.r-project.org",
"www.cpan.org",
"tug.ctan.org",
"proxy.golang.org",
"api.nuget.org",
"crates.io",
"repo.packagist.org",
"arxiv.org",
"f-droid.org"
],
"version": 3
},
"name": "xget-for-chromium",
"repository": {
"type": "git",
"url": "https://github.com/xixu-me/Xget-for-Chromium.git"
},
"scripts": {
"build": "不需要构建过程 - 扩展直接从源码运行",
"clean": "rm -f *.zip",
"dev": "打开 chrome://extensions/ 并加载解压的扩展",
"lint": "未配置代码检查 - 建议为 JavaScript 文件添加 ESLint",
"package": "zip -r extension.zip . -x '*.git*' 'node_modules/*' '.github/*' '*.md' 'LICENSE' '*.zip'",
"release": "npm run validate && npm run package",
"test": "在 Chrome 开发者模式下加载扩展进行测试",
"validate": "node -e \"JSON.parse(require('fs').readFileSync('manifest.json', 'utf8')); console.log('✅ manifest.json 格式有效')\""
"build": "echo 'No build process needed for Chrome extension'",
"test": "echo 'No tests specified'"
},
"version": "1.3.0"
}
"version": "2.0.0"
}
+215
View File
@@ -0,0 +1,215 @@
/**
* 平台配置对象,包含各个平台的基础URL和名称
* @type {Object.<string, {base: string, name: string, pattern: RegExp}>}
*/
export 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\//,
},
};
/**
* 统一的路径转换函数
* @param {string} path - 原始路径
* @param {string} platformKey - 平台键值
* @returns {string} - 转换后的路径
*/
export function transformPath(path, platformKey) {
if (!PLATFORMS[platformKey]) {
return path;
}
const prefix = `/${platformKey.replace(/-/g, "/")}/`;
let transformedPath = path.replace(
new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`),
"/"
);
// 特殊处理 crates.io API 路径
if (platformKey === "crates") {
// 转换路径以包含 API 前缀
if (transformedPath.startsWith("/")) {
// 处理不同的 API 端点:
// /serde/1.0.0/download -> /api/v1/crates/serde/1.0.0/download
// /serde -> /api/v1/crates/serde
// /?q=query -> /api/v1/crates?q=query
if (transformedPath === "/" || transformedPath.startsWith("/?")) {
// 搜索端点
transformedPath = transformedPath.replace("/", "/api/v1/crates");
} else {
// 特定 crate 端点
transformedPath = `/api/v1/crates${transformedPath}`;
}
}
}
return transformedPath;
}
/**
* 根据URL检测平台
* @param {string} url - 要检测的URL
* @returns {string|null} - 平台键值或null
*/
export function detectPlatform(url) {
for (const [key, platform] of Object.entries(PLATFORMS)) {
if (platform.pattern.test(url)) {
return key;
}
}
return null;
}
/**
* 转换URL为Xget格式
* @param {string} url - 原始URL
* @param {string} xgetDomain - Xget域名
* @param {Object} enabledPlatforms - 启用的平台配置
* @returns {string|null} - 转换后的URL或null
*/
export 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;
const transformedPath = transformPath(path, platform);
return `https://${xgetDomain}/${platform}${transformedPath}`;
} catch (error) {
console.error("转换 URL 时出错:", error);
return null;
}
}
+176 -29
View File
@@ -7,7 +7,7 @@
<style>
body {
width: 380px;
min-height: 280px;
min-height: 400px;
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
@@ -120,10 +120,37 @@
}
.platforms {
max-height: 200px;
overflow-y: auto;
margin-top: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 6px;
background: rgba(255, 255, 255, 0.05);
}
.platform-category {
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 8px 12px 0 12px;
}
.platform-category:last-child {
border-bottom: none;
}
.category-title {
font-size: 11px;
font-weight: 600;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 6px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.platform-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-top: 8px;
gap: 6px;
margin-bottom: 8px;
}
.platform-item {
@@ -131,9 +158,9 @@
align-items: center;
justify-content: space-between;
background: rgba(255, 255, 255, 0.1);
padding: 8px 12px;
border-radius: 6px;
font-size: 13px;
padding: 6px 10px;
border-radius: 4px;
font-size: 12px;
}
.status {
@@ -212,7 +239,6 @@
<body>
<div class="header">
<h1>Xget for Chromium</h1>
<div class="subtitle">下载加速器</div>
</div>
<div class="content">
@@ -247,26 +273,147 @@
<div class="setting-group">
<label class="setting-label">启用的平台</label>
<div class="platforms">
<div class="platform-item">
<span>GitHub</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="ghToggle" />
<span class="slider"></span>
</label>
<div class="platform-category">
<div class="category-title">代码托管</div>
<div class="platform-grid">
<div class="platform-item">
<span>GitHub</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="ghToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>GitLab</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="glToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Gitea</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="giteaToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Codeberg</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="codebergToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>SourceForge</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="sfToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>AOSP</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="aospToggle" />
<span class="slider"></span>
</label>
</div>
</div>
</div>
<div class="platform-item">
<span>GitLab</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="glToggle" />
<span class="slider"></span>
</label>
<div class="platform-category">
<div class="category-title">AI/ML</div>
<div class="platform-grid">
<div class="platform-item">
<span>Hugging Face</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="hfToggle" />
<span class="slider"></span>
</label>
</div>
</div>
</div>
<div class="platform-item">
<span>Hugging Face</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="hfToggle" />
<span class="slider"></span>
</label>
<div class="platform-category">
<div class="category-title">包管理</div>
<div class="platform-grid">
<div class="platform-item">
<span>npm</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="npmToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>PyPI</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="pypiToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Conda</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="condaToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Maven</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="mavenToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>RubyGems</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="rubygemsToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Crates.io</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="cratesToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>NuGet</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="nugetToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>Go Modules</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="golangToggle" />
<span class="slider"></span>
</label>
</div>
</div>
</div>
<div class="platform-category">
<div class="category-title">其他</div>
<div class="platform-grid">
<div class="platform-item">
<span>arXiv</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="arxivToggle" />
<span class="slider"></span>
</label>
</div>
<div class="platform-item">
<span>F-Droid</span>
<label class="toggle-switch mini-toggle">
<input type="checkbox" id="fdroidToggle" />
<span class="slider"></span>
</label>
</div>
</div>
</div>
</div>
</div>
@@ -278,16 +425,16 @@
target="_blank"
class="link-item"
>
<span class="link-icon">🚀</span>
<span class="link-text">部署你自己的 Xget 服务</span>
<span class="link-icon">🔗</span>
<span class="link-text">Xget 存储库</span>
</a>
<a
href="https://github.com/xixu-me/Xget-for-Chromium"
target="_blank"
class="link-item"
>
<span class="link-icon">📖</span>
<span class="link-text">源码和文档</span>
<span class="link-icon">📚</span>
<span class="link-text">扩展文档</span>
</a>
</div>
</div>
+95 -9
View File
@@ -21,9 +21,43 @@ async function loadSettings() {
document.getElementById("enabledToggle").checked = enabledValue;
// 更新平台切换
document.getElementById("ghToggle").checked = settings.enabledPlatforms.gh;
document.getElementById("glToggle").checked = settings.enabledPlatforms.gl;
document.getElementById("hfToggle").checked = settings.enabledPlatforms.hf;
const platformToggles = {
// 代码托管平台
gh: document.getElementById("ghToggle"),
gl: document.getElementById("glToggle"),
gitea: document.getElementById("giteaToggle"),
codeberg: document.getElementById("codebergToggle"),
sf: document.getElementById("sfToggle"),
aosp: document.getElementById("aospToggle"),
// AI/ML 平台
hf: document.getElementById("hfToggle"),
// 包管理平台
npm: document.getElementById("npmToggle"),
pypi: document.getElementById("pypiToggle"),
conda: document.getElementById("condaToggle"),
maven: document.getElementById("mavenToggle"),
rubygems: document.getElementById("rubygemsToggle"),
crates: document.getElementById("cratesToggle"),
nuget: document.getElementById("nugetToggle"),
golang: document.getElementById("golangToggle"),
// 其他平台
arxiv: document.getElementById("arxivToggle"),
fdroid: document.getElementById("fdroidToggle"),
};
// 设置平台切换状态
Object.entries(platformToggles).forEach(([platform, toggle]) => {
if (
toggle &&
settings.enabledPlatforms &&
settings.enabledPlatforms[platform] !== undefined
) {
toggle.checked = settings.enabledPlatforms[platform];
}
});
// 如果缺少域名则显示状态
if (!domainValue && settings.enabled) {
@@ -52,9 +86,32 @@ function setupEventListeners() {
.addEventListener("blur", validateDomain);
// 平台切换
document.getElementById("ghToggle").addEventListener("change", saveSettings);
document.getElementById("glToggle").addEventListener("change", saveSettings);
document.getElementById("hfToggle").addEventListener("change", saveSettings);
const platformToggles = [
"ghToggle",
"glToggle",
"giteaToggle",
"codebergToggle",
"sfToggle",
"aospToggle",
"hfToggle",
"npmToggle",
"pypiToggle",
"condaToggle",
"mavenToggle",
"rubygemsToggle",
"cratesToggle",
"nugetToggle",
"golangToggle",
"arxivToggle",
"fdroidToggle",
];
platformToggles.forEach((toggleId) => {
const element = document.getElementById(toggleId);
if (element) {
element.addEventListener("change", saveSettings);
}
});
}
async function saveSettings() {
@@ -73,9 +130,38 @@ async function saveSettings() {
enabled: document.getElementById("enabledToggle").checked,
xgetDomain: domainValue,
enabledPlatforms: {
gh: document.getElementById("ghToggle").checked,
gl: document.getElementById("glToggle").checked,
hf: document.getElementById("hfToggle").checked,
// 代码托管平台
gh: document.getElementById("ghToggle")?.checked || false,
gl: document.getElementById("glToggle")?.checked || false,
gitea: document.getElementById("giteaToggle")?.checked || false,
codeberg: document.getElementById("codebergToggle")?.checked || false,
sf: document.getElementById("sfToggle")?.checked || false,
aosp: document.getElementById("aospToggle")?.checked || false,
// AI/ML 平台
hf: document.getElementById("hfToggle")?.checked || false,
// 包管理平台
npm: document.getElementById("npmToggle")?.checked || false,
pypi: document.getElementById("pypiToggle")?.checked || false,
"pypi-files": true, // 默认开启
conda: document.getElementById("condaToggle")?.checked || false,
"conda-community": true, // 默认开启
maven: document.getElementById("mavenToggle")?.checked || false,
apache: true, // 默认开启
gradle: true, // 默认开启
rubygems: document.getElementById("rubygemsToggle")?.checked || false,
cran: true, // 默认开启
cpan: true, // 默认开启
ctan: true, // 默认开启
golang: document.getElementById("golangToggle")?.checked || false,
nuget: document.getElementById("nugetToggle")?.checked || false,
crates: document.getElementById("cratesToggle")?.checked || false,
packagist: true, // 默认开启
// 其他平台
arxiv: document.getElementById("arxivToggle")?.checked || false,
fdroid: document.getElementById("fdroidToggle")?.checked || false,
},
};