fix(player): mpv draws all Linux video, and no longer runs text from a URL

Security (DR-298, DR-299):
- The pinned libmpv crate's Mpv::command joins its arguments and calls
  mpv_command_string, which parses `;` as a command separator. Stream
  URLs carry server-controlled ids and TranscodingUrl, and a download's
  file:// path carries its track title, so a crafted title could run any
  mpv command, `run` included. Every call now goes through
  mpv_command::command, an argv built for mpv_command. The same parse
  broke loadfile for every downloaded title containing a space.
- mpv's tls-verify defaults to no, and its URLs carry the ApiKey. Every
  handle is now hardened with tls-verify=yes and ytdl=no before its
  first loadfile, and fails construction if it cannot be.

Linux video (DR-235 phase 1):
- native_video::enabled() is unconditional on Linux; the
  JELLYTAU_NATIVE_VIDEO opt-in is retired. No platform reports a
  webview video fallback, so the Settings switch no longer appears.
  Windows keeps the webview element until mpv reaches it (DR-237).
- The Linux device profile is unchanged (still h264, DR-234), so this
  ships the configuration that was tested under the env var.
This commit is contained in:
2026-09-24 20:38:32 -04:00
parent fd1277746d
commit 9d9d81bef3
13 changed files with 298 additions and 161 deletions
+8 -5
View File
@@ -2,8 +2,8 @@
A cross-platform Jellyfin client. Business logic lives in a Rust backend
(`src-tauri/`); a SvelteKit + TypeScript frontend (`src/`) handles presentation
and talks to it over Tauri v2 IPC. Targets **Linux** (libmpv, WebKitGTK HTML5
`<video>` for transcoded playback) and **Android** (ExoPlayer).
and talks to it over Tauri v2 IPC. Targets **Linux** (libmpv for audio and video) and
**Android** (ExoPlayer); Windows still renders video in the webview `<video>`.
Package manager is **bun**.
@@ -151,9 +151,12 @@ output as a reviewed draft, not a final changelog.
- **Svelte frontend** (`src/`) — presentation only. Stores in
`src/lib/stores/`, API wrappers in `src/lib/api/`, components in
`src/lib/components/`.
- **Playback layers** — Linux uses libmpv for direct playback and a WebKitGTK
HTML5 `<video>` element for HLS-transcoded (h264) streams; Android uses
ExoPlayer with a foreground media service + `MediaSessionCompat`.
- **Playback layers** — Linux uses libmpv for audio and video (mpv draws video
beneath the transparent webview); Windows still uses the webview HTML5
`<video>` element for video; Android uses ExoPlayer with a foreground media
service + `MediaSessionCompat`. Every mpv command goes through
`player/mpv_command.rs` (argv, never a command string) and every handle is
hardened (`tls-verify=yes`, `ytdl=no`) — see DR-298/DR-299.
- **tauri-specta** generates TypeScript bindings and typed events from the Rust
command/event definitions (registered via the Builder in `src-tauri/src/lib.rs`).