v0.2.9
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m33s
Traceability Validation / Check Requirement Traces (push) Successful in 25s
🏗️ Build and Test JellyTau / Run Tests (push) Successful in 17m25s
Build & Release / Run Tests (push) Successful in 6m7s
🏗️ Build and Test JellyTau / Android Compile Check (push) Successful in 8m38s
Build & Release / Build Linux (push) Successful in 19m23s
Build & Release / Build Windows (push) Successful in 13m43s
Build & Release / Build Android (push) Successful in 29m47s
Build & Release / Create Release (push) Successful in 19s
An episode played audio-only while the app was backgrounded stalled at the episode boundary instead of advancing, and ExoPlayer parked in STATE_ENDED — where any later play intent (lockscreen, headset, Bluetooth reconnect) replays the ended item, surfacing as the episode randomly restarting. End-of-playback is dispatched from two places and they disagreed. The Android JNI callback carried the background-audio branch but can never reach it: load_and_play sets EndReason::NewTrackLoaded at every load and nothing clears it, so the first real end consumes it and the decision is always Stop. The call that actually decides is the frontend's echo of the resulting PlaybackEnded into player_on_playback_ended — and that path had no background-audio case at all, so it started a countdown whose advance is a webview goto() that cannot start audio while backgrounded. Both dispatchers now share PlayerController::auto_advance_to_next_episode, so they cannot drift apart again. The handoff base offset moves from the BackgroundAudioOffset Tauri state onto the controller, and the advance clears it: the next episode's stream is built without StartTimeTicks, so its timeline is already absolute and a stale base made player_exit_background_audio return old_base + position_in_new_episode. Unreachable until the advance actually worked. Tests (red before the fix): - test_auto_advance_background_audio_episode_advances_in_backend - test_auto_advance_foreground_video_episode_uses_countdown - test_advance_to_next_episode_audio_only_clears_handoff_base Bump to 0.2.9.

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
38
JellyTau v0.11.0
Latest
Languages
Rust
50.7%
TypeScript
25.8%
Svelte
16.4%
Kotlin
4.8%
Shell
1.7%
Other
0.5%