feat: subtitles, delete-all, auto refresh, and menu cleanup

Subtitles: a language preference in Settings drives what is shown and
what is downloaded. yt-dlp saves WebVTT sidecars next to each download,
including YouTube's auto-generated track, and the player attaches them
as <track> elements so they work offline. Sidecars are removed with
their video, and by Delete all.

WebVTT rather than muxed subtitle streams because WebKit reads a <track>
reliably and largely ignores subtitle tracks inside an MP4.

Downloads in progress now appear under the downloaded-only filter, so a
download you just started does not vanish from the list you are watching
it in. That view also gains a Delete all, behind a confirmation naming
what goes.

The feed refreshes on launch and whenever the player closes, so the
Refresh button is only for staleness.

Player: Delete moved to the footer and shortened, Open on YouTube is now
an external-link icon.

Removes the Edit and Help menus. Cut/Copy/Paste move to the app menu,
without which their shortcuts would stop working in the search field.
The webview context menu is suppressed outside text fields — its Reload
and Back items act on a page the app does not present as one.

Settings now warns that 4K AV1 plays back with artefacts: the files
decode cleanly in ffmpeg, so it is the built-in decoder, not the
download.
This commit is contained in:
vincent
2026-08-29 13:25:17 +02:00
parent 73f12cfac1
commit 557467baad
12 changed files with 458 additions and 43 deletions
+12
View File
@@ -110,3 +110,15 @@ export const STREAM_QUALITIES: Array<{ value: Quality; label: string }> = [
{ value: "720", label: "720p" },
{ value: "480", label: "480p" },
];
/** Preferred subtitle language: shown when available, and downloaded. */
export const SUB_LANGS: Array<{ value: string; label: string }> = [
{ value: "off", label: "None" },
{ value: "en", label: "English" },
{ value: "nl", label: "Nederlands" },
{ value: "de", label: "Deutsch" },
{ value: "fr", label: "Français" },
{ value: "es", label: "Español" },
{ value: "it", label: "Italiano" },
{ value: "pt", label: "Português" },
];