diff --git a/go_backend/exports_reenrich.go b/go_backend/exports_reenrich.go index 9b8eb7e2..8484290f 100644 --- a/go_backend/exports_reenrich.go +++ b/go_backend/exports_reenrich.go @@ -74,11 +74,30 @@ func (r *reEnrichRequest) lyricsSidecarEnabled() bool { return mode == "external" || mode == "both" } +// reEnrichSameRelease reports whether the candidate track appears to come +// from the same release as the file's existing album. An ISRC identifies a +// recording, not a release: the same song often also resolves to a +// compilation, whose album name, cover, and track positions must not +// replace the original release's. +func reEnrichSameRelease(currentAlbum, candidateAlbum string) bool { + if isPlaceholderReEnrichValue(currentAlbum) || + strings.TrimSpace(candidateAlbum) == "" { + return true + } + return titlesMatch(currentAlbum, candidateAlbum) +} + func applyReEnrichTrackMetadata(req *reEnrichRequest, track ExtTrackMetadata) { if req == nil { return } + sameRelease := reEnrichSameRelease(req.AlbumName, track.AlbumName) + if !sameRelease { + GoLog("[ReEnrich] Candidate album %q differs from file album %q; keeping release identity (album, cover, positions, date)\n", + track.AlbumName, req.AlbumName) + } + if track.SpotifyID != "" { req.SpotifyID = track.SpotifyID } else if track.DeezerID != "" { @@ -98,14 +117,16 @@ func applyReEnrichTrackMetadata(req *reEnrichRequest, track ExtTrackMetadata) { if track.Artists != "" { req.ArtistName = track.Artists } - if track.AlbumName != "" { - req.AlbumName = track.AlbumName - } - if track.AlbumArtist != "" { - req.AlbumArtist = track.AlbumArtist + if sameRelease { + if track.AlbumName != "" { + req.AlbumName = track.AlbumName + } + if track.AlbumArtist != "" { + req.AlbumArtist = track.AlbumArtist + } } } - if req.shouldUpdateField("track_info") { + if sameRelease && req.shouldUpdateField("track_info") { if track.TrackNumber > 0 { req.TrackNumber = track.TrackNumber } @@ -120,14 +141,14 @@ func applyReEnrichTrackMetadata(req *reEnrichRequest, track ExtTrackMetadata) { } } if req.shouldUpdateField("release_info") { - if track.ReleaseDate != "" { + if sameRelease && track.ReleaseDate != "" { req.ReleaseDate = track.ReleaseDate } if track.ISRC != "" { req.ISRC = track.ISRC } } - if req.shouldUpdateField("cover") { + if sameRelease && req.shouldUpdateField("cover") { if coverURL := track.ResolvedCoverURL(); coverURL != "" { req.CoverURL = coverURL } diff --git a/go_backend/exports_test.go b/go_backend/exports_test.go index dc0a8ccb..dc1e2f85 100644 --- a/go_backend/exports_test.go +++ b/go_backend/exports_test.go @@ -352,7 +352,7 @@ func TestApplyReEnrichTrackMetadataPreservesExistingReleaseDateWhenCandidateMiss } applyReEnrichTrackMetadata(&req, ExtTrackMetadata{ - AlbumName: "Resolved Album", + AlbumName: "Original Album (Deluxe)", ReleaseDate: "", ISRC: "", }) @@ -360,7 +360,7 @@ func TestApplyReEnrichTrackMetadataPreservesExistingReleaseDateWhenCandidateMiss if req.ReleaseDate != "2024-01-01" { t.Fatalf("release date = %q, want existing value preserved", req.ReleaseDate) } - if req.AlbumName != "Resolved Album" { + if req.AlbumName != "Original Album (Deluxe)" { t.Fatalf("album = %q, want updated album", req.AlbumName) } if req.ISRC != "REQ123" { @@ -368,6 +368,43 @@ func TestApplyReEnrichTrackMetadataPreservesExistingReleaseDateWhenCandidateMiss } } +func TestApplyReEnrichTrackMetadataKeepsReleaseIdentityOnAlbumMismatch(t *testing.T) { + req := reEnrichRequest{ + TrackName: "Afsana", + ArtistName: "Artist Name", + AlbumName: "Original Soundtrack", + CoverURL: "https://covers/original.jpg", + TrackNumber: 3, + ReleaseDate: "2005-01-01", + } + + applyReEnrichTrackMetadata(&req, ExtTrackMetadata{ + Name: "Afsana", + Artists: "Artist Name", + AlbumName: "The Hit Machine", + CoverURL: "https://covers/compilation.jpg", + TrackNumber: 17, + ReleaseDate: "2010-01-01", + ISRC: "NEW123", + }) + + if req.AlbumName != "Original Soundtrack" { + t.Fatalf("album = %q, want original release kept", req.AlbumName) + } + if req.CoverURL != "https://covers/original.jpg" { + t.Fatalf("cover = %q, want original release cover kept", req.CoverURL) + } + if req.TrackNumber != 3 { + t.Fatalf("track number = %d, want original position kept", req.TrackNumber) + } + if req.ReleaseDate != "2005-01-01" { + t.Fatalf("release date = %q, want original date kept", req.ReleaseDate) + } + if req.ISRC != "NEW123" { + t.Fatalf("isrc = %q, want recording-level fields still enriched", req.ISRC) + } +} + func TestSelectBestReEnrichTrackPrefersCandidateWithReleaseDate(t *testing.T) { req := reEnrichRequest{ TrackName: "Song Title",