e5d3cc06f29e2e1da4f495124806ad2e78e88c91
Locking the screen killed audio on video playback even with the background-audio toggle armed. configureWebViewForMedia() ran from onCreate's delayed post AND from every onResume, re-calling addJavascriptInterface on each pass — five times in a 45s session. WebView binds injected objects at page-load time, so re-injecting over a live page leaves JS holding a stale proxy: the object stays truthy (passing the `bridge()?.` optional chain) while its methods vanish. Logcat showed 66 "WebView: Unknown object" errors and, in JS, "TypeError: setEnabled is not a function". So the toggle turned blue but never reached native. backgroundAudioEnabled stayed false, onStop never dispatched 'jellytau-background', the handoff never ran, and audio stopped the instant the screen locked. PiP and audio focus broke identically. - Register the bridges exactly once per WebView (identity-compared), and split the idempotent settings/chrome-client work into configureWebViewSettings() so it still runs on every resume. - Forward WebView console output to logcat as "JellyTauWeb". The frontend was previously invisible to adb, which is what made this bug so hard to place; keep it for the next boundary-spanning diagnosis. - setBackgroundAudioEnabled now reports whether native was actually reached instead of silently no-oping, so a dead bridge can never again masquerade as an armed toggle. Removing the re-injection revived a latent conflict it had been masking: the focus calls started working, and three AUDIOFOCUS_GAIN requesters inside one uid began fighting — MainActivity, ExoPlayer, and Chromium's own AudioFocusDelegate. The grant was followed ~45ms later by AUDIOFOCUS_LOSS, whose handler paused playback, so arming background audio (or just pressing play) paused the video in a loop. WebView already manages focus for <video>. Drop the redundant AndroidAudioFocus bridge, its listeners and its helpers entirely, and leave focus to whichever engine is actually rendering — consistent with the player-is-authoritative principle. Also drops the dead AndroidBackgroundAudio.isSupported() probe, unused since the button gate moved to platform(). TRACES: UR-040 | IR-025, DR-051 | UT-062

JellyTau
A cross-platform Jellyfin client built with Tauri, SvelteKit, and TypeScript.
Business logic lives in a Rust backend; a UI-rich Svelte frontend handles presentation and talks to it over Tauri's IPC. Targets Linux (libmpv) and Android (ExoPlayer).
Getting Started
This project uses bun as its package manager.
# Activate the Rust environment (fish shell)
source "$HOME/.cargo/env.fish"
# Install dependencies
bun install
# Run in development
bun run tauri dev
# Type-check the frontend
bun run check
# Build for Linux
bun run tauri build
# Build for Android
bun run tauri android build
For the full set of build, test, and Android helper scripts, see scripts/README.md.
Documentation
| Topic | Location |
|---|---|
| Architecture overview & subsystem docs | docs/architecture/ |
| Requirements, traceability & technical debt | docs/requirements.md |
| Build & release process | docs/build-release.md |
| Docker builds | docs/build/docker.md |
| Traceability tooling & CI | docs/traceability.md, docs/traceability-ci.md |
| Release checklist | docs/release-checklist.md |
| UX flows | docs/ux-flows.md |
Recommended IDE Setup
VS Code + Svelte + Tauri + rust-analyzer.
License
MIT
Releases
37
JellyTau v0.10.1
Latest
Languages
Rust
49.1%
TypeScript
26.6%
Svelte
17.1%
Kotlin
4.9%
Shell
1.7%
Other
0.5%