chore(release): v0.11.5
🏗️ Build and Test JellyTau / Run Tests (push) Skipped
🏗️ Build and Test JellyTau / Android Compile Check (push) Skipped
🏗️ Build and Test JellyTau / Supply Chain (push) Successful in 3m41s
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m20s
Traceability Validation / Check Requirement Traces (push) Successful in 11s
Build & Release / Run Tests (push) Successful in 14m44s
Build & Release / Build Linux (push) Successful in 20m30s
Build & Release / Build Windows (push) Successful in 15m38s
Build & Release / Build Android (push) Successful in 30m30s
Build & Release / Create Release (push) Successful in 37s

One fix since v0.11.4: a video in a picture-in-picture window no longer drops
to audio-only partway through, replaying from wherever the picture had been
when the window opened.

Two independent faults had to line up for it. The player's position variable is
written only by a requestAnimationFrame loop while playing, and RAF stops for a
document that is not being rendered -- which an Android activity behind a PiP
window is not; the `timeupdate` handler that would have covered the gap had
gated itself on `!isPlaying` since the first commit. And PiP and the
background-audio handoff, nominally alternatives, could both be armed at once,
with a single `isInPictureInPictureMode` sample taken inside onStop() standing
between them.

The frozen position was not confined to the handoff: the seek bar, resume
points and the progress reported to Jellyfin all read the same variable, so all
three stood still for as long as a PiP window was open.

