feat: 新增客户端协议生成系统,支持8种主流下载工具

🚀 核心功能
- 新增完整的客户端下载链接生成器系统
- 支持ARIA2、Motrix、比特彗星、迅雷、wget、cURL、IDM、FDM、PowerShell等8种客户端
- 自动处理防盗链参数(User-Agent、Referer、Cookie等)
- 提供可扩展的生成器架构,支持自定义客户端

🔧 技术实现
- ClientLinkGeneratorFactory: 工厂模式管理生成器
- DownloadLinkMeta: 元数据存储下载信息
- ClientLinkUtils: 便捷工具类
- 线程安全的ConcurrentHashMap设计

🌐 前端集成
- 新增ClientLinks.vue界面,支持客户端链接展示
- Element Plus图标系统,混合图标显示
- 客户端检测逻辑优化,避免自动打开外部应用
- 移动端和PC端环境判断

📚 文档完善
- 完整的CLIENT_LINK_GENERATOR_GUIDE.md使用指南
- API文档和测试用例
- 输出示例和最佳实践

从单纯的网盘解析工具升级为完整的下载解决方案生态
This commit is contained in:
q
2025-10-24 09:25:57 +08:00
parent 231d5c3fb9
commit 42b721eabf
47 changed files with 3740 additions and 96 deletions

View File

@@ -2,11 +2,13 @@ import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import ShowFile from '@/views/ShowFile.vue'
import ShowList from '@/views/ShowList.vue'
import ClientLinks from '@/views/ClientLinks.vue'
const routes = [
{ path: '/', component: Home },
{ path: '/showFile', component: ShowFile },
{ path: '/showList', component: ShowList }
{ path: '/showList', component: ShowList },
{ path: '/clientLinks', component: ClientLinks }
]
const router = createRouter({

125
web-front/src/utils/api.js Normal file
View File

@@ -0,0 +1,125 @@
import axios from 'axios'
// 创建 axios 实例
const api = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL || 'http://localhost:6400',
timeout: 30000,
headers: {
'Content-Type': 'application/json'
}
})
// 请求拦截器
api.interceptors.request.use(
config => {
// 可以在这里添加认证token等
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
api.interceptors.response.use(
response => {
return response.data
},
error => {
console.error('API请求错误:', error)
if (error.response) {
// 服务器返回错误状态码
const message = error.response.data?.message || error.response.data?.error || '服务器错误'
return Promise.reject(new Error(message))
} else if (error.request) {
// 网络错误
return Promise.reject(new Error('网络连接失败,请检查网络设置'))
} else {
// 其他错误
return Promise.reject(new Error(error.message || '请求失败'))
}
}
)
// 客户端链接 API
export const clientLinksApi = {
/**
* 获取所有客户端下载链接
* @param {string} shareUrl - 分享链接
* @param {string} password - 提取码(可选)
* @returns {Promise} 客户端链接响应
*/
async getClientLinks(shareUrl, password = '') {
const params = new URLSearchParams()
params.append('url', shareUrl)
if (password) {
params.append('pwd', password)
}
return await api.get(`/v2/clientLinks?${params.toString()}`)
},
/**
* 获取指定类型的客户端下载链接
* @param {string} shareUrl - 分享链接
* @param {string} password - 提取码(可选)
* @param {string} clientType - 客户端类型
* @returns {Promise} 指定类型的客户端链接
*/
async getClientLink(shareUrl, password = '', clientType) {
const params = new URLSearchParams()
params.append('url', shareUrl)
if (password) {
params.append('pwd', password)
}
params.append('clientType', clientType)
return await api.get(`/v2/clientLink?${params.toString()}`)
}
}
// 其他 API如果需要的话
export const parserApi = {
/**
* 解析分享链接
* @param {string} shareUrl - 分享链接
* @param {string} password - 提取码(可选)
* @returns {Promise} 解析结果
*/
async parseLink(shareUrl, password = '') {
const params = new URLSearchParams()
params.append('url', shareUrl)
if (password) {
params.append('pwd', password)
}
return await api.get(`/v2/linkInfo?${params.toString()}`)
},
/**
* 获取文件列表
* @param {string} shareUrl - 分享链接
* @param {string} password - 提取码(可选)
* @param {string} dirId - 目录ID可选
* @param {string} uuid - UUID可选
* @returns {Promise} 文件列表
*/
async getFileList(shareUrl, password = '', dirId = '', uuid = '') {
const params = new URLSearchParams()
params.append('url', shareUrl)
if (password) {
params.append('pwd', password)
}
if (dirId) {
params.append('dirId', dirId)
}
if (uuid) {
params.append('uuid', uuid)
}
return await api.get(`/v2/getFileList?${params.toString()}`)
}
}
export default api

File diff suppressed because one or more lines are too long

View File

@@ -91,6 +91,7 @@
<el-button style="margin-left: 20px" @click="generateMarkdown">生成Markdown</el-button>
<el-button style="margin-left: 20px" @click="generateQRCode">扫码下载</el-button>
<el-button style="margin-left: 20px" @click="getStatistics">分享统计</el-button>
<el-button style="margin-left: 20px" @click="goToClientLinks" type="primary">客户端链接(实验)</el-button>
</p>
</div>
@@ -589,6 +590,55 @@ export default {
}).catch(() => {
this.$message.error('复制失败');
});
},
// 跳转到客户端链接页面
async goToClientLinks() {
// 验证输入
if (!this.link.trim()) {
this.$message.warning('请先输入分享链接')
return
}
if (!this.link.startsWith("https://") && !this.link.startsWith("http://")) {
this.$message.error("请输入有效链接!")
return
}
try {
// 显示加载状态
this.isLoading = true
// 直接使用 axios 请求客户端链接 API因为它的响应格式与其他 API 不同
const params = { url: this.link }
if (this.password) params.pwd = this.password
const response = await axios.get(`${this.baseAPI}/v2/clientLinks`, { params })
const result = response.data
// 处理包装格式的响应
const clientData = result.data || result
if (clientData.success) {
// 将数据存储到 sessionStorage供客户端链接页面使用
sessionStorage.setItem('clientLinksData', JSON.stringify(clientData))
sessionStorage.setItem('clientLinksForm', JSON.stringify({
shareUrl: this.link,
password: this.password
}))
// 跳转到客户端链接页面
this.$router.push('/clientLinks')
this.$message.success('客户端链接生成成功,正在跳转...')
} else {
this.$message.error(clientData.error || '生成客户端链接失败')
}
} catch (error) {
console.error('生成客户端链接失败:', error)
this.$message.error('生成客户端链接失败')
} finally {
this.isLoading = false
}
}
},