fix: same-titled albums of two release groups are two albums, and a missing track with no disc is on disc 1
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m23s
release / go (push) Successful in 1m30s
release / integration (push) Successful in 5m0s
release / android (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 29s
release / Verify release artifacts (tag releases only) (push) Skipped
release / govulncheck (push) Successful in 16s
release / web (push) Successful in 1m23s
release / go (push) Successful in 1m30s
release / integration (push) Successful in 5m0s
release / android (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 29s
release / Verify release artifacts (tag releases only) (push) Skipped
The scanner found an album by artist and title alone, so Weezer's six self-titled albums (1994–2026) were one 118-track row and their merges, wants and upgrades counted them as one. A same-named row whose release group is known and differs from the file's is now another album; tagReadVersion 7 re-reads the library so existing tracks move to their own rows. WantHoldings compared discs with IS NOT DISTINCT FROM, so a missing track 6 with no disc was never covered by a present disc 1 track 6. Air's Love 2 stayed wanted and was downloaded again for nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -385,3 +385,94 @@ func TestScanner_ReleaseGroupMBID_Integration(t *testing.T) {
|
||||
t.Errorf("album A release group changed to %v", rg)
|
||||
}
|
||||
}
|
||||
|
||||
// Two albums of one name by one artist, in different release groups, are two
|
||||
// albums: Weezer's six self-titled albums shared one row until 2026-10-20. A
|
||||
// track of the same group joins its album, and a track filed under the other
|
||||
// album's row by the old lookup moves to its own on the tagReadVersion re-read.
|
||||
func TestScanner_SameTitledAlbumsOfTwoGroupsAreTwoAlbums_Integration(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping scanner integration in -short mode")
|
||||
}
|
||||
dsn := os.Getenv("MINSTREL_TEST_DATABASE_URL")
|
||||
if dsn == "" {
|
||||
t.Skip("MINSTREL_TEST_DATABASE_URL not set")
|
||||
}
|
||||
ctx := context.Background()
|
||||
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
if err := db.Migrate(dsn, logger); err != nil {
|
||||
t.Fatalf("migrate: %v", err)
|
||||
}
|
||||
pool, err := pgxpool.New(ctx, dsn)
|
||||
if err != nil {
|
||||
t.Fatalf("pool: %v", err)
|
||||
}
|
||||
t.Cleanup(pool.Close)
|
||||
if _, err := pool.Exec(ctx, "TRUNCATE tracks, albums, artists RESTART IDENTITY CASCADE"); err != nil {
|
||||
t.Fatalf("truncate: %v", err)
|
||||
}
|
||||
|
||||
const (
|
||||
blue = "aaaaaaaa-1994-2222-3333-444444444444"
|
||||
green = "bbbbbbbb-2001-2222-3333-444444444444"
|
||||
)
|
||||
root := t.TempDir()
|
||||
tagged := func(rel, title, group string) string {
|
||||
p := filepath.Join(root, rel)
|
||||
writeTestMP3(t, p, map[string]string{
|
||||
"TIT2": title, "TPE1": "Weezer", "TALB": "Weezer",
|
||||
"TXXX": "MusicBrainz Release Group Id\x00" + group,
|
||||
})
|
||||
return p
|
||||
}
|
||||
tagged("Weezer (1994)/01.mp3", "My Name Is Jonas", blue)
|
||||
tagged("Weezer (1994)/02.mp3", "No One Else", blue)
|
||||
greenPath := tagged("Weezer (2001)/01.mp3", "Don't Let Go", green)
|
||||
|
||||
scanner := New(pool, logger, []string{root}, nil)
|
||||
if _, err := scanner.Scan(ctx, nil); err != nil {
|
||||
t.Fatalf("scan: %v", err)
|
||||
}
|
||||
albumsByGroup := func() map[string]int {
|
||||
t.Helper()
|
||||
rows, err := pool.Query(ctx, `SELECT a.release_group_mbid, count(t.id) FROM albums a
|
||||
JOIN tracks t ON t.album_id = a.id WHERE a.title = 'Weezer' GROUP BY a.id, a.release_group_mbid`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
out := map[string]int{}
|
||||
for rows.Next() {
|
||||
var g *string
|
||||
var n int
|
||||
if err := rows.Scan(&g, &n); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if g == nil {
|
||||
t.Fatal("an album with no release group")
|
||||
}
|
||||
out[*g] = n
|
||||
}
|
||||
return out
|
||||
}
|
||||
if got := albumsByGroup(); len(got) != 2 || got[blue] != 2 || got[green] != 1 {
|
||||
t.Fatalf("albums by group = %v, want blue with 2 tracks and green with 1", got)
|
||||
}
|
||||
|
||||
// The green track as the old lookup left it: on the blue album's row,
|
||||
// under an older tag-read version, its own album row gone.
|
||||
if _, err := pool.Exec(ctx, `
|
||||
WITH b AS (SELECT id FROM albums WHERE release_group_mbid = $1)
|
||||
UPDATE tracks SET album_id = (SELECT id FROM b), tag_read_version = 6 WHERE file_path = $2`, blue, greenPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := pool.Exec(ctx, `DELETE FROM albums WHERE release_group_mbid = $1`, green); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := scanner.Scan(ctx, nil); err != nil {
|
||||
t.Fatalf("rescan: %v", err)
|
||||
}
|
||||
if got := albumsByGroup(); len(got) != 2 || got[blue] != 2 || got[green] != 1 {
|
||||
t.Errorf("after the re-read, albums by group = %v, want the green track on its own album", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user