Fix release matching for featured artists and credit annotations
ci / module boundaries / boundaries (push) Successful in 1m11s
ci / api / api (push) Successful in 1m54s
ci / mobile / mobile (Metro-бандл Android) (push) Failing after 6m50s
ci / ts / ts (packages + web) (push) Failing after 6m19s
ci / db / db (push) Failing after 11s

This commit is contained in:
mrleo1nid committed 2026-10-30 10:23:12 +03:00
1 parent f4681da876
commit fd17c06397
7 files changed
+146 -12

No files matched your search

+42 -3
View File
@@ -5,6 +5,7 @@ import (
"encoding/hex"
"encoding/json"
"math"
"regexp"
"sort"
"strings"
@@ -70,7 +71,11 @@ func releaseHash(files []File) string {
entries = append(entries, entry{f.ID, f.Meta, f.DurationMs, f.Tags})
}
sort.Slice(entries, func(i, j int) bool { return entries[i].ID.String() < entries[j].ID.String() })
b, _ := json.Marshal(entries)
// Invalidate persisted reports when matching rules change, as well as tags.
b, _ := json.Marshal(struct {
Version int
Files []entry
}{2, entries})
h := sha256.Sum256(b)
return hex.EncodeToString(h[:])
}
@@ -111,6 +116,39 @@ func batchReleaseQuery(files []File) (musicbrainz.Query, bool) {
}
return q, q.Artist != ""
}
// Only credit annotations are removed for tentative matching. Version labels
// such as live, remix or instrumental remain significant.
var releaseTitleCredits = regexp.MustCompile(`(?i)\s*[\(\[]\s*(?:feat\.?|ft\.?|featuring|prod\.?|produced by)\s+[^()\[\]]+[\)\]]\s*$`)
func releaseTitleKey(title string) string {
for {
cleaned := releaseTitleCredits.ReplaceAllString(title, "")
if cleaned == title {
return meta.Key(title)
}
title = cleaned
}
}
func sameReleaseArtists(a, b string) bool {
left := meta.SplitArtists(strings.ToLower(a), nil)
right := meta.SplitArtists(strings.ToLower(b), nil)
if len(left) == 0 || len(left) != len(right) {
return false
}
credits := make(map[string]bool, len(left))
for _, artist := range left {
credits[meta.Key(artist.Name)] = true
}
for _, artist := range right {
if !credits[meta.Key(artist.Name)] {
return false
}
}
return true
}
func trackScore(f File, t musicbrainz.Track, albumArtist string) int {
if f.Meta == nil {
return 0
@@ -137,8 +175,9 @@ func trackScore(f File, t musicbrainz.Track, albumArtist string) int {
if title && (t.DurationMs == 0 || f.DurationMs == nil) {
return 70
}
if delta <= 2000 && m.Track != nil && *m.Track == t.Position && (m.Disc == nil && t.Disc == 1 || m.Disc != nil && *m.Disc == t.Disc) && meta.Key(m.Artist) == meta.Key(t.Artist) {
return 60
if delta <= 2000 && m.Track != nil && *m.Track == t.Position && (m.Disc == nil && t.Disc == 1 || m.Disc != nil && *m.Disc == t.Disc) &&
releaseTitleKey(m.Title) != "" && releaseTitleKey(m.Title) == releaseTitleKey(t.Title) && sameReleaseArtists(m.Artist, t.Artist) {
return 75
}
return 0
}