Commit Graph
2086 Commits
Author SHA1 Message Date
bvandeusenandClaude Opus 5.5 f32abc974f fix: a duplicate fold never deletes a lossless copy for a lossy one, nor folds two versions (M498)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m31s
release / android (push) Successful in 4m58s
release / integration (push) Successful in 5m0s
release / Build signed APK (releases and dev) (push) Successful in 5m7s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
The first album-copy fold pass on 2026-10-20 removed five FLACs (Måneskin
Rush!, Weezer 2016) in favour of mp3s whose only edge was a recording MBID,
and an explicit "Suite-Pee" for its clean version. ProposeSurvivor now ranks
lossless before tag fit; tag fit still outranks file size, which is what the
Humanz rips needed. The fold keys copies by their version words (title and
file name), so a clean, live or instrumental copy holding the same title tag
is linked, not folded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:36:55 -04:00
bvandeusenandClaude Opus 5.5 16a152b862 test: the album-copy fold test makes each album once, as UpsertAlbum folds only by MBID (#5401)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m38s
release / android (push) Successful in 5m8s
release / integration (push) Successful in 5m8s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 12:01:16 -04:00
bvandeusenandClaude Opus 5.5 3ebd35e51d fix: a slot the resolver emptied folds only into a copy of its own song (M498)
release / web (push) Successful in 1m28s
release / go (push) Successful in 1m36s
release / android (push) Successful in 5m2s
release / govulncheck (push) Successful in 16s
release / integration (push) Failing after 5m7s
release / Build signed APK (releases and dev) (push) Successful in 5m12s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
On 2026-10-20 the emptied "Open the Gateway" slot of Auvic's Speed Demons
was folded by title into another file tagged "Open the Gateway" that holds
Onward (244 s against the song's 254 s), so the album was never wanted
back. A wrong-slot removal now stamps tracks.emptied_at (migration 0095)
when the album holds no copy of the song as long as its MusicBrainz slot,
and missing-pair folding pairs such a row by title only with a track added
since: a copy fetched again. A slot whose song the album does hold (VOID
DLC's Weeper beside Void's) folds into it as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:55:23 -04:00
bvandeusenandClaude Opus 5.5 09e74a57a2 feat: an album holding a song twice beside its single keeps one copy (#5401)
A cross-release group was only ever linked, never merged, so an album that
held the song twice among the releases kept both: Humanz has Saturnz Barz,
Andromeda, We Got the Power and Garage Palace as its FLAC and a YouTube mp3,
each beside the single. The resolver now merges an album's extra copies
into its best (the one that is not a video rip, else ProposeSurvivor:
lossless first) with ReplaceTrack, history and all, then links what is
left as one song.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:55:23 -04:00
bvandeusenandClaude Opus 5.5 80ecc2f7e7 fix: imported FLAC, Ogg and Opus files keep their track and disc numbers (#6171)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m29s
release / integration (push) Successful in 5m1s
release / android (push) Successful in 5m5s
release / Build signed APK (releases and dev) (push) Successful in 5m21s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
The importer wrote track=N/M for every format, which ffmpeg stores in a
Vorbis comment as TRACKNUMBER=3/20; dhowden/tag reads a Vorbis TRACKNUMBER
with a bare Atoi, so it came back 0. All 245 tracks imported since
2026-10-10 (Humanz, Plastic Beach, the Gorillaz super deluxe and twelve
more albums) have no track or disc number, and their album pages have no
order.

- The importer writes a Vorbis track and disc number alone, with
  TRACKTOTAL and DISCTOTAL, as Picard does. ID3 and MP4 keep N/M.
- ReadTrackAndDisc takes the number before a slash when the Vorbis reader
  returns 0, for the scanner and for the import's own check of a download.
- tagReadVersion 6 re-reads the files already held (tag reads only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:49:44 -04:00
bvandeusenandClaude Opus 5.5 42e48efb79 fix: the duplicate resolver waits for a running scan, so a copy it removes is not marked present again (#6169)
release / govulncheck (push) Successful in 13s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m38s
release / integration (push) Successful in 5m6s
release / android (push) Successful in 5m10s
release / Build signed APK (releases and dev) (push) Successful in 5m21s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 14s
release / Verify release artifacts (tag releases only) (push) Skipped
At boot the scan lists the library, the resolver removes wrong-slot copies
and marks their tracks missing, then the scan reconciles from its list and
marks them present: 7 of the 13 removed on 2026-10-20 15:00 read as
present with no file, and would not be wanted back until a later scan. A
pass now waits while a scan younger than StuckScanThreshold is in flight
and tries again a minute later; a stuck run does not hold it up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 11:04:46 -04:00
bvandeusenandClaude Opus 5.5 3a482bd715 fix: AcoustID decides any one-album mismatch the lengths cannot, not only copies each cut to its slot (#6169)
release / govulncheck (push) Successful in 13s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m3s
release / android (push) Successful in 5m6s
release / Build signed APK (releases and dev) (push) Successful in 5m14s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
The first pass on the operator's library held 16 groups. In several, every
copy's own lookup names one recording (Wombats Record Shop/Tormentor,
Alchemist (2)/Prelude, Monday Chill 8/9, 404sessions), but one copy sits 3-10s
from its slot, so the every-copy-fits precondition kept AcoustID out. Now:
copies whose lookups all agree are that recording, whatever their
fingerprints read; copies of the same audio are asked about as before; and
the track list places the recording in one copy's slot, or none. Copies
filed as one song are not settled here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:52:42 -04:00
bvandeusenandClaude Opus 5.5 18d31e9cdd feat: one recording cut to several songs' lengths is named by AcoustID; the copy in its slot stays, the rest go, and the release is set aside (#6169)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m31s
release / android (push) Successful in 5m1s
release / integration (push) Successful in 5m1s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
Savant's Mortals held one recording as 16 of its 50 tracks, each trimmed to
its own slot's MusicBrainz length, so the lengths could not say which slot
was its own and every group waited for the operator. When a one-album
mismatch is the same audio (identical, or fingerprints within 0.02) and
every copy fits its own slot, the resolver asks what the recording is: the
copies' own AcoustID lookups, or a fresh lookup of one copy (five a pass).
The track list names each slot's recording; the copy in that slot is kept
and the others removed, or every copy when the recording is in none of
their slots or AcoustID knows none. AcoustID unreachable or answers in
several copies' slots: the group waits.

Whenever wrong-slot copies are removed, the download the files were
imported from is set aside, so the album fetched again is not the same
files. Albums imported before Minstrel downloaded anything have none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:33:55 -04:00
bvandeusenandClaude Opus 5.5 e3eddab80f feat: the duplicates review says what each match rests on and plays every copy (#6168)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m34s
release / android (push) Successful in 4m58s
release / integration (push) Successful in 5m4s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Each group now states its evidence: identical audio data, or the share of
audio fingerprints that agree. Copies titled as different songs in one
acoustic group say so and ask the reviewer to listen, and each copy has a
play button so they can.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:28:29 -04:00
bvandeusenandClaude Opus 5.5 460e78c955 fix: an album with missing tracks is wanted back by its release group, not only when it carries a release MBID (#6167)
release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m32s
release / integration (push) Successful in 5m1s
release / android (push) Successful in 5m7s
release / Build signed APK (releases and dev) (push) Successful in 5m17s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
The release id was only ever used to find the group. 238 albums matched to a
group carried none, so their losses, five of the resolver's wrong-slot
removals among them, were never fetched again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 10:21:06 -04:00
bvandeusenandClaude Opus 5.5 39029b5cd9 fix: clearing a wrong slot's MBID clears its source too, as tracks_mbid_source_pair requires (M498)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m37s
release / android (push) Successful in 5m1s
release / integration (push) Successful in 5m4s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:47:02 -04:00
bvandeusenandClaude Opus 5.5 8daa3d07b5 fix: a slot emptied of another song's file drops that file's recording MBID, so missing-pair folding cannot fold it into the copy kept (M498)
release / govulncheck (push) Successful in 24s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m35s
release / integration (push) Failing after 5m1s
release / android (push) Successful in 5m2s
release / Build signed APK (releases and dev) (push) Successful in 5m11s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
On 2026-10-20 twelve of the 24 slots the resolver emptied were folded by MBID
into the kept copy, so their albums were never wanted back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:39:17 -04:00
bvandeusenandClaude Opus 5.5 304caaee02 fix: the AcoustID rate-limit test bounds arrivals by the service's 3 a second, not the client's send spacing
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m42s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m26s
release / Build signed APK (releases and dev) (push) Successful in 5m31s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 24s
release / Verify release artifacts (tag releases only) (push) Skipped
Run 9543 saw two arrivals 389ms apart though the client sent them 400ms apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:29:00 -04:00
bvandeusenandClaude Opus 5.5 a3d9effca3 feat: when no slot an album gives one recording is its own, every copy is removed and the album fetched again (M498)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m28s
release / go (push) Failing after 1m31s
release / integration (push) Successful in 5m15s
release / android (push) Successful in 5m23s
release / Build signed APK (releases and dev) (push) Successful in 5m37s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Shnabubula's whole album, one 45-minute file, was filed as both Fading Light
and Looking for Answers. Neither slot fits, so wrongSlots had nothing to keep
and held the group. Every copy now goes when each is clearly another song's;
a copy near its slot still holds the group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:21:43 -04:00
bvandeusenandClaude Opus 5.5 c8e855ae4a feat: the duplicate resolver fetches a missing album track list from MusicBrainz to decide a wrong slot, five albums a pass (M498)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m16s
release / go (push) Successful in 1m33s
release / integration (push) Successful in 5m0s
release / android (push) Successful in 5m7s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
20 of the 34 groups left for review had no cached track list for their album:
the catalogue only reads one when the wanted list or the importer needs it.
The resolver now asks catalogue.RefreshReleaseGroup for an album it must
decide and the catalogue has never read, through the shared MusicBrainz pacer,
at most five a pass (hourly). An unreachable MusicBrainz stops the pass's
fetching; a group read and found empty is not asked about again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 09:02:53 -04:00
bvandeusenandClaude Opus 5.5 c5868c00cc feat: a version named after a dash counts as a version, and a song held twice beside a wrong slot no longer blocks it (M498)
release / govulncheck (push) Successful in 25s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m31s
release / android (push) Successful in 4m51s
release / integration (push) Successful in 4m53s
release / Build signed APK (releases and dev) (push) Successful in 5m0s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 17s
release / Verify release artifacts (tag releases only) (push) Skipped
- songKey drops a dashed version suffix (" - Instrumental Version", " - Radio
  Edit", live, remix, mix, acoustic, demo, reprise, rework, VIP), so Andora's
  "Goodbye Yesterday - Instrumental Version" is distinct, not a wrong slot.
- wrongSlots accepts several fitting copies when they share one title
  (Killjoy twice beside Dreamland): the other slot's copy is removed, and the
  doubled song is left for the next sweep to find as a pair the resolver merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 06:24:47 -04:00
bvandeusenandClaude Opus 5.5 80c711ac9d fix: a wrong-slot removal reads without a counted noun (M498)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m28s
release / go (push) Successful in 1m38s
release / integration (push) Successful in 5m9s
release / android (push) Successful in 5m11s
release / Build signed APK (releases and dev) (push) Successful in 5m21s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 29s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:31:11 -04:00
bvandeusenandClaude Opus 5.5 0f58ebcd6c feat: duplicates settle themselves: retitled copies across releases link, alike versions on one album are dismissed, and a file in another song's slot is removed so the album is fetched again (M498 #6159-#6162)
release / govulncheck (push) Successful in 14s
release / web (push) Failing after 1m26s
release / go (push) Successful in 1m35s
release / integration (push) Successful in 5m8s
release / android (push) Successful in 5m12s
release / Build signed APK (releases and dev) (push) Successful in 5m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
The operator's library had 536 groups waiting for review, 2026-10-19. A sample
showed most were one recording under two titles on two releases.

- The headline and the Duplicates count leave out cross-release groups, which
  the resolver keeps and links: the headline read 3,479 when 536 needed review.
- Any group spanning albums is cross_release and is linked as one song,
  whatever its titles say. Nothing is deleted.
- One album, two versions named as such ("Lovesick (Instrumental)") and not
  byte-identical: a new class, distinct, dismissed by the resolver.
- One album, one recording under different song titles (mismatch): the
  album's cached MusicBrainz track list decides. When exactly one slot's song
  is as long as the file and every other slot's song is clearly not, the other
  copies are removed and their tracks marked missing, so the reacquisition
  sweeper wants the album back. Otherwise the group stays for review.
- The duplicates_found notice moves from the sweep to the resolver: it names
  only groups a pass first left for review.
- Resolved automatically lists dismissals and wrong-slot removals beside
  merges.

Migration 0094 adds 'distinct' to the class CHECK (rule 36).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 23:22:38 -04:00
bvandeusenandClaude Opus 5.5 8538f0dc68 fix: the playback-error test matches the prefixed username, and announcementFor keeps detekt's two returns (M542)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m25s
release / go (push) Successful in 1m35s
release / integration (push) Successful in 5m7s
release / android (push) Successful in 5m8s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 14s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:53:13 -04:00
bvandeusenandClaude Opus 5.5 854c307834 feat: notifications say what changed and alert once: a grouped notice names the tracks, grows without re-alerting, and a phone pile lists its titles (M542 #6146-#6151)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m33s
release / android (push) Failing after 1m42s
release / integration (push) Failing after 4m42s
release / Build signed APK (releases and dev) (push) Successful in 4m55s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
- An update to a grouped notice keeps its arrival time and email state, so the
  phone and the email no longer go off again each time it grows.
- Notices carry the names of what changed (newest ten), shown as three and
  "and N more": tracks still missing after the scan's move/replacement fold,
  duplicate groups new to a sweep, songs merged automatically, and the track
  and listener a playback error was for.
- Duplicates found counts only the groups new to that sweep; playback errors
  count reports, not the unresolved total.
- A scan failure says what stopped and links to Admin > Library.
- Android: a pile of more than three alerts lists the newest five titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:44:19 -04:00
bvandeusenandClaude Opus 5.5 2365514e5b test: TestPlanRoots looks for the empty-list refusal as the message words it (#6129)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m34s
release / integration (push) Successful in 5m2s
release / android (push) Successful in 5m6s
release / Build signed APK (releases and dev) (push) Successful in 5m16s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 1m22s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:40:54 -04:00
bvandeusenandClaude Opus 5.5 edcb3a57ef feat: the library's folders are set in Admin › Library, and changing a folder moves its tracks with it, keeping their plays, likes and playlists (#6129)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m20s
release / go (push) Failing after 1m37s
release / integration (push) Failing after 4m56s
release / android (push) Successful in 5m1s
release / Build signed APK (releases and dev) (push) Successful in 5m13s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:37:03 -04:00
bvandeusenandClaude Opus 5.5 453a977e48 refactor: the admin and user Requests pages draw a request with one RequestRow, and the kind chip is one KindPill there and on Hidden tracks (#5651)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m16s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 5m10s
release / android (push) Successful in 5m17s
release / Build signed APK (releases and dev) (push) Successful in 5m33s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 18:20:53 -04:00
bvandeusenandClaude Opus 5.5 db15713798 refactor: the server says a count one way, words.Count, for notifications, a wanted match's reason and the duplicate resolver's activity line (M505 #5643)
release / govulncheck (push) Successful in 22s
release / web (push) Successful in 1m35s
release / go (push) Successful in 1m45s
release / integration (push) Successful in 5m41s
release / android (push) Successful in 6m7s
release / Build signed APK (releases and dev) (push) Successful in 6m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 29s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:18:50 -04:00
bvandeusenandClaude Opus 5.5 9e24b2b4fc refactor: every count in the web app is said by one plural(), with the viewer's thousands separator; a source guard names any hand-written copy (M505 #5642)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:18:04 -04:00
bvandeusenandClaude Opus 5.5 af2d4f9859 refactor: a running download is worded the same on the admin Overview as on the wanted list, from one liveDownloadLine (M505 #5641)
release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m29s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m8s
release / android (push) Successful in 5m21s
release / Build signed APK (releases and dev) (push) Successful in 5m35s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:15:21 -04:00
bvandeusenandClaude Opus 5.5 622f248ea2 refactor: track lengths and file sizes come from the shared formatters on Missing files, Duplicates, a want's Releases and the app download; an hour-long track reads 1:01:05, not 61:05 (M505 #5639 #5640)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 16:14:01 -04:00
bvandeusenandClaude Opus 5.5 9e7d50b38e fix: FLAC, Ogg and Opus tracks carry their MusicBrainz recording id from the tag: one reader in library gives the scanner, the backfills and the importer the same ids, and the next scan re-reads the library (#5637)
release / govulncheck (push) Successful in 20s
release / web (push) Successful in 1m30s
release / go (push) Successful in 1m50s
release / integration (push) Successful in 5m19s
release / android (push) Successful in 5m50s
release / Build signed APK (releases and dev) (push) Successful in 6m12s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 15:55:25 -04:00
bvandeusenandClaude Opus 5.5 c1305a547d feat: the admin Overview shows who is listening, downloads, the library and its disk, and the server's version, uptime and recent errors; a download waiting on you, a client not answering or a full disk count in its verdict (M504 #5627 #5628 #5629 #5630)
release / govulncheck (push) Successful in 17s
release / web (push) Successful in 1m35s
release / go (push) Successful in 2m0s
release / integration (push) Successful in 5m40s
release / android (push) Successful in 6m15s
release / Build signed APK (releases and dev) (push) Successful in 6m30s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
The version moves to internal/buildinfo, so /rest/ping reports the build
instead of "dev".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:51:41 -04:00
bvandeusenandClaude Opus 5.5 ead0abf0cf feat: one Missing files page under Collection: folders gone, each with its album's want, last search or download, and Search, Releases and Remove; an album held before its files went is no longer shown as held again (M504 #5626)
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m30s
release / go (push) Successful in 1m46s
release / integration (push) Successful in 5m23s
release / android (push) Successful in 5m43s
release / Build signed APK (releases and dev) (push) Successful in 6m2s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:44:33 -04:00
bvandeusenandClaude Opus 5.5 38b2325d2d feat: Reports, Duplicates and Suspect sources live under Collection, with their counts on its rail and a "To look at" line naming the ones waiting; notices link there (M504 #5625)
release / govulncheck (push) Successful in 21s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m39s
release / integration (push) Successful in 5m31s
release / android (push) Successful in 6m5s
release / Build signed APK (releases and dev) (push) Successful in 6m21s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 32s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 14:35:59 -04:00
bvandeusenandClaude Opus 5.5 12725e71b0 fix: the reports test name keeps its apostrophe inside double quotes, and the merge API test sends no unmonitor (M502 #5525)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m19s
release / go (push) Successful in 1m35s
release / integration (push) Successful in 5m12s
release / android (push) Successful in 5m18s
release / Build signed APK (releases and dev) (push) Successful in 5m34s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 13:55:55 -04:00
bvandeusenandClaude Opus 5.5 3a16732883 feat: Minstrel no longer talks to Lidarr: its connection, Delete via Lidarr and the unmonitor options are gone, and the track reports are plain quarantine (M502 #5525)
release / govulncheck (push) Successful in 15s
release / web (push) Failing after 17s
release / go (push) Successful in 1m13s
release / integration (push) Successful in 4m56s
release / android (push) Successful in 5m9s
release / Build signed APK (releases and dev) (push) Successful in 5m19s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
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>
2026-10-11 13:48:20 -04:00
bvandeusenandClaude Opus 5.5 c54792c51e feat: a held album below the quality you settle for, or holding a video rip, stays wanted for a better copy, and the import replaces the old tracks with their likes and plays carried over (M502 #5524)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m23s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 5m20s
release / android (push) Successful in 5m28s
release / Build signed APK (releases and dev) (push) Successful in 5m30s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 27s
release / Verify release artifacts (tag releases only) (push) Skipped
- acquisition_settings.upgrade_until (default High quality lossy, Lidarr's
  cutoff, note #5527; "" is off), an "Upgrade until" row under Searching.
- The wanted worker judges held albums hourly: tier per format from size per
  second (the scanner records no bitrate), the album's worst. Below the
  cutoff it is wanted for quality; a video rip among its tracks always.
- The schedule searches upgrades weekly, after open wants; a release no
  better than the copy held is refused ("not_better").
- The import matches each file to the track it would replace (recording,
  then disc/track) and replaces it when it is a rip or the file is a better
  tier: over the same path in one rename, or filed beside it and the old
  track folded in (library.ReplaceTrack: file first, then foldTrackInto).
  Nothing better: the release is set aside.
- Collection › Upgrades (Lidarr's Cutoff Unmet); Suspect sources says when a
  clean copy was looked for instead of Lidarr's search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 12:24:59 -04:00
bvandeusenandClaude Opus 5.5 a5ad301c94 feat: Users, Diagnostics and Tuning sit on the admin layout like the rest: debug mode is a row action on Users, every admin load error has Try again, and figures carry their scale (M503 #5608)
release / android (push) Successful in 5m24s
release / Build signed APK (releases and dev) (push) Successful in 5m26s
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m34s
release / integration (push) Successful in 5m19s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
- Users: a one-line count of accounts, admins and open invites; Turn on/off debug mode in each row's actions, and a "debug on" badge that opens that account's events
- Diagnostics: no title or paragraph of its own; devices named by account, OS, app version and last seen, not client id; opens on ?account=
- Tuning: each profile, the taste build and Discover are row groups with one-line hints; the sparkline has a 0–100% axis
- Requests, Duplicates, Missing files and Suspect sources: load errors offer Try again
- Library: cover art reads "N of M albums have art"

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:52:51 -04:00
bvandeusenandClaude Opus 5.5 0049b64ff1 fix: the AcoustID and Library tests expect the new copy and one folder per line (M503 #5607)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m27s
release / go (push) Successful in 1m43s
release / android (push) Successful in 5m19s
release / integration (push) Successful in 5m22s
release / Build signed APK (releases and dev) (push) Successful in 5m38s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:30:20 -04:00
bvandeusenandClaude Opus 5.5 7f913e3e70 feat: the admin settings cards read as menus: each a titled group of rows with one short line, status first, failures in words (M503 #5607)
release / govulncheck (push) Successful in 16s
release / web (push) Failing after 1m27s
release / go (push) Successful in 1m44s
release / android (push) Successful in 5m13s
release / integration (push) Successful in 5m18s
release / Build signed APK (releases and dev) (push) Successful in 5m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Indexers and clients, searching, missing files, Lidarr's neighbours, AcoustID, fingerprinting, loudness, outgoing email's schedule, public address and proxies move from paragraph cards to SettingsGroup and SettingRow. Switches are role="switch". Also fixes the two type errors run 9023 found: the Lidarr test result is narrowed before its lists are read, and the tag-source save mock carries version_bumped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:25:46 -04:00
bvandeusenandClaude Opus 5.5 7e1cfb8d08 feat: Integrations splits into Library, Acquisition, Metadata sources and Email & network, each a page on the admin rail; the Overview keeps only what needs you (M503 #5607)
release / govulncheck (push) Successful in 14s
release / web (push) Failing after 16s
release / go (push) Successful in 1m13s
release / integration (push) Successful in 4m54s
release / android (push) Successful in 5m5s
release / Build signed APK (releases and dev) (push) Successful in 5m18s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
- Library: the folders, Run scan and a row per scan job, cover art, fingerprints and loudness (off the Overview and Duplicates)
- Acquisition: indexers and clients, searching, re-acquisition (off Missing files), Lidarr
- Metadata sources: AcoustID, and one provider block for cover art and tags in place of the pasted pair
- Email & network: outgoing email, the notification schedule, public address, proxies
- Lidarr, outgoing email and the provider block are rebuilt as SettingsGroup rows; failures read as sentences, not codes
- Duplicates and Missing files say what their setting is and link to where it is set

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 11:21:48 -04:00
bvandeusenandClaude Opus 5.5 0cc4bc686a fix: a report's details keep the space before a note, and the Reports menu test opens the row it means (M503 #5606)
release / govulncheck (push) Successful in 19s
release / web (push) Successful in 1m38s
release / go (push) Successful in 1m49s
release / android (push) Successful in 5m22s
release / integration (push) Successful in 5m27s
release / Build signed APK (releases and dev) (push) Successful in 5m30s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:57:02 -04:00
bvandeusenandClaude Opus 5.5 89a2653995 feat: Admin › Reports is one queue of broken tracks, whether a listener flagged it or it failed to play, one row per track with one set of actions (M503 #5606)
release / govulncheck (push) Successful in 16s
release / web (push) Failing after 1m18s
release / go (push) Successful in 1m36s
release / integration (push) Successful in 5m27s
release / android (push) Successful in 5m28s
release / Build signed APK (releases and dev) (push) Successful in 5m38s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
- /admin/reports folds the quarantine queue and the unresolved playback
  errors into one row per track, newest first: who flagged it and why,
  what failed and for whom, the file, with Resolve (clears the reports and
  marks the errors fixed), Play, Copy details, Delete file and, for an album
  Lidarr holds, Delete via Lidarr.
- One delete path: Delete file removes the track, and its reports and
  errors go with the row.
- A Handled tab shows what was done: reports cleared, files deleted,
  errors marked fixed or ignored.
- The summary counts reports by track across both sources, so the rail,
  the Overview and the page agree.
- /admin/quarantine and /admin/playback-errors redirect to Reports: the
  notifications and the Android app link to them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:53:58 -04:00
bvandeusenandClaude Opus 5.5 864eb45580 feat: Settings uses the width of a wide screen: groups sit in two columns, each narrow enough that a row's control stays near its name (M503 #5595)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m24s
release / go (push) Successful in 1m41s
release / integration (push) Successful in 5m13s
release / android (push) Successful in 5m15s
release / Build signed APK (releases and dev) (push) Successful in 5m25s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
The content was capped at max-w-3xl, so a wide window showed one narrow
strip and a lot of empty space. SettingsColumns lays a page's groups out as
one column on a phone or narrow window and two side by side from xl up;
the page cap moves to 100rem so the columns don't stretch on a very wide
screen.

- Account: Android app, Profile and Password, with Signed-in devices beside.
- Playback: "Between tracks" (crossfade) beside "Volume leveling".
- Connections: ListenBrainz beside Subsonic apps.
- Appearance, Notifications, About: one column's width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 10:28:06 -04:00
bvandeusenandClaude Opus 5.5 ace7e22e6a feat: Admin is a left rail with how many wait on you in each queue, and the Overview opens with a verdict, the queues that need you and since when, then the clear ones on one line (M503 #5605)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m21s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m10s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 24s
release / Verify release artifacts (tag releases only) (push) Skipped
- GET /api/admin/summary: every admin queue (requests, reported tracks,
  playback errors, duplicates, suspect sources, missing files) with its
  count and the age of its oldest item, in one query.
- The admin layout drops the 11-tab strip for SectionRail, as Settings and
  the Collection have, with each queue's count as its badge; the counts
  refresh on each admin navigation and every 30s.
- The Overview leads with "Nothing needs you." or "N things need you.",
  lists each waiting queue with "oldest 3d ago" and a link to it, counts a
  failed library scan as a problem, and names the empty queues on one line.
  The request and quarantine previews and the stat tiles are gone; those
  queues are worked on their own pages. A failed summary says so with Try
  again instead of reading as all-clear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:58:13 -04:00
bvandeusenandClaude Opus 5.5 7c89e59536 fix: admin bugs from the audit: a playback-error delete no longer reports failure, a failed Overview load no longer reads as all-clear, and email settings can't be saved over with defaults (M503 #5604)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m31s
release / go (push) Successful in 1m49s
release / integration (push) Successful in 5m20s
release / Build signed APK (releases and dev) (push) Successful in 5m9s
release / android (push) Successful in 6m26s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
- Playback errors: Delete file stops resolving the error row the track
  deletion already took with it (ON DELETE CASCADE), which 404'd into
  "Delete failed".
- Overview: a queue that fails to load says so with Try again, and its tile
  shows a dash, not 0. Delete via Lidarr shows only for an album Lidarr
  holds while Lidarr is connected. An approve refreshes the Collection.
- Quarantine: Delete via Lidarr is in the row menu, so a phone reaches it;
  "1 report", not "1 reports".
- Duplicates: the Keep badge follows the copy picked.
- Integrations: provider save failures and load errors are said, not
  swallowed or shown as "No providers registered"; the Lidarr test catches
  a failed call; SMTP fills once and Save stays off until it has loaded.
  Lidarr's blurb says what it is still used for.
- Requests: release profiles point at Collection › Following.
- Library: an empty library sends an admin to Admin to run a scan, and
  tells anyone else the admin scans it, instead of opening Settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 09:40:11 -04:00
bvandeusenandClaude Opus 5.5 c94c09aeae feat: Settings is one page per section down a left rail, Account first, every setting a row; the profile form no longer saves blanks over your name and email (M503 #5595 #5596 #5597)
release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m45s
release / go (push) Successful in 1m58s
release / integration (push) Successful in 5m39s
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
release / android (push) Successful in 5m43s
release / Build signed APK (releases and dev) (push) Successful in 5m58s
release / Attach APK to the Release (tag releases only) (push) Skipped
- /settings lands on Account: the Android app, profile, password, signed-in
  devices. Then Playback, Appearance, Notifications, Connections, About.
- Each setting is a row (name, one short line, control at the end) in a
  capped-width column; one-of-N choices are a shared Segmented control.
- Collection and Settings share one SectionRail.
- Connections leads ListenBrainz with a status line: not connected,
  connected and not sending, or sending with the last scrobble's age.
- Notifications prints its column labels once; the digest email's
  settings link points at /settings/notifications.
- #5596: the profile form now loads what is stored and sends only the
  fields that changed. It used to start blank, and the server reads a
  blank as "clear", so one Save wiped the display name and email.
- Recommendation metrics moves to Library › Your listening, and Hidden
  tracks gets a Library tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:34:51 -04:00
bvandeusenandClaude Opus 5.5 c0c0f8a71f feat: Now Playing's cover grows to fill the screen, and the page takes the cover's dominant colour as Android does (#5592)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m45s
release / go (push) Successful in 2m9s
release / integration (push) Successful in 5m44s
release / android (push) Successful in 5m49s
release / Build signed APK (releases and dev) (push) Successful in 6m9s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
The web colour helper now picks Palette's dominant swatch (5-bit
quantise, Palette's default filter, median cut to 16, the most-populated
box) instead of the 1x1 mean, so the web and Android agree; PlayerBar's
accent strip shares it. Now Playing draws Android's gradient (55% at the
top, 18% at 45%, then the page) as a masked background colour that fades
over 600ms between tracks, holding the old colour until the new resolves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 23:05:05 -04:00
bvandeusenandClaude Opus 5.5 2f2573dd07 fix: the re-tag test sets its clock one statement at a time, as a prepared statement takes only one (M502 #5579)
release / govulncheck (push) Successful in 14s
release / web (push) Successful in 1m17s
release / go (push) Successful in 1m35s
release / integration (push) Successful in 5m9s
release / android (push) Successful in 5m15s
release / Build signed APK (releases and dev) (push) Successful in 5m20s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 24s
release / Verify release artifacts (tag releases only) (push) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:23:16 -04:00
bvandeusenandClaude Opus 5.5 a8786abace feat: Collection › Unmatched lists the library albums no MusicBrainz album matched, each matched by hand from a search or a link, or left off (M502 #5579)
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m17s
release / go (push) Successful in 1m34s
release / integration (push) Failing after 5m34s
release / android (push) Successful in 5m36s
release / Build signed APK (releases and dev) (push) Successful in 5m44s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Skipped
release / Verify release artifacts (tag releases only) (push) Skipped
Like Lidarr's Unmapped Files. A local band's album, which MusicBrainz will
never have, is left off: never matched again and not counted. A re-tagged
album is matched again on the next listing. The Collection's verdict now
says when library albums need matching.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:12:30 -04:00
bvandeusenandClaude Opus 5.5 10be068dcc fix: the player bar's heart is Lucide's, outlined then filled as on Android, and its title and artist read at the size of the rest of the page (#5580)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 22:12:29 -04:00
bvandeusenandClaude Opus 5.5 358849de77 feat: the Wanted view becomes Collection, shaped like Lidarr: an artist catalogue first, the state sections down a left rail (M502 #5577)
release / govulncheck (push) Successful in 21s
release / web (push) Successful in 1m39s
release / go (push) Successful in 1m54s
release / integration (push) Successful in 5m33s
release / android (push) Successful in 5m40s
release / Build signed APK (releases and dev) (push) Successful in 5m56s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 25s
release / Verify release artifacts (tag releases only) (push) Skipped
The section opens on a catalogue of every artist on the list, A–Z with a
letter rail, each card showing how many of their albums are held. An artist
opens on their page: every album of theirs, held or not, with its status,
search, releases and tracks. Wanted, Missing files, Activity, Following and
Blocked sit down a left rail as the sections that show state; Held is gone,
the catalogue shows it. The section moves from /wanted to /collection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:14:33 -04:00
bvandeusenandClaude Opus 5.5 a4fbe44bd5 feat: the Wanted view lists artists A–Z with their albums inside, each album's tracks a click away (M502 #5572)
release / govulncheck (push) Successful in 21s
release / web (push) Successful in 1m20s
release / go (push) Successful in 1m38s
release / integration (push) Successful in 5m35s
release / android (push) Successful in 5m59s
release / Build signed APK (releases and dev) (push) Successful in 6m10s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
The list runs like the library: artists by the library's sort name, each
artist's albums oldest first, grouped under the artist (linked into the
library when it holds them). A filter narrows it to an artist or album by
name, on the server, so it finds what has not been scrolled to. Tracks
opens an album's track list: the library's own for an album it holds, a
lost file marked, otherwise MusicBrainz's standard edition, named.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 18:43:32 -04:00