Migration 0091 drops lidarr_config and renames the quarantine tables, types,
indexes and the history column off the Lidarr name. The Integrations Lidarr
card, the Reports "Delete via Lidarr" action, the merge and remove-track
unmonitor options, the Lidarr audit actions and error codes go, on the
server, web and Android. The README describes acquisition as it is now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Minstrel keeps its own list of what it is to get, keyed by MusicBrainz
release group. A want comes from an approved request, a new release by a
followed artist, or an album whose files went missing, and is held once the
library has a full edition of it.
- Migration 0081: release_type_profiles (Standard seeded: Album, EP,
Single, studio only), follows, follow_seen_groups and wants.
lidarr_requests becomes requests with plain *_mbid columns; approved
album and track requests move onto the wanted list, approved artist
requests become follows, and the library's album artists start out
followed. missing_reacquisitions and the retry settings go.
- internal/wanted: follows are checked against MusicBrainz discographies
daily. The first check sets a baseline, and only releases after it are
wanted unless the follow asked for what already exists. Profiles filter
by primary and secondary type, so live recordings stay out unless a
profile ticks Live.
- internal/requests (was lidarrrequests): approving puts the request on
the wanted list, and an artist request can be approved on a chosen
profile. A request completes when its want is held.
- The re-acquisition sweeper wants a missing album back instead of asking
Lidarr; searching for it is the search schedule's (#5521).
- Web: an admin Wanted page (Wanted, Missing files, Held, Following), a
follow control on artist pages, a release-type profiles card on
Integrations, "Approve on a profile" on Requests, and want state on
Missing files. The artist detail API returns the artist's MBID.
- Android: the request body sends artist_mbid, album_mbid and track_mbid.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The daily 03:00 scheduler rebuild (and the manual refresh endpoint) replace
a user's system playlists + You-might-like rows but published no event, so a
client left open across the rebuild served yesterday's snapshot until a
manual reload — the stale-tab case behind #968. Add a user-scoped
playlist.system_rebuilt event (envelope {kind,user_id,data:{}}) from both the
scheduler (bus threaded into NewScheduler) and handleSystemPlaylistRefresh.
Clients consume it to invalidate home / system-playlist views and proactively
re-pull a stale active queue. Issue #968.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Slice 3a — extends the producer set onto the SSE bus.
quarantine events (5 producer sites):
- quarantine.flagged (user-side flag): broadcast so the flagger's other
clients invalidate their Hidden tab and admins' clients invalidate
their queue.
- quarantine.unflagged (user-side unflag): scoped to the user.
- quarantine.resolved / .file_deleted / .deleted_via_lidarr (admin
actions): broadcast because a single admin action can affect every
user who'd flagged that track.
playlist events (6 producer sites):
- playlist.created / .updated / .deleted: owner-scoped.
- playlist.tracks_changed: emitted for AppendTracks / RemoveTrack /
Reorder. Owner-scoped. Single kind for all three mutations because
the client invalidation logic is identical (refetch the detail).
Public-playlist subscribers (other users viewing someone else's public
playlist) intentionally left out — needs a separate broadcast kind, not
exercised yet at single-household scale.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Slice 2 of #392 — wires the first producers onto the bus that slice 1
built. After this commit, an SSE subscriber sees real events fire:
- track.liked / track.unliked when the user toggles the heart on a track
(handleLikeTrack / handleUnlikeTrack). Album + artist like events
intentionally deferred — they're symmetric trivial follow-ups but the
operator's primary like surface is tracks.
- request.status_changed when a Lidarr request is created, cancelled,
approved, or rejected. Auto-approve will fire twice (pending then
approved) in rapid succession, which is semantically correct; client
invalidation handles that fine.
Events are user-scoped via row.UserID so admin approve/reject route to
the requester, not the admin acting. Helpers live in events_publish.go
so the wire shape (kind names, payload keys) stays in one place — future
producers in slice 3 reuse the same pattern.
events_publish.go is no-op when h.eventbus is nil so tests that
construct handlers without a bus continue to pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>