refactor(player): delete the webview video path; mpv selects its own tracks

DR-235 phase 3. Every video renderer is native now: mpv on Linux and
Windows, ExoPlayer on Android, all drawing behind the transparent
webview. The HTML5 <video> path is gone, not bypassed:

- Frontend: hls.js, Html5PlayerAdapter and its compatibility shim, the
  createAdapter factory, streamTransport, hlsRecovery, timeTracking,
  videoFit, the <video>/<track> markup and every element handler in
  VideoPlayer (3277 -> 2144 lines), the experimentalNativeVideo store
  and its Settings toggle, webviewVideoFallback/supportsNativeVideo, and
  the setHtml5VideoState PiP bridge call. NativePlayerAdapter is the one
  video adapter; webview audio gets its own adapter kind.
- Rust: use_html5 dropped from player_seek_video,
  player_switch_audio_track and player_set_stream_quality with the
  Html5* strategies and ReloadStream responses; use_html5_element and
  VideoBackend dropped from PlayerStatus; player_play_item always loads
  the backend (set_current_item removed); Capabilities::webview removed;
  the WebKitGTK GStreamer/VAAPI setup (and its gst-inspect spawn) removed.
- Android: the HTML5 video state in PictureInPictureManager and
  ScreenWakeManager, and the bridge method feeding it.
- CSP: connect-src loses http:/https: and worker-src loses blob: -
  both existed for hls.js; with it gone they were only an exfiltration
  channel and a blob worker for injected script. A test now keeps them
  out.

mpv takes over what the <video> element did (mpv_tracks, UT-275):
subtitles are the WebVTT list the play request carries, queued on
sub-files and selected by position in that list, starting off; audio
tracks are selected by position in the file; sid/aid are reset before
each load. Without this, Linux video had no subtitle selection and a
direct-play audio switch failed since mpv became its renderer.

Verified: Rust 948 passing, and the same 948 cross-compiled for Windows
under wine against the shipped DLL (track tests included); frontend
1111 passing; aarch64 debug APK builds. Lint warnings 158 -> 146, CI
ratchet tightened to match. Not yet seen on Windows hardware.
This commit is contained in:
2026-09-24 23:11:17 -04:00
parent bb3ab1edd7
commit 1677f5f299
69 changed files with 4014 additions and 7330 deletions
+12 -4
View File
@@ -54,21 +54,29 @@ describe("tauri.conf.json CSP", () => {
expect(csp["img-src"]).toContain("asset:");
expect(csp["img-src"]).toContain("http://asset.localhost");
expect(csp["media-src"]).toContain("asset:");
// hls.js: MSE object URLs, and its demuxer worker built from a blob.
expect(csp["media-src"]).toContain("blob:");
expect(csp["worker-src"]).toContain("blob:");
// The token-guarded loopback media server (DR-137).
expect(csp["media-src"]).toContain("http://127.0.0.1:*");
// Tauri's invoke transport.
expect(csp["connect-src"]).toContain("ipc:");
expect(csp["connect-src"]).toContain("http://ipc.localhost");
// The user's Jellyfin server: an arbitrary run-time origin, http on a LAN.
for (const directive of ["img-src", "media-src", "connect-src"]) {
for (const directive of ["img-src", "media-src"]) {
expect(csp[directive]).toContain("http:");
expect(csp[directive]).toContain("https:");
}
});
// The page makes no network requests of its own — all traffic goes through
// Rust — so `connect-src` is IPC only. It allowed any http(s) host while
// hls.js fetched segments in the page; with hls.js deleted (DR-235) that
// grant was only an exfiltration channel for injected script. Likewise the
// blob worker was hls.js' demuxer.
it("gives injected script no network egress and no blob workers", () => {
expect(csp["connect-src"]).not.toContain("http:");
expect(csp["connect-src"]).not.toContain("https:");
expect(csp["worker-src"]).not.toContain("blob:");
});
it("never widens a data directive into script execution", () => {
for (const [name, sources] of Object.entries(csp)) {
if (name === "script-src" || name === "worker-src") {