From 7ef1fca90c58e60d1bc82a2b2c73dc27b8eea1f0 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Sat, 10 Oct 2026 18:14:56 -0400 Subject: [PATCH] fix: an album holding every track of an edition, and more besides, is that release group (M502 #5569) Savant's "Void" folder holds all 23 tracks of the VOID (DLC) edition plus 20 more, and was refused at 23 of 43. A whole edition of three or more tracks now matches whatever else the folder holds; singles and two-track releases still need most of the album's tracks, since many albums hold their songs. Matcher version 4 retries the refusals. Co-Authored-By: Claude Opus 5.5 --- internal/wanted/library.go | 3 ++- internal/wanted/library_test.go | 5 ++++- internal/wanted/match.go | 13 ++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/internal/wanted/library.go b/internal/wanted/library.go index ea56759c..051fbbf1 100644 --- a/internal/wanted/library.go +++ b/internal/wanted/library.go @@ -30,7 +30,8 @@ const libraryMatchBatch = 25 // 1 tags, release, discography and search, checked by title and length // 2 titles alone under the album's own name; a refusal names the track // 3 a second copy of a track counts once; joining words count for nothing -const libraryMatcher = 3 +// 4 an album holding every track of an edition, and more, is that group +const libraryMatcher = 4 // listLibrary puts the library's albums on the wanted list as held, once // (operator, 2026-10-10: "make a record saying that the import has diff --git a/internal/wanted/library_test.go b/internal/wanted/library_test.go index 7f1a6187..f503d67d 100644 --- a/internal/wanted/library_test.go +++ b/internal/wanted/library_test.go @@ -277,9 +277,12 @@ func TestTrackAgreement(t *testing.T) { if len(copies) != 2 { t.Errorf("a second copy of a track is read once: %+v", copies) } - if agrees(3, 4) || !agrees(4, 5) || agrees(0, 0) { + if agrees(3, 4, 0) || !agrees(4, 5, 0) || agrees(0, 0, 0) { t.Error("agrees: 80% of the album's tracks, and an album has tracks") } + if !agrees(23, 43, 23) || agrees(2, 10, 2) || agrees(22, 43, 23) { + t.Error("agrees: a whole edition of three or more tracks, with more besides") + } } // A refusal by an older matcher is matched again once the matching improves, diff --git a/internal/wanted/match.go b/internal/wanted/match.go index 9d9d8c99..f98f7b1f 100644 --- a/internal/wanted/match.go +++ b/internal/wanted/match.go @@ -170,9 +170,12 @@ func minutes(ms int) string { return fmt.Sprintf("%d:%02d", sec/60, sec%60) } -// agrees: enough of the album's tracks agree for the edition to be it. -func agrees(n, tracks int) bool { - return tracks > 0 && n*10 >= tracks*matchAgreement +// agrees: enough of the album's tracks agree for the edition to be it, or +// the album holds every track of the edition and more besides (a folder +// with the deluxe edition and its demos). A single or a two-track release +// is not taken on containment: too many albums hold its songs. +func agrees(n, tracks, edition int) bool { + return tracks > 0 && (n*10 >= tracks*matchAgreement || (edition >= 3 && n == edition)) } // sameTitle: the same words, not merely one holding the other. "And", @@ -243,7 +246,7 @@ func (s *Service) matchAlbum(ctx context.Context, a dbq.ListAlbumsToMatchRow, tr if err := check(discography); err != nil { return albumMatch{}, err } - if !agrees(bestN, len(tracks)) { + if !agrees(bestN, len(tracks), bestEdition) { found, err := s.searchCandidates(ctx, a) if err != nil { return albumMatch{}, err @@ -252,7 +255,7 @@ func (s *Service) matchAlbum(ctx context.Context, a dbq.ListAlbumsToMatchRow, tr return albumMatch{}, err } } - if agrees(bestN, len(tracks)) { + if agrees(bestN, len(tracks), bestEdition) { best.OK = true return best, nil }