# Changelog All notable changes to JellyTau are documented here. 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). For how long each fixed defect had been shipping before it was found, see [docs/defect-windows.md](docs/defect-windows.md). ## v0.9.0 An audit release. One new setting you asked for, two naming bugs that only ever showed in builds a developer never looks at, and a large amount of tidying that should be invisible in use. Note for anyone upgrading a Linux package: the Debian/RPM package is now called `jelly-tau` rather than `jellytau` (the packager derives it from the app name). It declares the rename, so `apt`/`dnf` will replace the old package rather than install a second copy. The command is still `jellytau`. ### ✨ Changes - **You can now hide library folders from music browsing.** Pick the folders to exclude in Settings; they disappear from albums, artists, genres, search and the home rows alike. This replaces a filter that dropped anything *named* "Podcasts" β€” one person's library layout compiled into the app, which meant an album genuinely called "Podcasts" vanished while a podcast folder named anything else stayed. Exclusion now matches on the folder itself, is decided in one place rather than at the six screens someone remembered to filter, and defaults to excluding nothing. (UR-076 β†’ DR-209) - **The app is called JellyTau again.** The Android release build showed `jellytau` under its icon, and the Linux and Windows packages carried the same lowercase name. The debug build has always overridden the label to "JellyTau Debug", so the install a developer looks at every day was the only correctly cased one and nobody saw it. (DR-214) - **The RPM package is published.** It has been built by every release since Linux packaging was added, and never copied out of the build β€” so it existed, cost build time, and reached nobody. (DR-214) - **Linux and Windows packages carry their own metadata.** Publisher, copyright, category, description and licence were all absent, so the packages installed with no maintainer and no description. The hand-written Arch package had all of it; only the generated packaging was missing it. (DR-214) ### πŸ”’ Hardening None of these were reachable in normal use β€” the app refuses plain-`http` servers, Android blocks cleartext, and the webview runs under a CSP that bars inline script β€” so they are consistency fixes rather than incidents. Each one had the correct pattern already in the same file, a few lines away. - **Thumbnail cache writes stay inside the cache directory.** The filename was built from three values but only one was sanitised, and joining a path does not fold `..` or keep the base when handed an absolute path. (DR-210) - **Download paths stay inside the download directory.** A correct sanitiser already existed, but the command that queues a download accepted a raw path, so the guard could be routed around rather than being absent. (DR-211) - **Query and URL values are bound and encoded, not pasted in.** The offline item-type filter built SQL by string formatting while its sibling query used placeholders, and browse URLs left values unencoded while the genre parameter next to them was encoded properly. Volume is also range-checked at the command boundary instead of relying on each player backend. (DR-212) ### πŸ›  Development Nothing here changes the app, but the previous release's audit found the tooling claiming more than it delivered, and this is the repair. - **The frontend has a real logger.** 484 `console` calls shipped to users and ran on every device; the Rust half has had levelled logging with a runtime override since the beginning. There is now a matching facade β€” quiet in release builds, verbose in debug ones, with warnings and errors never suppressed and `localStorage` able to turn the volume up in a shipped build to diagnose a problem. (DR-204) - **The traceability matrix is navigable.** Every one of its ~2,800 file links was broken: the generator wrote repo-root paths into a file that lives in `docs/`. The document the whole traceability system exists to produce could not be clicked through, and had no test. Both are fixed, and a link checker now fails the build on a dead documentation link. (DR-093, DR-208) - **The Rust toolchain is pinned.** Developer machines and CI were five releases apart, which meant a clean `cargo clippy` locally proved nothing about CI β€” the same tree measured zero warnings on one and three on the other. With both sides on the same compiler, clippy is now a hard gate instead of advisory. (DR-206) - **The frontend has a linter and formatter**, its first β€” the Rust half has had `cargo fmt --check` and clippy in CI for a while. A pre-commit hook runs the fast checks, so the "before committing" list is enforced rather than remembered. (DR-205, DR-207) - **Containerised builds no longer leave root-owned files** in the working tree, which had accumulated to the point of breaking `cargo clean` and, eventually, `cargo build` itself. (DR-213) - Removed: a webdriverio end-to-end suite that had not run in seven months and was wired into nothing, and a frontend validation module whose six exported functions had no caller outside their own tests β€” which made it read as covered input validation while guarding nothing. ## v0.8.2 A single fix, for Android background audio. ### πŸ› Fixes - **Listening to a video in the background no longer jumps back to where you started.** Handing a video off to background audio streams a live mp3 transcode, which is chunked β€” no length, and no duration the player can read. ExoPlayer resumes a failed load in place only when it knows one of those two things; with neither it assumes the source is live and re-requests the URL from the beginning. That URL starts at the moment you locked the screen, so a network blip left a retry armed, and when the buffer eventually ran dry β€” minutes later, with nothing in between β€” playback silently resumed from the handoff point and carried on. No error was raised and nothing ended, so none of the existing stream-recovery paths could see it; the only sign was a position that went backwards, which is why it looked random. The player is now refused its own retry for exactly that kind of stream, so the failure surfaces and the backend re-opens the stream at the position playback actually reached, keeping your selected audio track. Music and video are untouched: both declare their timeline, and the player resumes them where the load stopped. (UR-040, UR-004 β†’ DR-203) ## v0.8.1 A single fix, for Android. ### πŸ› Fixes - **The screen no longer sleeps while you are watching something.** Android counts its display timeout from the last time you touched the phone, and watching a film is exactly when you do not β€” so the picture dimmed and the screen went out mid-playback unless you kept tapping it. Nothing in the app ever asked the display to stay on, and neither video renderer does so by itself: ExoPlayer's wake mode keeps the CPU and wifi alive but says nothing about the screen, and an embedded WebView does not take the display wake lock that a browser takes for `