Skip to content

Commit de10ad2

Browse files
authored
Merge pull request #614 from imsyy/dev-player
✨ feat: 增加下载重试按钮,解决卡0%问题
2 parents be0f4ca + a76ce18 commit de10ad2

7 files changed

Lines changed: 170 additions & 111 deletions

File tree

electron/main/ipc/ipc-file.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -392,10 +392,10 @@ const initFileIpc = (): void => {
392392
songData?: any;
393393
skipIfExist?: boolean;
394394
} = {
395-
fileName: "未知文件名",
396-
fileType: "mp3",
397-
path: app.getPath("downloads"),
398-
},
395+
fileName: "未知文件名",
396+
fileType: "mp3",
397+
path: app.getPath("downloads"),
398+
},
399399
): Promise<{ status: "success" | "skipped" | "error"; message?: string }> => {
400400
try {
401401
// 获取窗口

src/components/Menu/SongListMenu.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import type { SongType } from "@/types/main";
2020
import { NAlert, type DropdownOption } from "naive-ui";
2121
import { useStatusStore, useLocalStore, useDataStore, useMusicStore } from "@/stores";
22+
import DownloadManager from "@/utils/downloadManager";
2223
import { renderIcon, copyData } from "@/utils/helper";
2324
import { deleteCloudSong, importCloudSong } from "@/api/cloud";
2425
import {
@@ -74,6 +75,8 @@ const openDropdown = (
7475
const isCurrent = statusStore.playIndex === index;
7576
// 是否为用户歌单
7677
const isUserPlaylist = !!playListId && userPlaylistsData.some((pl) => pl.id === playListId);
78+
// 是否正在下载或下载失败
79+
const isDownloading = dataStore.downloadingSongs.some((item) => item.song.id === song.id);
7780
// 生成菜单
7881
nextTick().then(() => {
7982
dropdownOptions.value = [
@@ -246,10 +249,17 @@ const openDropdown = (
246249
{
247250
key: "download",
248251
label: "下载歌曲",
249-
show: !isLocal && type === "song",
252+
show: !isLocal && type === "song" && !isDownloading,
250253
props: { onClick: () => openDownloadSong(song) },
251254
icon: renderIcon("Download"),
252255
},
256+
{
257+
key: "retry-download",
258+
label: "重试下载",
259+
show: isDownloading,
260+
props: { onClick: () => DownloadManager.retryDownload(song.id) },
261+
icon: renderIcon("Refresh"),
262+
},
253263
];
254264
// 显示菜单
255265
dropdownX.value = e.clientX;

src/components/Setting/LocalSetting.vue

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@
237237
</template>
238238

239239
<script setup lang="ts">
240-
import { computed } from "vue";
241240
import { useSettingStore } from "@/stores";
242241
import { changeLocalLyricPath, changeLocalMusicPath } from "@/utils/helper";
243242
import { songLevelData, getSongLevelsData } from "@/utils/meta";

src/stores/data.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ interface ListState {
4040
song: SongType;
4141
/** 音质 */
4242
quality: SongLevelType;
43-
/** 状态:下载中 / 失败 */
44-
status: "downloading" | "failed";
43+
/** 状态:下载中 / 等待中 / 失败 */
44+
status: "downloading" | "waiting" | "failed";
4545
/** 下载进度 */
4646
progress: number;
4747
/** 已传输大小 */
@@ -350,14 +350,23 @@ export const useDataStore = defineStore("data", {
350350
this.downloadingSongs.push({
351351
song: cloneDeep(song),
352352
quality,
353-
status: "downloading",
353+
status: "waiting",
354354
progress: 0,
355355
transferred: "0MB",
356356
totalSize: "0MB",
357357
});
358358
// 保存到本地存储
359359
musicDB.setItem("downloadingSongs", cloneDeep(this.downloadingSongs));
360360
},
361+
// 更新下载状态
362+
updateDownloadStatus(songId: number, status: "downloading" | "waiting" | "failed") {
363+
const index = this.downloadingSongs.findIndex((item) => item.song.id === songId);
364+
if (index !== -1) {
365+
this.downloadingSongs[index].status = status;
366+
// 强制触发响应式更新 (Fix: 下一首歌曲状态更新UI不变化的问题)
367+
this.downloadingSongs = [...this.downloadingSongs];
368+
}
369+
},
361370
// 更新下载进度
362371
updateDownloadProgress(
363372
songId: number,
@@ -370,7 +379,7 @@ export const useDataStore = defineStore("data", {
370379
item.progress = progress;
371380
item.transferred = transferred;
372381
item.totalSize = totalSize;
373-
// 进度更新过于频繁,不再实时保存到本地存储,仅在添加/删除时保存
382+
// 进度更新过于频繁,不需要强制更新整个数组,以免影响性能
374383
}
375384
},
376385
// 移除正在下载的歌曲(下载失败时)
@@ -383,23 +392,25 @@ export const useDataStore = defineStore("data", {
383392
},
384393
// 标记下载失败(保留在列表中)
385394
markDownloadFailed(songId: number) {
386-
const item = this.downloadingSongs.find((item) => item.song.id === songId);
387-
if (item) {
388-
item.status = "failed";
389-
item.progress = 0;
390-
item.transferred = "0MB";
391-
item.totalSize = "0MB";
395+
const index = this.downloadingSongs.findIndex((item) => item.song.id === songId);
396+
if (index !== -1) {
397+
this.downloadingSongs[index].status = "failed";
398+
this.downloadingSongs[index].progress = 0;
399+
this.downloadingSongs[index].transferred = "0MB";
400+
this.downloadingSongs[index].totalSize = "0MB";
401+
this.downloadingSongs = [...this.downloadingSongs];
392402
musicDB.setItem("downloadingSongs", cloneDeep(this.downloadingSongs));
393403
}
394404
},
395405
// 重置下载任务状态(用于重试)
396406
resetDownloadingSong(songId: number) {
397-
const item = this.downloadingSongs.find((item) => item.song.id === songId);
398-
if (item) {
399-
item.status = "downloading";
400-
item.progress = 0;
401-
item.transferred = "0MB";
402-
item.totalSize = "0MB";
407+
const index = this.downloadingSongs.findIndex((item) => item.song.id === songId);
408+
if (index !== -1) {
409+
this.downloadingSongs[index].status = "waiting";
410+
this.downloadingSongs[index].progress = 0;
411+
this.downloadingSongs[index].transferred = "0MB";
412+
this.downloadingSongs[index].totalSize = "0MB";
413+
this.downloadingSongs = [...this.downloadingSongs];
403414
}
404415
},
405416
},

src/utils/downloadManager.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,17 @@ class DownloadManager {
118118
const total = (totalBytes / 1024 / 1024).toFixed(2) + "MB";
119119
dataStore.updateDownloadProgress(
120120
song.id,
121-
Number((percent * 100).toFixed(0)),
121+
Number((percent * 100).toFixed(1)),
122122
transferred,
123123
total,
124124
);
125125
};
126126
removeListener = window.electron.ipcRenderer.on("download-progress", progressHandler);
127127
}
128128

129+
// 更新状态为下载中
130+
dataStore.updateDownloadStatus(song.id, "downloading");
131+
129132
// 开始下载
130133
try {
131134
const result = await this.processDownload({
@@ -443,14 +446,28 @@ class DownloadManager {
443446
if (!task) return;
444447

445448
// 重置任务状态与进度
446-
dataStore.resetDownloadingSong(songId);
449+
dataStore.updateDownloadStatus(songId, "downloading");
450+
// 重置进度信息
451+
dataStore.updateDownloadProgress(songId, 0, "0MB", "0MB");
447452

448453
// 重新加入队列
449454
this.queue.push({ song: task.song, quality: task.quality });
450455

451456
// 继续处理队列
452457
this.processQueue();
453458
}
459+
460+
/**
461+
* 重试所有下载任务
462+
*/
463+
public retryAllDownloads() {
464+
const dataStore = useDataStore();
465+
const songsToRetry = dataStore.downloadingSongs.map((item) => item.song.id);
466+
467+
songsToRetry.forEach((id) => {
468+
this.retryDownload(id);
469+
});
470+
}
454471
}
455472

456473
export default DownloadManager.getInstance();

0 commit comments

Comments
 (0)