feat(library): store each album's MusicBrainz release-group id (M483 #5242)
release / govulncheck (push) Successful in 22s
release / web (push) Successful in 1m14s
release / go (push) Successful in 1m33s
release / integration (push) Successful in 4m36s
release / Attach APK to the Release (tag releases only) (push) Canceled after 0s
release / Build + push container image (push) Canceled after 0s
release / Verify release artifacts (tag releases only) (push) Canceled after 0s
release / android (push) Canceled after 5m24s
release / Build signed APK (releases and dev) (push) Canceled after 5m29s

albums.mbid is the release id (Picard's musicbrainz_albumid, one edition).
Lidarr names albums by release group, so re-acquisition and request
completion need that id too (#5241).

Migration 0070 adds albums.release_group_mbid (nullable, non-unique index:
several releases share a group). The scanner reads musicbrainz_releasegroupid
through extractReleaseGroupMBID, writes it on insert and heals it onto
existing rows when NULL. tagReadVersion goes to 3 so the next scan fills
it for the library already indexed, bound by tag reads (no ffprobe, no
decode).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 11:33:26 -04:00
co-authored by Claude Opus 5.5
parent bf6364b709
commit 5c19a916ba
13 changed files with 250 additions and 35 deletions
+37
View File
@@ -163,3 +163,40 @@ func TestCleanMBID_OnlyNULReturnsEmpty(t *testing.T) {
t.Errorf("got %q, want empty", got)
}
}
// #5241: the release-group id is read beside the release id, from each
// format's own key, and the two are never confused.
func TestExtractReleaseGroupMBID(t *testing.T) {
cases := []struct {
name string
meta stubMeta
}{
{"vorbis", stubMeta{format: tag.VORBIS, raw: map[string]interface{}{
"musicbrainz_albumid": "release-1",
"musicbrainz_releasegroupid": "group-1",
}}},
{"id3v2", stubMeta{format: tag.ID3v2_4, raw: map[string]interface{}{
"TXXX": &tag.Comm{Description: "MusicBrainz Album Id", Text: "release-1"},
"TXXX_0": &tag.Comm{Description: "MusicBrainz Release Group Id", Text: "group-1\x00"},
}}},
{"mp4", stubMeta{format: tag.MP4, raw: map[string]interface{}{
"MusicBrainz Album Id": "release-1",
"MusicBrainz Release Group Id": "group-1",
}}},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := extractReleaseGroupMBID(c.meta); got != "group-1" {
t.Errorf("release group = %q, want group-1", got)
}
if album, _ := extractMBIDs(c.meta); album != "release-1" {
t.Errorf("album (release) = %q, want release-1", album)
}
})
}
none := stubMeta{format: tag.VORBIS, raw: map[string]interface{}{"musicbrainz_albumid": "release-1"}}
if got := extractReleaseGroupMBID(none); got != "" {
t.Errorf("untagged release group = %q, want empty", got)
}
}