-
v2026.06.20 — Image rendering resilience + player error recovery (skip, self-heal, live refresh)
Stabletest-go / test (push) Successful in 46stest-web / test (push) Successful in 55sandroid / Build + lint + test (push) Successful in 4m11stest-go / integration (push) Successful in 4m44srelease / Build signed APK (tag releases only) (push) Successful in 3m53srelease / Build + push container image (push) Successful in 1m41sreleased this
2026-06-20 21:04:04 -04:00 | 26 commits to main since this releasePer-day CalVer. Cover-art rendering and playback error-recovery hardening across server + web + Android, landed together. Issues #968 (images + player resilience) and #980 (stale-view refresh).
Covers never sit blank (#968)
One shared cover renderer per client, so a tile shows a placeholder while loading and a fallback on a 404 instead of an empty box — worst on the You might like row, whose unplayed items often have un-backfilled art.
- Web: new
Covercomponent owns the loading placeholder + error fallback; AlbumCard / ArtistCard / CompactTrackCard reuse it.ArtistCardpreviously had no error handler at all. - Android:
ServerImagenow tracks Coil's load state so the per-caller fallback doubles as a placeholder (loading) and an error painter (404), not just a null-URL guard.
Playback recovers instead of dead-ending (#968)
- Auto-skip a failed track (web + Android): a track that won't load advances to the next instead of stranding the player on "Try again" (web) / a stalled queue (Android). The error state only appears once the whole queue is unplayable. On Android the "Skipped N unplayable tracks" snackbar now tells the truth — it was firing while nothing actually skipped.
- Self-heal a stale queue: when the whole queue is unplayable — e.g. a tab/app left open across the daily 03:00 rebuild — the player re-pulls its source (a system playlist via the rotation-aware shuffle, or a radio re-seed) and resumes. Bounded to one re-pull per exhaustion so a still-broken refresh can't loop.
Browse views refresh themselves (#968)
The server now emits
playlist.system_rebuilton the daily rebuild and on manual refresh. The web client gained its first inbound SSE listener and Android consumes it viaEventsStream— both refresh the Home + playlist views, so a tab open since yesterday stops showing yesterday's mix.Stale-view refresh on an open mix (#980)
A system-playlist detail screen open across the rebuild shows a "This mix was refreshed · Refresh" banner (web) / snackbar (Android). Refresh re-resolves the rotated playlist id to the fresh mix — no forced redirect, no auto-reload, you refresh on your terms.
Verify
- Open Home (web or Android) with un-backfilled art → cover tiles show a placeholder then a fallback, never a blank box.
- Play a queue containing a dead/removed track → it skips to the next instead of dead-ending; only an all-unplayable queue surfaces "Try again".
- Leave a For You tab open across the 03:00 rebuild → the Home tiles refresh on their own; if you then play the stale queue it re-pulls the fresh mix.
- Open a system-playlist detail screen and trigger a refresh → a "This mix was refreshed · Refresh" prompt appears; Refresh lands on the new mix.
🤖 Generated with Claude Code
Downloads
- Web: new