Version stamped with scripts/set-version.sh. defect-windows.md records DR-265
under the present-since/reachable-since gap: defective since v0.0.1, but only
hittable once PiP started working on the HTML5 path in v0.5.3.
This commit is contained in:
2026-08-27 17:58:06 +02:00
parent c0399e4ebd
commit 8a04a6fad0
7 changed files with 37 additions and 6 deletions
+23
View File
@@ -9,6 +9,29 @@ generated trace matrix lives in [docs/traceability.md](docs/traceability.md).
For how long each fixed defect had been shipping before it was found, see For how long each fixed defect had been shipping before it was found, see
[docs/defect-windows.md](docs/defect-windows.md). [docs/defect-windows.md](docs/defect-windows.md).
## v0.11.5
### 🐛 Fixes
- **A video in a picture-in-picture window stays a video.** Watching in a PiP
window would sometimes drop to audio only, and the audio would pick up from
wherever the video had been when the window opened — while the picture itself
had carried on well past that. Two faults, both needed to produce it. The
player's idea of where it is in the video is kept by a loop that only runs
while the app is drawing to the screen, and behind a PiP window it is not:
the position quietly stopped advancing the moment the window opened, and the
one other source that could have kept it current had been written to switch
itself off during playback. Separately, PiP and the "keep the audio playing in
the background" toggle are meant to be alternatives, but only the toggle
enforced that — the PiP button could still be pressed with both armed, and the
single moment-in-time check meant to tell them apart is not always right about
whether a window is open. Opening PiP now turns background audio off, the app
trusts its own record of the window as well as the system's, and the position
keeps advancing whether or not anything is being drawn. The frozen position
also affected the seek bar, resume points and watch progress reported to the
server for as long as a PiP window was open. (UR-004, UR-040, UR-041 →
DR-265, DR-266)
## v0.11.4 ## v0.11.4
### 🐛 Fixes ### 🐛 Fixes
+9 -1
View File
@@ -17,11 +17,17 @@ row can be re-checked or disputed:
## Present since the first release ## Present since the first release
Fifteen defects date to the initial proof of concept (v0.0.1, 2026-06-23) and Sixteen defects date to the initial proof of concept (v0.0.1, 2026-06-23) and
shipped for between two weeks and two months before anyone hit them. shipped for between two weeks and two months before anyone hit them.
That is the dominant pattern here: not regressions, but original assumptions that That is the dominant pattern here: not regressions, but original assumptions that
went unexercised until a later feature leaned on them. went unexercised until a later feature leaned on them.
DR-265 is the clearest example of the "present since" / "reachable since" gap
this file warns about: the `!isPlaying` gate has been there since the first
commit, but nothing paused the document underneath a playing `<video>` until PiP
started working on the HTML5 path in v0.5.3. Defective for ~9 weeks, hittable
for ~2.
| Defect | Present since | Fixed in | Shipped broken for | How dated | | Defect | Present since | Fixed in | Shipped broken for | How dated |
|---|---|---|---|---| |---|---|---|---|---|
| `AudioStreamIndex=0` pinned the video stream as the audio track (DR-140) | v0.0.1 | **v0.4.6** | ~7 weeks | pickaxe | | `AudioStreamIndex=0` pinned the video stream as the audio track (DR-140) | v0.0.1 | **v0.4.6** | ~7 weeks | pickaxe |
@@ -40,6 +46,7 @@ went unexercised until a later feature leaned on them.
| Hero banner auto-rotation never restarted after a manual swipe (DR-038) | v0.0.1 | **v0.9.1** | ~8.5 weeks | pickaxe | | Hero banner auto-rotation never restarted after a manual swipe (DR-038) | v0.0.1 | **v0.9.1** | ~8.5 weeks | pickaxe |
| Audio-track change asked the player to select a track the transcode never carried (DR-258) | v0.0.1 | **v0.11.1** | ~2 months | pickaxe | | Audio-track change asked the player to select a track the transcode never carried (DR-258) | v0.0.1 | **v0.11.1** | ~2 months | pickaxe |
| Subtitle URL missing its `Stream.` route segment, so every fetch 404ed (DR-259) | v0.0.1 | **v0.11.1** | ~2 months | pickaxe | | Subtitle URL missing its `Stream.` route segment, so every fetch 404ed (DR-259) | v0.0.1 | **v0.11.1** | ~2 months | pickaxe |
| `timeupdate` gated on `!isPlaying`, so a paused activity froze the position (DR-265) | v0.0.1 | **v0.11.5** | ~9 weeks | pickaxe |
### Why they took so long to surface ### Why they took so long to surface
@@ -86,6 +93,7 @@ silently correct an out-of-range index — which is exactly why it was reported
| Positions reported as 0 before the first tick, and always 0 for webview media (DR-178/179/180) | v0.5.3 | **v0.5.5** | feature (DR-159's tick boundary) | | Positions reported as 0 before the first tick, and always 0 for webview media (DR-178/179/180) | v0.5.3 | **v0.5.5** | feature (DR-159's tick boundary) |
| Length-less handoff transcode left to the player's own load-error retry, which can only restart it (DR-203) | v0.0.16 | **v0.8.2** | feature (the handoff's progressive-mp3 choice) | | Length-less handoff transcode left to the player's own load-error retry, which can only restart it (DR-203) | v0.0.16 | **v0.8.2** | feature (the handoff's progressive-mp3 choice) |
| Recently Added trusted the server to group new tracks — `GroupItems=true` only groups a track whose parent chain resolves a `MusicAlbum`, and older servers ignore it | v0.5.1 | **v0.11.4** | feature (the v0.5.1 fix for the same symptom) | | Recently Added trusted the server to group new tracks — `GroupItems=true` only groups a track whose parent chain resolves a `MusicAlbum`, and older servers ignore it | v0.5.1 | **v0.11.4** | feature (the v0.5.1 fix for the same symptom) |
| PiP and the background-audio handoff both armable, decided by one `isInPictureInPictureMode` sample (DR-266) | v0.5.3 | **v0.11.5** | feature (PiP on the HTML5 path, beside a toggle that had shipped in v0.0.16) |
Three of these are worth separating out, because the defect is not a mistake in Three of these are worth separating out, because the defect is not a mistake in
the code so much as **plumbing that was built and never connected**: the code so much as **plumbing that was built and never connected**:
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jellytau", "name": "jellytau",
"version": "0.11.4", "version": "0.11.5",
"description": "A cross-platform Jellyfin client built with Tauri, SvelteKit and Rust.", "description": "A cross-platform Jellyfin client built with Tauri, SvelteKit and Rust.",
"author": "Duncan Tourolle <duncan@tourolle.paris>", "author": "Duncan Tourolle <duncan@tourolle.paris>",
"license": "MIT", "license": "MIT",
+1 -1
View File
@@ -8,7 +8,7 @@
# tarball/VCS URL and drop the local-copy prepare() step. # tarball/VCS URL and drop the local-copy prepare() step.
pkgname=jellytau pkgname=jellytau
pkgver=0.11.4 pkgver=0.11.5
pkgrel=1 pkgrel=1
pkgdesc="A cross-platform Jellyfin client" pkgdesc="A cross-platform Jellyfin client"
arch=('x86_64') arch=('x86_64')
+1 -1
View File
@@ -2181,7 +2181,7 @@ dependencies = [
[[package]] [[package]]
name = "jellytau" name = "jellytau"
version = "0.11.4" version = "0.11.5"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"async-trait", "async-trait",
+1 -1
View File
@@ -4,7 +4,7 @@ name = "jellytau"
# `player-conformance`, and a second binary makes a bare `cargo run` — # `player-conformance`, and a second binary makes a bare `cargo run` —
# which `tauri dev` issues — ambiguous. # which `tauri dev` issues — ambiguous.
default-run = "jellytau" default-run = "jellytau"
version = "0.11.4" version = "0.11.5"
description = "A cross-platform Jellyfin client" description = "A cross-platform Jellyfin client"
authors = ["Duncan Tourolle <duncan@tourolle.paris>"] authors = ["Duncan Tourolle <duncan@tourolle.paris>"]
license = "MIT" license = "MIT"
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "JellyTau", "productName": "JellyTau",
"version": "0.11.4", "version": "0.11.5",
"identifier": "com.dtourolle.jellytau", "identifier": "com.dtourolle.jellytau",
"build": { "build": {
"beforeDevCommand": "bun run dev", "beforeDevCommand": "bun run dev",