From 741e49e75a4cb1f5cbd0ba190438cc7e25129b37 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sun, 21 Jun 2026 22:42:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E4=B8=AA=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E5=86=85=E5=AE=B9=E5=AF=BC=E5=87=BA=E6=B7=B7=E4=B9=B1?= =?UTF-8?q?=E6=88=90=E4=B8=80=E4=B8=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/DownloadManagementPanel.tsx | 41 +++++++++++++++------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/src/components/DownloadManagementPanel.tsx b/src/components/DownloadManagementPanel.tsx index 019e71e..bb6857b 100644 --- a/src/components/DownloadManagementPanel.tsx +++ b/src/components/DownloadManagementPanel.tsx @@ -257,6 +257,28 @@ export function DownloadManagementPanel({ window.setTimeout(() => URL.revokeObjectURL(url), 1000); }; + const getTaskExportFilename = ( + task: CompletedTask, + usedFilenames: Set + ) => { + const episodeLabel = `第${task.episodeIndex + 1}集`; + const baseTitle = task.videoTitle || getGroupTitle([task]); + const episodeTitle = task.episodeTitle + ? `${episodeLabel}_${task.episodeTitle}` + : episodeLabel; + const baseFilename = sanitizeFilename(`${baseTitle}_${episodeTitle}`); + let filename = `${baseFilename}.ts`; + let duplicateIndex = 2; + + while (usedFilenames.has(filename)) { + filename = `${baseFilename}_${duplicateIndex}.ts`; + duplicateIndex += 1; + } + + usedFilenames.add(filename); + return filename; + }; + const getStoredDownloadDirHandle = async (): Promise< FileSystemDirectoryHandle | undefined > => { @@ -399,7 +421,8 @@ export function DownloadManagementPanel({ } } - const blobParts: BlobPart[] = []; + const usedFilenames = new Set(); + let exportedCount = 0; const failedTitles: string[] = []; for (const task of tasksToExport) { @@ -408,28 +431,20 @@ export function DownloadManagementPanel({ task.downloadMode === 'filesystem' ? await readFilesystemTaskAsBlobParts(task, dirHandle!) : await readIndexedDBTaskAsBlobParts(task); - blobParts.push(...parts); + const blob = new Blob(parts, { type: 'video/MP2T' }); + triggerBlobDownload(blob, getTaskExportFilename(task, usedFilenames)); + exportedCount += 1; } catch (error) { console.error('导出任务失败:', task.title, error); failedTitles.push(`第 ${task.episodeIndex + 1} 集`); } } - if (blobParts.length === 0) { + if (exportedCount === 0) { alert(`导出失败:${failedTitles.join('、') || '未找到可导出的内容'}`); return; } - const selectedGroups = videoGroups.filter((group) => - group.tasks.some((task) => selectedIds.has(task.id)) - ); - const baseName = - selectedGroups.length === 1 - ? selectedGroups[0].title - : `MoonTVPlus导出_${tasksToExport.length}集`; - const blob = new Blob(blobParts, { type: 'video/MP2T' }); - triggerBlobDownload(blob, `${sanitizeFilename(baseName)}.ts`); - if (failedTitles.length > 0) { alert(`已导出可读取的内容,但以下条目失败:${failedTitles.join('、')}`); }