refactor(download): 重构下载系统,支持暂停/恢复/取消,修复歌词加载

- 新建 DownloadManager 类(主进程),每个任务独立 AbortController 控制
- 新建 Pinia useDownloadStore 作为渲染进程单一数据源
- 支持暂停/恢复/取消下载,支持断点续传(Range header)
- 批量下载全部完成后发送汇总系统通知,单首不重复通知
- 并发数可配置(1-5),队列持久化(重启后恢复)
- 修复下载列表不全、封面加载失败、通知重复等 bug
- 修复本地/下载歌曲歌词加载:优先从 ID3/FLAC 元数据提取,API 作为 fallback
- 删除 useDownloadStatus.ts,统一状态管理
- DownloadDrawer/DownloadPage 全面重写,移除 @apply 违规
- 新增 5 语言 i18n 键值(暂停/恢复/取消/排队中等)
This commit is contained in:
alger
2026-03-27 23:00:39 +08:00
parent 59f71148af
commit bc46024499
20 changed files with 1861 additions and 1578 deletions
+37 -1
View File
@@ -82,7 +82,43 @@ const api = {
scanLocalMusicWithStats: (folderPath: string) =>
ipcRenderer.invoke('scan-local-music-with-stats', folderPath),
parseLocalMusicMetadata: (filePaths: string[]) =>
ipcRenderer.invoke('parse-local-music-metadata', filePaths)
ipcRenderer.invoke('parse-local-music-metadata', filePaths),
// Download manager
downloadAdd: (task: any) => ipcRenderer.invoke('download:add', task),
downloadAddBatch: (tasks: any) => ipcRenderer.invoke('download:add-batch', tasks),
downloadPause: (taskId: string) => ipcRenderer.invoke('download:pause', taskId),
downloadResume: (taskId: string) => ipcRenderer.invoke('download:resume', taskId),
downloadCancel: (taskId: string) => ipcRenderer.invoke('download:cancel', taskId),
downloadCancelAll: () => ipcRenderer.invoke('download:cancel-all'),
downloadGetQueue: () => ipcRenderer.invoke('download:get-queue'),
downloadSetConcurrency: (n: number) => ipcRenderer.send('download:set-concurrency', n),
downloadGetCompleted: () => ipcRenderer.invoke('download:get-completed'),
downloadDeleteCompleted: (filePath: string) =>
ipcRenderer.invoke('download:delete-completed', filePath),
downloadClearCompleted: () => ipcRenderer.invoke('download:clear-completed'),
getEmbeddedLyrics: (filePath: string) =>
ipcRenderer.invoke('download:get-embedded-lyrics', filePath),
downloadProvideUrl: (taskId: string, url: string) =>
ipcRenderer.invoke('download:provide-url', { taskId, url }),
onDownloadProgress: (cb: (data: any) => void) => {
ipcRenderer.on('download:progress', (_event: any, data: any) => cb(data));
},
onDownloadStateChange: (cb: (data: any) => void) => {
ipcRenderer.on('download:state-change', (_event: any, data: any) => cb(data));
},
onDownloadBatchComplete: (cb: (data: any) => void) => {
ipcRenderer.on('download:batch-complete', (_event: any, data: any) => cb(data));
},
onDownloadRequestUrl: (cb: (data: any) => void) => {
ipcRenderer.on('download:request-url', (_event: any, data: any) => cb(data));
},
removeDownloadListeners: () => {
ipcRenderer.removeAllListeners('download:progress');
ipcRenderer.removeAllListeners('download:state-change');
ipcRenderer.removeAllListeners('download:batch-complete');
ipcRenderer.removeAllListeners('download:request-url');
}
};
// 创建带类型的ipcRenderer对象,暴露给渲染进程