Release v2026.05.14.0 — player polish, CacheFiller, offline mutation queue #47

Merged
bvandeusen merged 262 commits from dev into main 2026-05-14 21:17:45 -04:00
bvandeusen commented 2026-05-14 21:17:38 -04:00 (Migrated from git.fabledsword.com)

Highlights

Player track-change feel

  • setQueueFromTracks now sets the audio source before broadcasting queue/mediaItem, so AudioService stops emitting the previous track's metadata mid-swap (fb95a46).
  • Prefetcher pre-warms cover bytes + palette for the next N tracks via flutter_cache_manager and the palette extractor; _scheduleSwap takes a fast sync path when the warm cache hits.
  • Playback stream errors now skip to next instead of leaving the UI claiming the broken track is still playing.
  • Reverted the Wear MediaSession surface expansion — Pixel Watch 2 stopped showing controls when we advertised setRating. Kept the dormant LikeBridge wiring for a future re-attempt.

CacheFiller (60085b1)

  • Background sweeper that walks cached_artists / cached_albums for missing relations and fills them via /api/artists/:id + /api/albums/:id. 10s initial delay, 5-minute interval, 200ms throttle between requests. Pre-warms covers for newly discovered albums.

Offline mutation queue (335940c + wiring)

  • New cached_mutations drift table + MutationQueue.enqueue + MutationReplayer (3s initial drain, 1min periodic, 5-attempt drop). Likes / quarantine / add-to-playlist / Lidarr request+cancel now write their optimistic local state to drift first, attempt the REST call, and queue on failure — so the user's intent persists across network loss instead of getting rolled back.

cacheFirst hang fix (5511f87)

  • Added a coldFetchAttempted flag + yield-after-fetch so populates that write to the watched table but produce no rows for the filter (Liked tab on a fresh install) don't spin forever waiting for a re-fetch that would never reveal new data.

Test fixes

  • Cancel one-shot Timers on CacheFiller / MutationReplayer dispose (d27dd69).
  • Drop eager connectivityProvider listener in MutationReplayer.start(); the 3s initial + 1min ticker + post-enqueue nudge cover reconnect (f6ee837).
  • Capture cacheFirst stream Future before feeding controller in tests (67bacac).

Test plan

  • CI green on dev (analyze + tests)
  • Smoke test on device: track change feels instant, mini bar doesn't flicker
  • Toggle airplane mode mid-like / mid-add-to-playlist; verify drift state persists and replays on reconnect

🤖 Generated with Claude Code

## Highlights **Player track-change feel** - `setQueueFromTracks` now sets the audio source before broadcasting queue/mediaItem, so AudioService stops emitting the previous track's metadata mid-swap (`fb95a46`). - Prefetcher pre-warms cover bytes + palette for the next N tracks via `flutter_cache_manager` and the palette extractor; `_scheduleSwap` takes a fast sync path when the warm cache hits. - Playback stream errors now skip to next instead of leaving the UI claiming the broken track is still playing. - Reverted the Wear MediaSession surface expansion — Pixel Watch 2 stopped showing controls when we advertised setRating. Kept the dormant LikeBridge wiring for a future re-attempt. **CacheFiller (`60085b1`)** - Background sweeper that walks `cached_artists` / `cached_albums` for missing relations and fills them via `/api/artists/:id` + `/api/albums/:id`. 10s initial delay, 5-minute interval, 200ms throttle between requests. Pre-warms covers for newly discovered albums. **Offline mutation queue (`335940c` + wiring)** - New `cached_mutations` drift table + `MutationQueue.enqueue` + `MutationReplayer` (3s initial drain, 1min periodic, 5-attempt drop). Likes / quarantine / add-to-playlist / Lidarr request+cancel now write their optimistic local state to drift first, attempt the REST call, and queue on failure — so the user's intent persists across network loss instead of getting rolled back. **cacheFirst hang fix (`5511f87`)** - Added a `coldFetchAttempted` flag + yield-after-fetch so populates that write to the watched table but produce no rows for the filter (Liked tab on a fresh install) don't spin forever waiting for a re-fetch that would never reveal new data. **Test fixes** - Cancel one-shot Timers on `CacheFiller` / `MutationReplayer` dispose (`d27dd69`). - Drop eager `connectivityProvider` listener in `MutationReplayer.start()`; the 3s initial + 1min ticker + post-enqueue nudge cover reconnect (`f6ee837`). - Capture `cacheFirst` stream Future before feeding controller in tests (`67bacac`). ## Test plan - [x] CI green on dev (analyze + tests) - [ ] Smoke test on device: track change feels instant, mini bar doesn't flicker - [ ] Toggle airplane mode mid-like / mid-add-to-playlist; verify drift state persists and replays on reconnect 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/minstrel#47