diff --git a/CHANGELOG.md b/CHANGELOG.md index ec8153b4..a0e98308 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,69 @@ Entries are grouped by the capability they change, not by commit. Requirement IDs in parentheses point at [docs/requirements.md](docs/requirements.md); the generated trace matrix lives in [docs/traceability.md](docs/traceability.md). +## v0.4.0 + +### ✨ Features + +- **Favourites, across libraries.** A `/library/favorites` page renders + favourites from every library with All / Movies / Shows / Music scope tabs, + reusing the standard grid so card shape still follows the media — a mixed All + tab reads as posters, squares and thumbnails side by side. Home carries + favourite rows below Recently Added, and a row with no items does not render + at all, so a fresh install shows no empty rows. Server favourite state is + mirrored into the local database as results are cached, so offline browsing + sees the same favourites as the server; a toggle made offline is never + overwritten by a stale server value before it has been pushed. + (UR-067, UR-069 → DR-113, DR-114, DR-115, DR-117, DR-118) + +- **Search answers from the local index.** The instant leg read only downloaded + items, so with no downloads it returned nothing and every keystroke fell + through to a full `Recursive=true` server query. It now reads the whole synced + catalog through the same availability CTE `get_items` uses, gated on the same + `include_catalog_browse` flag, so search and browse cannot diverge. The index + also gained MusicArtist, Playlist and People — the very groups search sorts + results into. Re-indexing moved from a frontend startup call to a Rust + background task with a 6h TTL, so a long session no longer searches a stale + catalog. (UR-065 → DR-108, DR-110, DR-111) + +### 🐛 Fixes + +- **Playback no longer restarts an episode at random on a flaky connection.** + Background audio-only playback of a video streams a progressive mp3 transcode + over plain HTTP, which is chunked and so declares no length: when the + connection dropped mid-episode, ExoPlayer saw end-of-input and reported + `STATE_ENDED`, indistinguishable from the real end. The app ran its + end-of-episode logic mid-episode and playback parked in `STATE_ENDED`, where + the next play intent from the lockscreen, notification or a Bluetooth + reconnect seeks an ended player to position 0 — surfacing as "the episode + randomly restarted". The item's runtime is now what decides: an end reported + well short of it re-opens the stream where it stopped. (UR-040 → DR-129) + +- **A network hiccup no longer kills playback outright.** Music and video + declare a length, so a cut connection reaches them as an *error* rather than a + phantom end — and every error stopped the player. A recoverable error now gets + one bounded attempt at re-opening the stream where it stopped, with a growing + backoff, leaving the rest of the queue intact. On Linux, MPV additionally + reconnects inside the demuxer so ordinary blips never surface at all, and + `EndFile(ERROR)` — previously a bare log line that left playback halted while + the UI still showed "playing" — is now reported and recovered. + (UR-004, UR-040 → DR-129, DR-130) + +- **The player no longer reads 0:00 as a track ends on Linux.** MPV exposes + `time-pos` and `duration` as properties of the *loaded* file, so at EOF it + unloads and both stop resolving — reporting zero at exactly the moment + end-of-file handling asks where playback reached. The last reading seen while + media was loaded is now kept and used as the fallback. (UR-005 → DR-130) + +- **Server-side deletions propagate to the local catalog.** `DELETE FROM items` + existed nowhere, so items removed on the server lingered locally forever. A + post-crawl mark-and-sweep now removes them, scoped to crawled types, skipping + downloaded items, and refusing to run after a partial crawl. Separately, + `items_fts` grew a full duplicate index on every catalog pass; it is now a + real upsert, with a migration rebuilding existing indexes. (DR-110) + +- **Android system bars and display cutout are handled correctly.** (UR-066) + ## v0.2.0 ### ✨ Features diff --git a/package.json b/package.json index 4b49bb6c..69949c8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jellytau", - "version": "0.3.0", + "version": "0.4.0", "description": "", "type": "module", "packageManager": "bun@1.3.5", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0c592e73..46992654 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1994,7 +1994,7 @@ dependencies = [ [[package]] name = "jellytau" -version = "0.3.0" +version = "0.4.0" dependencies = [ "aes-gcm", "async-trait", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 5b1a194d..af4bc77f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "jellytau" -version = "0.3.0" +version = "0.4.0" description = "A Tauri App" authors = ["you"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 26087716..edbc69fc 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "jellytau", - "version": "0.3.0", + "version": "0.4.0", "identifier": "com.dtourolle.jellytau", "build": { "beforeDevCommand": "bun run dev",