diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index 2f5bade..92b597f 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -469,7 +469,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n but there's no ESLint/Prettier config, script, or dependency — no enforced style tooling. - [x] **L45 — Three self-descriptions** drift: pkg `description` "A yt-dlp frontend for Windows" vs builder `copyright` "yt-dlp frontend" vs Sidebar caption "yt-dlp frontend". -- [ ] **L46 — yt-dlp-missing error copy differs across 4 modules** (download/ytdlp/probe/indexer): +- [x] **L46 — yt-dlp-missing error copy differs across 4 modules** (download/ytdlp/probe/indexer): "Reinstall AeroFetch, or drop…" vs "Download it into resources/bin/…" vs "Drop it into resources/bin/." - [x] **L47 — `probeMeta` 30s timeout returns null silently** — no surfaced message, unlike every other yt-dlp timeout ("Timed out …"). @@ -510,12 +510,12 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n (`typeof crypto !== 'undefined'` is always true) — dead defensive branch (see M7). *Fixed with M7: the branch now lives once in `newId` (kept so the fn is total in any host) and is covered by a test that stubs `crypto` to exercise it.* -- [ ] **L71 — Settings folder inputs are `readOnly`** with only a Browse button — no way to paste a +- [x] **L71 — Settings folder inputs are `readOnly`** with only a Browse button — no way to paste a known path. - [x] **L72 — History re-download drops the thumbnail** (passes only title/channel), so the re-queued row loses its thumbnail until re-probed. - [ ] **L73 — Two verbs for the same probe action** — DownloadBar "Fetch" vs LibraryView "Index". -- [ ] **L74 — Accent swatches are triple-labeled** (`aria-pressed` + `aria-label` + `title`). +- [x] **L74 — Accent swatches are triple-labeled** (`aria-pressed` + `aria-label` + `title`). - [x] **L75 — Update-token field always visible** in the Software-update card, even when no update is pending — buries an advanced/rarely-needed input. - [x] **L76 — Duplicate-warning may show a placeholder title** — `setDup(existing.title)` can be the diff --git a/src/main/binaries.ts b/src/main/binaries.ts index 517dcfe..81be1fb 100644 --- a/src/main/binaries.ts +++ b/src/main/binaries.ts @@ -80,6 +80,10 @@ export function getFfprobePath(): string { return join(getBinDir(), 'ffprobe.exe') } +/** User-facing error shown whenever yt-dlp.exe is not found at startup. */ +export const YTDLP_MISSING_MSG = + 'yt-dlp.exe is missing. Open Settings → Software update to re-download it.' + /** Optional bundled external downloader; absent unless dropped into resources/bin. */ export function getAria2cPath(): string { return join(getBinDir(), 'aria2c.exe') diff --git a/src/main/download.ts b/src/main/download.ts index f0ea523..d1c6ec3 100644 --- a/src/main/download.ts +++ b/src/main/download.ts @@ -10,7 +10,8 @@ import { getFfmpegPath, getFfprobePath, getSystem32Path, - getAppIconImage + getAppIconImage, + YTDLP_MISSING_MSG } from './binaries' import { getSettings, getDownloadArchivePath, getDefaultMediaDir } from './settings' import { ensureManagedYtdlp } from './ytdlp' @@ -225,7 +226,7 @@ export function startDownload(wc: WebContents, opts: StartDownloadOptions): Star if (!existsSync(ytdlp)) { return { ok: false, - error: `yt-dlp.exe is missing and couldn't be restored from the bundle.\nReinstall AeroFetch, or drop yt-dlp.exe into resources/bin/ (see the README there).` + error: YTDLP_MISSING_MSG } } // ffmpeg is used by nearly every download (merge, audio extract, thumbnail/ diff --git a/src/main/indexer.ts b/src/main/indexer.ts index 0d16a5e..aa9c4db 100644 --- a/src/main/indexer.ts +++ b/src/main/indexer.ts @@ -11,7 +11,7 @@ import { execFile } from 'child_process' import { existsSync } from 'fs' -import { getYtdlpPath } from './binaries' +import { getYtdlpPath, YTDLP_MISSING_MSG } from './binaries' import { cleanError } from './log' import { assertHttpUrl } from './url' import { @@ -90,7 +90,7 @@ export async function indexSource( return { ok: false, error: (e as Error).message } } if (!existsSync(getYtdlpPath())) { - return { ok: false, error: 'yt-dlp.exe not found. Drop it into resources/bin/.' } + return { ok: false, error: YTDLP_MISSING_MSG } } const cls = classifySource(url) diff --git a/src/main/probe.ts b/src/main/probe.ts index 32ea2ce..3bef06e 100644 --- a/src/main/probe.ts +++ b/src/main/probe.ts @@ -1,6 +1,6 @@ import { execFile } from 'child_process' import { existsSync } from 'fs' -import { getYtdlpPath } from './binaries' +import { getYtdlpPath, YTDLP_MISSING_MSG } from './binaries' import { fmtBytes } from './lib/formatters' import { cleanError } from './log' import { assertHttpUrl } from './url' @@ -115,7 +115,7 @@ export function probeMedia(url: string): Promise { if (!existsSync(ytdlp)) { return Promise.resolve({ ok: false, - error: `yt-dlp.exe not found at ${ytdlp}\nDrop it into resources/bin/ (see the README there).` + error: YTDLP_MISSING_MSG }) } let target: string diff --git a/src/main/ytdlp.ts b/src/main/ytdlp.ts index 74f1808..ef9b23d 100644 --- a/src/main/ytdlp.ts +++ b/src/main/ytdlp.ts @@ -1,7 +1,7 @@ import { execFile } from 'child_process' import { existsSync, mkdirSync, copyFileSync } from 'fs' import { dirname } from 'path' -import { getYtdlpPath, getBundledYtdlpPath } from './binaries' +import { getYtdlpPath, getBundledYtdlpPath, YTDLP_MISSING_MSG } from './binaries' import { getSettings, setSettings } from './settings' import { shouldAutoCheckYtdlp } from './ytdlpPolicy' import { @@ -39,7 +39,7 @@ export function getYtdlpVersion(): Promise { if (!existsSync(ytdlpPath)) { return Promise.resolve({ ok: false, - error: `yt-dlp.exe not found at ${ytdlpPath}\nDownload it into resources/bin/ (see the README there).` + error: YTDLP_MISSING_MSG }) } @@ -85,7 +85,7 @@ export function updateYtdlp(channel: YtdlpUpdateChannel): Promise
} + onChange={(_, d) => update({ videoDir: d.value })} />