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
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>
This commit is contained in:
@@ -13,6 +13,7 @@ import (
|
||||
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/audit"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/musicbrainz"
|
||||
"git.fabledsword.com/bvandeusen/minstrel/internal/notifications"
|
||||
syncpkg "git.fabledsword.com/bvandeusen/minstrel/internal/sync"
|
||||
)
|
||||
@@ -33,6 +34,10 @@ import (
|
||||
// Anything less certain stays with the operator.
|
||||
|
||||
const (
|
||||
// trackListFetchesPerPass is how many albums' track lists a pass may ask
|
||||
// MusicBrainz for, when the catalogue has never read them. The resolver
|
||||
// runs hourly, so a backlog drains over a few hours without a burst.
|
||||
trackListFetchesPerPass = 5
|
||||
// slotFit is how close a file must be to a slot's MusicBrainz length to be
|
||||
// that slot's song, and slotOther how far away every length of a slot's
|
||||
// title must be for the file to be another song's.
|
||||
@@ -143,9 +148,14 @@ func dismissDistinct(
|
||||
// to settled.
|
||||
func settleWrongSlots(
|
||||
ctx context.Context, pool *pgxpool.Pool, logger *slog.Logger, groups []*resolveGroup, settled map[pgtype.UUID]bool,
|
||||
fetch TrackListFetcher,
|
||||
) (int, []string) {
|
||||
q := dbq.New(pool)
|
||||
tracksByGroup := map[string][]dbq.MbReleaseTrack{}
|
||||
fetches := trackListFetchesPerPass
|
||||
if fetch == nil {
|
||||
fetches = 0
|
||||
}
|
||||
removed := 0
|
||||
var names []string
|
||||
for _, g := range groups {
|
||||
@@ -163,6 +173,18 @@ func settleWrongSlots(
|
||||
logger.Warn("duplicate resolve: reading the album's track list failed", "release_group", rg, "err", err)
|
||||
continue
|
||||
}
|
||||
if len(tracks) == 0 && fetches > 0 && neverRead(ctx, q, rg) {
|
||||
fetches--
|
||||
if err := fetch(ctx, rg); err != nil {
|
||||
logger.Info("duplicate resolve: fetching the album's track list failed", "release_group", rg, "err", err)
|
||||
if errors.Is(err, musicbrainz.ErrUnreachable) {
|
||||
fetches = 0
|
||||
}
|
||||
} else if tracks, err = q.ListMBReleaseTracksForGroup(ctx, rg); err != nil {
|
||||
logger.Warn("duplicate resolve: reading the album's track list failed", "release_group", rg, "err", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
tracksByGroup[rg] = tracks
|
||||
}
|
||||
copies := make([]slotCopy, len(g.members))
|
||||
@@ -187,6 +209,14 @@ func settleWrongSlots(
|
||||
return removed, names
|
||||
}
|
||||
|
||||
// neverRead reports whether the catalogue has never read a release group's
|
||||
// releases. A group read and found empty is not asked about again: the
|
||||
// catalogue's own refresh revisits it.
|
||||
func neverRead(ctx context.Context, q *dbq.Queries, rg string) bool {
|
||||
g, err := q.GetMBReleaseGroup(ctx, rg)
|
||||
return errors.Is(err, pgx.ErrNoRows) || (err == nil && !g.ReleasesRefreshedAt.Valid)
|
||||
}
|
||||
|
||||
// removeWrongSlots deletes each loser's file, then marks its track missing in
|
||||
// the same transaction that closes the group. The row is kept, with its likes
|
||||
// and plays: it is the slot, and a good copy fetched again takes it over. A
|
||||
|
||||
Reference in New Issue
Block a user