diff --git a/CODE-AUDIT.md b/CODE-AUDIT.md index 99273cc..3c28ddf 100644 --- a/CODE-AUDIT.md +++ b/CODE-AUDIT.md @@ -438,7 +438,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n ref; changing the default in Settings while on the Downloads tab isn't reflected until reload. - [ ] **L29 — UI constant in the store.** `QUALITY_OPTIONS` lives in `store/downloads.ts` yet is a presentational constant imported by views — couples UI to the store module. -- [ ] **L30 — Redundant `loading="lazy"`** on `MediaThumb` images already inside a virtualized +- [x] **L30 — Redundant `loading="lazy"`** on `MediaThumb` images already inside a virtualized list (the virtualizer only mounts visible rows). - [ ] **L31 — Two theme switchers.** Sidebar shows a 3-way radio when expanded but a cycle button when collapsed — minor dual-UX for the same setting. @@ -465,7 +465,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n URL (surfaced by the NSIS installer). - [x] **L42 — `package.json` has no `license` field** (ships LGPL ffmpeg + GPL aria2c). - [x] **L43 — `package.json` has no `repository` field** (real repo is the Gitea instance). -- [ ] **L44 — Vestigial lint excludes.** `electron-builder.yml` excludes `.eslintrc`/`.prettierrc` +- [x] **L44 — Vestigial lint excludes.** `electron-builder.yml` excludes `.eslintrc`/`.prettierrc` 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". @@ -493,7 +493,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n - [x] **L58 — `chooseFolder` passes the macOS-only `createDirectory` property** — dead option on Windows. - [ ] **L59 — `THEME_BACKGROUND` (index.ts) duplicates `pageBackground` (theme.ts)** — two hand-synced color constants (a "keep in sync" comment guards them). -- [ ] **L60 — `'external-url'` channel name lacks the `category:` prefix** every other IPC channel uses. +- [x] **L60 — `'external-url'` channel name lacks the `category:` prefix** every other IPC channel uses. - [ ] **L61 — `taskbarProgress` is the lone `ipcMain.on`** (fire-and-forget) amid all-`invoke` channels. - [ ] **L62 — "Best available" synthetic format hardcodes `ext:'mp4'`/`hasAudio:true`** (probe.ts) — mislabels when the chosen container is mkv/webm. @@ -555,7 +555,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n *Round 5 (2026-06-29) — code-level micro-inconsistencies & polish:* -- [ ] **L90 — Two idioms for "value in const array."** [settings.ts](src/main/settings.ts) `sanitizeOptions` +- [x] **L90 — Two idioms for "value in const array."** [settings.ts](src/main/settings.ts) `sanitizeOptions` uses `ARR.includes(x as never)` (L116–120) while `setSettings` uses `(ARR as readonly string[]).includes(x as string)` (L275/323). Pick one. - [x] **L91 — Unsafe tuple cast / fragile encoding.** `value.split('|') as [MediaKind, string]` ([SettingsView.tsx](src/renderer/src/components/SettingsView.tsx):411) trusts a `'|'`-joined diff --git a/electron-builder.yml b/electron-builder.yml index 653a267..763f6a5 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -23,7 +23,7 @@ files: - '!**/.vscode/*' - '!src/*' - '!electron.vite.config.{js,ts,mjs,cjs}' - - '!{.eslintignore,.eslintrc.cjs,.eslintrc.js,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' + - '!{eslint.config.js,.prettierrc,dev-app-update.yml,CHANGELOG.md,README.md}' - '!{.env,.env.*,.npmrc,pnpm-lock.yaml,package-lock.json}' - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' - '!*.tsbuildinfo' diff --git a/src/main/settings.ts b/src/main/settings.ts index 4b3199d..7876529 100644 --- a/src/main/settings.ts +++ b/src/main/settings.ts @@ -16,7 +16,10 @@ import { isYtdlpUpdateChannel, type Settings, type DownloadOptions, - type SponsorBlockCategory + type SponsorBlockCategory, + type AudioFormat, + type VideoContainer, + type VideoCodecPref } from '@shared/ipc' const DEFAULTS: Settings = { @@ -121,12 +124,16 @@ function sanitizeOptions(input: unknown): DownloadOptions { ) as SponsorBlockCategory[]) : d.sponsorBlockCategories return { - audioFormat: AUDIO_FORMATS.includes(o.audioFormat as never) ? o.audioFormat! : d.audioFormat, - videoContainer: VIDEO_CONTAINERS.includes(o.videoContainer as never) - ? o.videoContainer! + audioFormat: (AUDIO_FORMATS as readonly string[]).includes(o.audioFormat as string) + ? (o.audioFormat as AudioFormat) + : d.audioFormat, + videoContainer: (VIDEO_CONTAINERS as readonly string[]).includes(o.videoContainer as string) + ? (o.videoContainer as VideoContainer) : d.videoContainer, - preferredVideoCodec: VIDEO_CODECS.includes(o.preferredVideoCodec as never) - ? o.preferredVideoCodec! + preferredVideoCodec: (VIDEO_CODECS as readonly string[]).includes( + o.preferredVideoCodec as string + ) + ? (o.preferredVideoCodec as VideoCodecPref) : d.preferredVideoCodec, formatSort: typeof o.formatSort === 'string' ? o.formatSort.trim() : d.formatSort, embedSubtitles: bool(o.embedSubtitles, d.embedSubtitles), diff --git a/src/renderer/src/components/MediaThumb.tsx b/src/renderer/src/components/MediaThumb.tsx index bc1e0fd..727d66c 100644 --- a/src/renderer/src/components/MediaThumb.tsx +++ b/src/renderer/src/components/MediaThumb.tsx @@ -53,13 +53,7 @@ export function MediaThumb({ style={{ backgroundColor: colors.bg, color: colors.fg }} > {showImg ? ( - setFailedSrc(src ?? null)} - /> + setFailedSrc(src ?? null)} /> ) : kind === 'audio' ? ( ) : ( diff --git a/src/shared/ipc.ts b/src/shared/ipc.ts index 3085770..ffd98cc 100644 --- a/src/shared/ipc.ts +++ b/src/shared/ipc.ts @@ -56,7 +56,7 @@ export const IpcChannels = { preloadBridgeFailure: 'preload:bridge-failure', /** main → renderer push channel: a URL handed to AeroFetch from outside the app * (the aerofetch:// protocol, or a .url file via Explorer's "Send to" menu) */ - externalUrl: 'external-url', + externalUrl: 'app:external-url', // --- Sources & media-manager indexing (Pinchflat-style, see ROADMAP-PINCHFLAT.md) --- sourcesList: 'sources:list', sourceIndex: 'sources:index',