From 8cbfc90f5d41bfdfd438d8726c8a37ac7b4340b9 Mon Sep 17 00:00:00 2001 From: debont80 Date: Tue, 30 Jun 2026 15:46:55 -0400 Subject: [PATCH] Fix M18: make audio quality labels format-agnostic ("Best", not "Best (MP3)") The audio quality preset "Best (MP3)" named a format that's wrong whenever the audio format is opus/flac/wav. Renamed it to "Best" so the label never contradicts the chosen audioFormat (which is picked separately). Bitrate presets stay as bitrates and are already ignored for lossless formats (M21). - AUDIO_QUALITY_OPTIONS[0]: 'Best (MP3)' -> 'Best' (buildArgs already had a `case 'Best'` returning '0', so arg generation is unchanged). - Updated the main + renderer defaults and the preview/mock/test fixtures. - Added a one-line migration in getSettings() that rewrites a stored legacy 'Best (MP3)' to 'Best' so existing users' dropdowns match. typecheck + 242 tests + eslint green. Co-Authored-By: Claude Opus 4.8 --- CODE-AUDIT.md | 2 +- src/main/settings.ts | 7 ++++++- src/renderer/src/main.tsx | 2 +- src/renderer/src/store/downloads.ts | 2 +- src/renderer/src/store/history.ts | 2 +- src/renderer/src/store/settings.ts | 2 +- src/shared/ipc.ts | 9 ++++++--- test/buildArgs.test.ts | 6 ++---- test/real-download.integration.test.ts | 4 ++-- 9 files changed, 21 insertions(+), 15 deletions(-) diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index 11f79be..d8df109 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -274,7 +274,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n persisted data lives in main, so nothing is lost).* - [x] **M17 — `statusByUrl` collapses duplicate URLs.** LibraryView maps URL→status into one `Map`; with "Download anyway" duplicates, a row can reflect the wrong item's state. -- [ ] **M18 — Audio "quality" presets hard-code MP3.** `QUALITY_OPTIONS.audio` labels ("Best +- [x] **M18 — Audio "quality" presets hard-code MP3.** `QUALITY_OPTIONS.audio` labels ("Best (MP3)", "320 kbps") are shown even when `downloadOptions.audioFormat` is opus/flac/wav, so the label contradicts the actual output format; `--audio-quality` is also meaningless for lossless. - [x] **M19 — Sidebar-collapsed pref uses `localStorage`** while every other preference uses diff --git a/src/main/settings.ts b/src/main/settings.ts index 6bcdf0a..4522207 100644 --- a/src/main/settings.ts +++ b/src/main/settings.ts @@ -29,7 +29,7 @@ const DEFAULTS: Settings = { audioDir: '', defaultKind: 'video', defaultVideoQuality: 'Best available', - defaultAudioQuality: 'Best (MP3)', + defaultAudioQuality: 'Best', maxConcurrent: 2, filenameTemplate: '%(title)s.%(ext)s', // Follow the OS theme on first launch (SR1) so a dark-mode Windows user isn't @@ -263,6 +263,11 @@ export function getSettings(): Settings { if (!(ACCENT_COLORS as readonly string[]).includes(cur.accentColor)) { s.set('accentColor', DEFAULTS.accentColor) } + // Migrate the legacy audio-quality label 'Best (MP3)' to the format-agnostic + // 'Best' so the dropdown matches and the label no longer names a format (M18). + if (cur.defaultAudioQuality === 'Best (MP3)') { + s.set('defaultAudioQuality', 'Best') + } // Hand callers (and, via IPC, the renderer) plaintext credentials — they're // only encrypted on disk (see withDecryptedSecrets / encryptSecret). cachedSettings = withDecryptedSecrets(s.store) diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index b0f8536..3bd74d3 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -16,7 +16,7 @@ if (import.meta.env.DEV && !window.api) { audioDir: 'C:\\Users\\you\\Documents\\Audio', defaultKind: 'video', defaultVideoQuality: 'Best available', - defaultAudioQuality: 'Best (MP3)', + defaultAudioQuality: 'Best', maxConcurrent: 2, filenameTemplate: '%(title)s.%(ext)s', theme: 'system', diff --git a/src/renderer/src/store/downloads.ts b/src/renderer/src/store/downloads.ts index fb5f6a9..b3cc604 100644 --- a/src/renderer/src/store/downloads.ts +++ b/src/renderer/src/store/downloads.ts @@ -221,7 +221,7 @@ const seed: DownloadItem[] = PREVIEW channel: 'ChillStudio', durationLabel: '1:00:21', kind: 'audio', - quality: 'Best (MP3)', + quality: 'Best', status: 'queued', progress: 0 }, diff --git a/src/renderer/src/store/history.ts b/src/renderer/src/store/history.ts index 1129fa4..a123424 100644 --- a/src/renderer/src/store/history.ts +++ b/src/renderer/src/store/history.ts @@ -25,7 +25,7 @@ const seed: HistoryEntry[] = PREVIEW channel: 'ChillStudio', url: 'https://youtube.com/watch?v=aaa1111', kind: 'audio', - quality: 'Best (MP3)', + quality: 'Best', sizeLabel: '142 MB', filePath: 'C:\\Users\\you\\Downloads\\Deep Focus — Ambient Mix.mp3', completedAt: Date.now() - 1000 * 60 * 60 * 26 diff --git a/src/renderer/src/store/settings.ts b/src/renderer/src/store/settings.ts index 7be2920..f24e4d8 100644 --- a/src/renderer/src/store/settings.ts +++ b/src/renderer/src/store/settings.ts @@ -10,7 +10,7 @@ const FALLBACK: Settings = { audioDir: PREVIEW ? 'C:\\Users\\you\\Documents\\Audio' : '', defaultKind: 'video', defaultVideoQuality: 'Best available', - defaultAudioQuality: 'Best (MP3)', + defaultAudioQuality: 'Best', maxConcurrent: 2, filenameTemplate: '%(title)s.%(ext)s', // Mirror main's DEFAULTS (SR1): follow the OS theme until real settings load, diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index 6b7cfad..1fbc978 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -128,7 +128,10 @@ export const VIDEO_QUALITY_OPTIONS = ['Best available', '1080p', '720p', '480p', export type VideoQuality = (typeof VIDEO_QUALITY_OPTIONS)[number] /** Quality/format labels for the audio download selector. */ -export const AUDIO_QUALITY_OPTIONS = ['Best (MP3)', '320 kbps', '192 kbps', '128 kbps'] as const +// Format-agnostic: the audio container/codec is chosen separately (downloadOptions +// .audioFormat); these are just the target quality. Bitrate values are ignored for +// lossless formats (flac/wav) -- see buildArgs (M18/M21). +export const AUDIO_QUALITY_OPTIONS = ['Best', '320 kbps', '192 kbps', '128 kbps'] as const export type AudioQuality = (typeof AUDIO_QUALITY_OPTIONS)[number] /** UI color theme: an explicit mode, or 'system' to follow the OS preference. */ @@ -409,7 +412,7 @@ export interface StartDownloadOptions { id: string url: string kind: MediaKind - /** one of the UI quality labels (e.g. '1080p', 'Best (MP3)') */ + /** one of the UI quality labels (e.g. '1080p', 'Best') */ quality: string /** absolute output directory; main falls back to the OS Downloads folder */ outputDir?: string @@ -614,7 +617,7 @@ export interface HistoryEntry { channel?: string url: string kind: MediaKind - /** Quality preset ('720p', 'Best available', 'Best (MP3)', …) or the probed + /** Quality preset ('720p', 'Best available', 'Best', …) or the probed * format's display label. Used for display and, when no formatId is present, * as the fallback quality selector on re-download (H5). */ quality: string diff --git a/test/buildArgs.test.ts b/test/buildArgs.test.ts index 5d00cf5..2689008 100644 --- a/test/buildArgs.test.ts +++ b/test/buildArgs.test.ts @@ -28,7 +28,7 @@ function opts(overrides: Partial = {}): StartDownloadOptio return { id: 't', url: URL, kind: 'video', quality: '1080p', ...overrides } } function audio(overrides: Partial = {}): StartDownloadOptions { - return opts({ kind: 'audio', quality: 'Best (MP3)', ...overrides }) + return opts({ kind: 'audio', quality: 'Best', ...overrides }) } function dlo(overrides: Partial = {}): DownloadOptions { return { ...DEFAULT_DOWNLOAD_OPTIONS, ...overrides } @@ -165,9 +165,7 @@ describe('audio: -x --audio-format ', () => { }) it('maps the quality label to an --audio-quality value', () => { - expect(hasSeq(build(audio({ quality: 'Best (MP3)' }), dlo()), '--audio-quality', '0')).toBe( - true - ) + expect(hasSeq(build(audio({ quality: 'Best' }), dlo()), '--audio-quality', '0')).toBe(true) expect(hasSeq(build(audio({ quality: '320 kbps' }), dlo()), '--audio-quality', '320K')).toBe( true ) diff --git a/test/real-download.integration.test.ts b/test/real-download.integration.test.ts index 570b018..99e0461 100644 --- a/test/real-download.integration.test.ts +++ b/test/real-download.integration.test.ts @@ -146,7 +146,7 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => { id: 'crop', url: 'https://www.youtube.com/watch?v=jNQXAC9IVRw', // "Me at the zoo", 19s kind: 'audio', - quality: 'Best (MP3)' + quality: 'Best' } const options = { ...DEFAULT_DOWNLOAD_OPTIONS, @@ -181,7 +181,7 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => { id: 'sb', url, kind: 'audio', - quality: 'Best (MP3)' + quality: 'Best' } const options = { ...DEFAULT_DOWNLOAD_OPTIONS,