From 90402243199d9a158b004f630e4aaceb181bbd16 Mon Sep 17 00:00:00 2001 From: Nexmoe <16796652+nexmoe@users.noreply.github.com> Date: Mon, 10 Nov 2025 21:25:43 +0800 Subject: [PATCH] refactor(types): remove obsolete format/quality/codec fields and related logic to simplify download and avoid redundant storage --- src/main/lib/download-engine.ts | 73 +---------- src/main/lib/subscription-scheduler.ts | 3 +- .../src/components/download/DownloadItem.tsx | 123 ++++++++++++------ src/renderer/src/store/downloads.ts | 3 - src/shared/types/index.ts | 10 -- 5 files changed, 93 insertions(+), 119 deletions(-) diff --git a/src/main/lib/download-engine.ts b/src/main/lib/download-engine.ts index 0e34b35..3128701 100644 --- a/src/main/lib/download-engine.ts +++ b/src/main/lib/download-engine.ts @@ -407,8 +407,7 @@ class DownloadEngine extends EventEmitter { createdAt, tags: options.tags, origin, - subscriptionId: options.subscriptionId, - subscriptionTitle: options.subscriptionTitle + subscriptionId: options.subscriptionId } this.queue.add(id, options, item) @@ -420,8 +419,7 @@ class DownloadEngine extends EventEmitter { downloadPath: targetDownloadPath, tags: options.tags, origin, - subscriptionId: options.subscriptionId, - subscriptionTitle: options.subscriptionTitle + subscriptionId: options.subscriptionId }) } @@ -441,8 +439,6 @@ class DownloadEngine extends EventEmitter { let availableFormats: VideoFormat[] = [] let selectedFormat: VideoFormat | undefined let actualFormat: string | null = null - let actualQuality: string | null = null - let actualCodec: string | null = null let videoInfo: VideoInfo | undefined // First, get detailed video info to capture basic metadata and formats @@ -455,20 +451,6 @@ class DownloadEngine extends EventEmitter { if (selectedFormat) { actualFormat = selectedFormat.ext || actualFormat - - if (selectedFormat.height) { - actualQuality = `${selectedFormat.height}p${ - selectedFormat.fps && selectedFormat.fps === 60 ? '60' : '' - }` - } else if (selectedFormat.format_note) { - actualQuality = selectedFormat.format_note - } - - if (options.type === 'audio' || options.type === 'extract') { - actualCodec = selectedFormat.acodec || actualCodec - } else { - actualCodec = selectedFormat.vcodec || selectedFormat.acodec || actualCodec - } } this.updateDownloadInfo(id, { @@ -513,18 +495,6 @@ class DownloadEngine extends EventEmitter { selectedFormat = candidate actualFormat = candidate.ext || actualFormat - if (candidate.height) { - actualQuality = `${candidate.height}p${candidate.fps === 60 ? '60' : ''}` - } else if (candidate.format_note) { - actualQuality = candidate.format_note - } - - if (options.type === 'audio' || options.type === 'extract') { - actualCodec = candidate.acodec || actualCodec - } else { - actualCodec = candidate.vcodec || candidate.acodec || actualCodec - } - this.updateDownloadInfo(id, { selectedFormat: candidate }) @@ -640,16 +610,6 @@ class DownloadEngine extends EventEmitter { if (extMatch && !actualFormat) { actualFormat = extMatch[1] } - - const heightMatch = formatInfo.match(/(\d+)p/) - if (heightMatch && !actualQuality) { - actualQuality = `${heightMatch[1]}p` - } - - const codecMatch = formatInfo.match(/(?:vcodec|acodec)[:\s]*([^\s,]+)/) - if (codecMatch && !actualCodec) { - actualCodec = codecMatch[1] - } } } @@ -759,9 +719,6 @@ class DownloadEngine extends EventEmitter { status: 'completed', completedAt: Date.now(), fileSize, - format: willMerge ? 'mp4' : actualFormat || undefined, - quality: actualQuality || undefined, - codec: actualCodec || undefined, savedFileName }) scopedLoggers.download.info('Download completed successfully for ID:', id) @@ -848,15 +805,6 @@ class DownloadEngine extends EventEmitter { if (updates.fileSize !== undefined) { historyUpdates.fileSize = updates.fileSize } - if (updates.format !== undefined) { - historyUpdates.format = updates.format - } - if (updates.quality !== undefined) { - historyUpdates.quality = updates.quality - } - if (updates.codec !== undefined) { - historyUpdates.codec = updates.codec - } if (updates.description !== undefined) { historyUpdates.description = updates.description } @@ -884,6 +832,9 @@ class DownloadEngine extends EventEmitter { if (updates.playlistSize !== undefined) { historyUpdates.playlistSize = updates.playlistSize } + if (updates.selectedFormat !== undefined) { + historyUpdates.selectedFormat = updates.selectedFormat + } if (updates.status !== undefined) { historyUpdates.status = updates.status } @@ -893,9 +844,6 @@ class DownloadEngine extends EventEmitter { if (updates.error !== undefined) { historyUpdates.error = updates.error } - if (updates.selectedFormat !== undefined) { - historyUpdates.selectedFormat = updates.selectedFormat - } if (updates.savedFileName !== undefined) { historyUpdates.savedFileName = updates.savedFileName } @@ -924,9 +872,6 @@ class DownloadEngine extends EventEmitter { error, duration: completedDownload?.item.duration, fileSize: completedDownload?.item.fileSize, - format: completedDownload?.item.format, - quality: completedDownload?.item.quality, - codec: completedDownload?.item.codec, description: completedDownload?.item.description, channel: completedDownload?.item.channel, uploader: completedDownload?.item.uploader, @@ -934,7 +879,6 @@ class DownloadEngine extends EventEmitter { tags: completedDownload?.item.tags, origin: completedDownload?.item.origin, subscriptionId: completedDownload?.item.subscriptionId, - subscriptionTitle: completedDownload?.item.subscriptionTitle, playlistId: completedDownload?.item.playlistId, playlistTitle: completedDownload?.item.playlistTitle, playlistIndex: completedDownload?.item.playlistIndex, @@ -964,9 +908,6 @@ class DownloadEngine extends EventEmitter { downloadedAt: updates.downloadedAt ?? Date.now(), completedAt: updates.completedAt, error: updates.error, - format: updates.format, - quality: updates.quality, - codec: updates.codec, description: updates.description, channel: updates.channel, uploader: updates.uploader, @@ -974,7 +915,6 @@ class DownloadEngine extends EventEmitter { tags: updates.tags ?? options.tags, origin: updates.origin ?? options.origin, subscriptionId: updates.subscriptionId ?? options.subscriptionId, - subscriptionTitle: updates.subscriptionTitle ?? options.subscriptionTitle, // Download-specific format info selectedFormat: updates.selectedFormat, playlistId: updates.playlistId, @@ -995,8 +935,7 @@ class DownloadEngine extends EventEmitter { downloadPath: resolvedDownloadPath ?? base.downloadPath, tags: updates.tags ?? base.tags, origin: updates.origin ?? base.origin, - subscriptionId: updates.subscriptionId ?? base.subscriptionId, - subscriptionTitle: updates.subscriptionTitle ?? base.subscriptionTitle + subscriptionId: updates.subscriptionId ?? base.subscriptionId } historyManager.addHistoryItem(merged) diff --git a/src/main/lib/subscription-scheduler.ts b/src/main/lib/subscription-scheduler.ts index 7a9401c..580177b 100644 --- a/src/main/lib/subscription-scheduler.ts +++ b/src/main/lib/subscription-scheduler.ts @@ -371,8 +371,7 @@ export class SubscriptionScheduler extends EventEmitter { customFilenameTemplate: namingTemplate, tags, origin: 'subscription', - subscriptionId, - subscriptionTitle: subscription.title + subscriptionId }) this.downloads.set(downloadId, { diff --git a/src/renderer/src/components/download/DownloadItem.tsx b/src/renderer/src/components/download/DownloadItem.tsx index 0cabd07..3c8f3e0 100644 --- a/src/renderer/src/components/download/DownloadItem.tsx +++ b/src/renderer/src/components/download/DownloadItem.tsx @@ -55,6 +55,73 @@ const tryFileOperation = async ( return false } +const getSavedFileExtension = (fileName?: string): string | undefined => { + if (!fileName) { + return undefined + } + const normalized = fileName.trim() + if (!normalized.includes('.')) { + return undefined + } + const ext = normalized.split('.').pop() + return ext?.toLowerCase() +} + +const resolveDownloadExtension = (download: DownloadRecord): string => { + const savedExt = getSavedFileExtension(download.savedFileName) + if (savedExt) { + return savedExt + } + const selectedExt = download.selectedFormat?.ext?.toLowerCase() + if (selectedExt) { + return selectedExt + } + return download.type === 'audio' ? 'mp3' : 'mp4' +} + +const getFormatLabel = (download: DownloadRecord): string | undefined => { + if (download.selectedFormat?.ext) { + return download.selectedFormat.ext.toUpperCase() + } + const savedExt = getSavedFileExtension(download.savedFileName) + return savedExt ? savedExt.toUpperCase() : undefined +} + +const getQualityLabel = (download: DownloadRecord): string | undefined => { + const format = download.selectedFormat + if (!format) { + return undefined + } + if (format.height) { + return `${format.height}p${format.fps === 60 ? '60' : ''}` + } + if (format.format_note) { + return format.format_note + } + if (typeof format.quality === 'number') { + return format.quality.toString() + } + return undefined +} + +const sanitizeCodec = (codec?: string | null): string | undefined => { + if (!codec || codec === 'none') { + return undefined + } + return codec +} + +const getCodecLabel = (download: DownloadRecord): string | undefined => { + const format = download.selectedFormat + if (!format) { + return undefined + } + if (download.type === 'audio' || download.type === 'extract') { + return sanitizeCodec(format.acodec) + } + return sanitizeCodec(format.vcodec) ?? sanitizeCodec(format.acodec) +} + interface DownloadItemProps { download: DownloadRecord } @@ -106,8 +173,7 @@ export function DownloadItem({ download }: DownloadItemProps) { const removeHistory = useSetAtom(removeHistoryRecordAtom) const isHistory = download.entryType === 'history' const isSubscriptionDownload = download.origin === 'subscription' - const subscriptionLabel = - download.subscriptionTitle ?? download.subscriptionId ?? t('subscriptions.labels.unknown') + const subscriptionLabel = download.subscriptionId ?? t('subscriptions.labels.unknown') const timestamp = download.completedAt ?? download.downloadedAt ?? download.createdAt const showActionsWithoutHover = isHistory || download.status === 'completed' const actionsContainerBaseClass = @@ -115,6 +181,7 @@ export function DownloadItem({ download }: DownloadItemProps) { const actionsContainerClass = showActionsWithoutHover ? actionsContainerBaseClass : `${actionsContainerBaseClass} sm:opacity-0 sm:group-hover:opacity-100` + const resolvedExtension = resolveDownloadExtension(download) // Track if the file exists const [fileExists, setFileExists] = useState(false) @@ -129,7 +196,7 @@ export function DownloadItem({ download }: DownloadItemProps) { } try { - const formatForPath = download.format || (download.type === 'audio' ? 'mp3' : 'mp4') + const formatForPath = resolvedExtension const filePaths = generateFilePathCandidates( download.downloadPath, download.title, @@ -151,13 +218,7 @@ export function DownloadItem({ download }: DownloadItemProps) { } checkFileExists() - }, [ - download.title, - download.downloadPath, - download.format, - download.savedFileName, - download.type - ]) + }, [download.title, download.downloadPath, download.savedFileName, resolvedExtension]) const handleCancel = async () => { if (isHistory) return @@ -172,7 +233,7 @@ export function DownloadItem({ download }: DownloadItemProps) { const handleOpenFolder = async () => { try { const downloadPath = download.downloadPath || settings.downloadPath - const format = download.format || (download.type === 'audio' ? 'mp3' : 'mp4') + const format = resolvedExtension const filePaths = generateFilePathCandidates( downloadPath, download.title, @@ -193,12 +254,7 @@ export function DownloadItem({ download }: DownloadItemProps) { } // Check if copy to clipboard is available const canCopyToClipboard = () => { - return !!( - download.title && - download.downloadPath && - fileExists && - (download.savedFileName || download.format) - ) + return Boolean(download.title && download.downloadPath && fileExists) } // need title, downloadPath, format @@ -210,10 +266,10 @@ export function DownloadItem({ download }: DownloadItemProps) { // Type guard: these values are guaranteed to exist after canCopyToClipboard() check const downloadPath = download.downloadPath - const format = download.format + const format = resolvedExtension const title = download.title - if (!downloadPath || !format || !title) { + if (!downloadPath || !title) { toast.error(t('notifications.copyFailed')) return } @@ -246,7 +302,7 @@ export function DownloadItem({ download }: DownloadItemProps) { if (!isHistory) return try { const downloadPath = download.downloadPath || settings.downloadPath - const format = download.format || (download.type === 'audio' ? 'mp3' : 'mp4') + const format = resolvedExtension const filePaths = generateFilePathCandidates( downloadPath, download.title, @@ -363,11 +419,7 @@ export function DownloadItem({ download }: DownloadItemProps) { download.selectedFormat?.filesize || download.selectedFormat?.filesize_approx const inlineFileSize = selectedFormatSize ? formatFileSize(selectedFormatSize) : undefined - const formatLabelValue = download.selectedFormat?.ext - ? download.selectedFormat.ext.toUpperCase() - : download.format - ? download.format.toUpperCase() - : undefined + const formatLabelValue = getFormatLabel(download) if (formatLabelValue) { metadataDetails.push({ @@ -376,14 +428,12 @@ export function DownloadItem({ download }: DownloadItemProps) { }) } - const qualityValue = download.selectedFormat?.height - ? `${download.selectedFormat.height}p${download.selectedFormat.fps === 60 ? '60' : ''}` - : download.quality + const qualityLabel = getQualityLabel(download) - if (qualityValue) { + if (qualityLabel) { metadataDetails.push({ label: t('download.metadata.quality'), - value: qualityValue + value: qualityLabel }) } @@ -394,10 +444,11 @@ export function DownloadItem({ download }: DownloadItemProps) { }) } - if (download.codec) { + const codecValue = getCodecLabel(download) + if (codecValue) { metadataDetails.push({ label: t('download.metadata.codec'), - value: download.codec + value: codecValue }) } @@ -508,7 +559,7 @@ export function DownloadItem({ download }: DownloadItemProps) { }) } - if (download.selectedFormat.height && !qualityValue) { + if (download.selectedFormat.height && !qualityLabel) { metadataDetails.push({ label: t('download.metadata.height'), value: `${download.selectedFormat.height}px` @@ -639,11 +690,9 @@ export function DownloadItem({ download }: DownloadItemProps) { )} {/* Quality badge */} - {(download.selectedFormat?.height || download.quality) && ( + {qualityLabel && ( - {download.selectedFormat?.height - ? `${download.selectedFormat.height}p${download.selectedFormat.fps === 60 ? '60' : ''}` - : download.quality} + {qualityLabel} )} diff --git a/src/renderer/src/store/downloads.ts b/src/renderer/src/store/downloads.ts index 18ddadf..735ccf6 100644 --- a/src/renderer/src/store/downloads.ts +++ b/src/renderer/src/store/downloads.ts @@ -28,9 +28,6 @@ const toHistoryRecord = (item: DownloadHistoryItem): DownloadRecord => ({ speed: undefined, duration: item.duration, fileSize: item.fileSize, - format: item.format, - quality: item.quality, - codec: item.codec, createdAt: item.downloadedAt, startedAt: item.downloadedAt, completedAt: item.completedAt ?? item.downloadedAt, diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts index d4a6d65..e0afe93 100644 --- a/src/shared/types/index.ts +++ b/src/shared/types/index.ts @@ -62,9 +62,6 @@ export interface DownloadItem { // Enhanced video information duration?: number fileSize?: number - format?: string - quality?: string - codec?: string savedFileName?: string // Timestamps createdAt: number @@ -78,7 +75,6 @@ export interface DownloadItem { tags?: string[] origin?: 'manual' | 'subscription' subscriptionId?: string - subscriptionTitle?: string // Download-specific format info selectedFormat?: VideoFormat // Playlist context (optional) @@ -112,10 +108,6 @@ export interface DownloadHistoryItem { downloadedAt: number completedAt?: number error?: string - // Enhanced video information - format?: string - quality?: string - codec?: string // Additional metadata description?: string channel?: string @@ -124,7 +116,6 @@ export interface DownloadHistoryItem { tags?: string[] origin?: 'manual' | 'subscription' subscriptionId?: string - subscriptionTitle?: string // Download-specific format info selectedFormat?: VideoFormat // Playlist context (optional) @@ -149,7 +140,6 @@ export interface DownloadOptions { tags?: string[] origin?: 'manual' | 'subscription' subscriptionId?: string - subscriptionTitle?: string } export interface PlaylistEntry {