fix: a second copy of a track counts once, joining words don't part two titles, and a newer matcher retries an older one's refusals (M502 #5569)
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m18s
release / go (push) Successful in 1m35s
release / integration (push) Failing after 5m33s
release / android (push) Successful in 5m47s
release / Build signed APK (releases and dev) (push) Successful in 6m4s
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
release / govulncheck (push) Successful in 15s
release / web (push) Successful in 1m18s
release / go (push) Successful in 1m35s
release / integration (push) Failing after 5m33s
release / android (push) Successful in 5m47s
release / Build signed APK (releases and dev) (push) Successful in 6m4s
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 second run's refusals were mostly albums holding a track twice (a two-track single with three files), which no edition can pair, and release names that differ only in "+" against "/". Tracks are now read once per disc, number and title, and "and", "&" and "+" count for nothing when titles are compared; an edition's own title also counts as the album's name. library_album_matches records which matcher version decided each album. Refusals by an older version are matched again, even after the listing is done, so an improvement reaches them without a migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,15 @@ const libraryMatchBudget = 2 * time.Minute
|
||||
// libraryMatchBatch is how many albums one query hands the matching.
|
||||
const libraryMatchBatch = 25
|
||||
|
||||
// libraryMatcher is the matching's version. Raise it when the matching
|
||||
// changes in a way that could match an album it refused: albums an older
|
||||
// version refused are matched again, even after the listing is done.
|
||||
//
|
||||
// 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
|
||||
|
||||
// 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
|
||||
// happened so later changes like unwanting hold and dont auto import from
|
||||
@@ -39,7 +48,8 @@ const libraryMatchBatch = 25
|
||||
// of the albums no match was found for.
|
||||
//
|
||||
// Each album decided is recorded in library_album_matches, so an album taken
|
||||
// off the list stays off, and once done the listing never runs again.
|
||||
// off the list stays off. Once done the listing runs again only for albums
|
||||
// an older matcher refused (libraryMatcher).
|
||||
func (s *Service) listLibrary(ctx context.Context, res *PassResult) error {
|
||||
q := dbq.New(s.pool)
|
||||
state, err := q.GetLibraryListing(ctx)
|
||||
@@ -47,7 +57,13 @@ func (s *Service) listLibrary(ctx context.Context, res *PassResult) error {
|
||||
return fmt.Errorf("wanted: read the library listing: %w", err)
|
||||
}
|
||||
if state.LibraryListedAt.Valid {
|
||||
return nil
|
||||
stale, err := q.CountAlbumsToRematch(ctx, libraryMatcher)
|
||||
if err != nil {
|
||||
return fmt.Errorf("wanted: count refusals to retry: %w", err)
|
||||
}
|
||||
if stale == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
cutoff := state.LibraryListingStartedAt
|
||||
if !cutoff.Valid {
|
||||
@@ -67,7 +83,8 @@ func (s *Service) listLibrary(ctx context.Context, res *PassResult) error {
|
||||
|
||||
deadline := s.now().Add(libraryMatchBudget)
|
||||
for {
|
||||
albums, err := q.ListAlbumsToMatch(ctx, dbq.ListAlbumsToMatchParams{Cutoff: cutoff, MaxRows: libraryMatchBatch})
|
||||
albums, err := q.ListAlbumsToMatch(ctx, dbq.ListAlbumsToMatchParams{
|
||||
Cutoff: cutoff, Matcher: libraryMatcher, MaxRows: libraryMatchBatch})
|
||||
if err != nil {
|
||||
return fmt.Errorf("wanted: albums to match: %w", err)
|
||||
}
|
||||
@@ -107,7 +124,8 @@ func (s *Service) listAlbum(ctx context.Context, q *dbq.Queries, a dbq.ListAlbum
|
||||
}
|
||||
if !m.OK {
|
||||
s.logger.Info("wanted: no MusicBrainz match for a library album", "album", a.Title, "artist", a.ArtistName, "why", m.Detail)
|
||||
return 0, q.RecordAlbumMatch(ctx, dbq.RecordAlbumMatchParams{AlbumID: a.ID, Outcome: "unmatched", Detail: m.Detail})
|
||||
return 0, q.RecordAlbumMatch(ctx, dbq.RecordAlbumMatchParams{
|
||||
AlbumID: a.ID, Outcome: "unmatched", Detail: m.Detail, Matcher: libraryMatcher})
|
||||
}
|
||||
var listed int64
|
||||
err = pgx.BeginFunc(ctx, s.pool, func(tx pgx.Tx) error {
|
||||
@@ -124,7 +142,7 @@ func (s *Service) listAlbum(ctx context.Context, q *dbq.Queries, a dbq.ListAlbum
|
||||
}
|
||||
listed = n
|
||||
return tq.RecordAlbumMatch(ctx, dbq.RecordAlbumMatchParams{
|
||||
AlbumID: a.ID, Outcome: "listed", Method: m.Method, ReleaseGroupMbid: m.Group,
|
||||
AlbumID: a.ID, Outcome: "listed", Method: m.Method, ReleaseGroupMbid: m.Group, Matcher: libraryMatcher,
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user