From 08d648cfa8b6f2b384b188f930e78258efcf6955 Mon Sep 17 00:00:00 2001 From: zarzet Date: Sun, 26 Jul 2026 01:28:25 +0700 Subject: [PATCH] fix(reenrich): allow correcting stale release metadata --- go_backend/exports_reenrich.go | 10 ++++++- go_backend/exports_test.go | 38 ++++++++++++++++++++++++ lib/screens/local_album_screen.dart | 1 + lib/screens/queue_tab_batch_actions.dart | 1 + lib/screens/track_metadata_lyrics.dart | 1 + 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/go_backend/exports_reenrich.go b/go_backend/exports_reenrich.go index 8484290f..51784dbd 100644 --- a/go_backend/exports_reenrich.go +++ b/go_backend/exports_reenrich.go @@ -43,6 +43,10 @@ type reEnrichRequest struct { DurationMs int64 `json:"duration_ms"` SearchOnline bool `json:"search_online"` UpdateFields []string `json:"update_fields,omitempty"` + // ReplaceReleaseMetadata lets an explicit user re-enrich action repair a + // stale album identity (for example, a playlist name stored as ALBUM). + // Older callers keep the conservative mismatch-preservation behavior. + ReplaceReleaseMetadata bool `json:"replace_release_metadata,omitempty"` } // shouldUpdateField returns true if the given field group should be updated. @@ -92,10 +96,14 @@ func applyReEnrichTrackMetadata(req *reEnrichRequest, track ExtTrackMetadata) { return } - sameRelease := reEnrichSameRelease(req.AlbumName, track.AlbumName) + albumMatches := reEnrichSameRelease(req.AlbumName, track.AlbumName) + sameRelease := req.ReplaceReleaseMetadata || albumMatches if !sameRelease { GoLog("[ReEnrich] Candidate album %q differs from file album %q; keeping release identity (album, cover, positions, date)\n", track.AlbumName, req.AlbumName) + } else if req.ReplaceReleaseMetadata && !albumMatches { + GoLog("[ReEnrich] Candidate album %q differs from file album %q; replacing release identity as requested\n", + track.AlbumName, req.AlbumName) } if track.SpotifyID != "" { diff --git a/go_backend/exports_test.go b/go_backend/exports_test.go index dc1e2f85..47dfc320 100644 --- a/go_backend/exports_test.go +++ b/go_backend/exports_test.go @@ -405,6 +405,44 @@ func TestApplyReEnrichTrackMetadataKeepsReleaseIdentityOnAlbumMismatch(t *testin } } +func TestApplyReEnrichTrackMetadataReplacesStalePlaylistAlbumWhenRequested(t *testing.T) { + req := reEnrichRequest{ + TrackName: "Song", + ArtistName: "Artist", + AlbumName: "Road Trip Playlist", + CoverURL: "https://covers/playlist.jpg", + TrackNumber: 42, + ReleaseDate: "", + ReplaceReleaseMetadata: true, + } + + applyReEnrichTrackMetadata(&req, ExtTrackMetadata{ + Name: "Song", + Artists: "Artist", + AlbumName: "Actual Album", + AlbumArtist: "Artist", + CoverURL: "https://covers/album.jpg", + TrackNumber: 3, + ReleaseDate: "2024-01-01", + }) + + if req.AlbumName != "Actual Album" { + t.Fatalf("album = %q, want actual album", req.AlbumName) + } + if req.AlbumArtist != "Artist" { + t.Fatalf("album artist = %q", req.AlbumArtist) + } + if req.CoverURL != "https://covers/album.jpg" { + t.Fatalf("cover = %q", req.CoverURL) + } + if req.TrackNumber != 3 { + t.Fatalf("track number = %d", req.TrackNumber) + } + if req.ReleaseDate != "2024-01-01" { + t.Fatalf("release date = %q", req.ReleaseDate) + } +} + func TestSelectBestReEnrichTrackPrefersCandidateWithReleaseDate(t *testing.T) { req := reEnrichRequest{ TrackName: "Song Title", diff --git a/lib/screens/local_album_screen.dart b/lib/screens/local_album_screen.dart index a66b3423..218528d8 100644 --- a/lib/screens/local_album_screen.dart +++ b/lib/screens/local_album_screen.dart @@ -454,6 +454,7 @@ class _LocalAlbumScreenState extends ConsumerState 'copyright': '', 'duration_ms': durationMs, 'search_online': true, + 'replace_release_metadata': true, // ignore: use_null_aware_elements if (updateFields != null) 'update_fields': updateFields, }; diff --git a/lib/screens/queue_tab_batch_actions.dart b/lib/screens/queue_tab_batch_actions.dart index d8b46d79..ee89630d 100644 --- a/lib/screens/queue_tab_batch_actions.dart +++ b/lib/screens/queue_tab_batch_actions.dart @@ -30,6 +30,7 @@ extension _QueueTabBatchActions on _QueueTabState { 'copyright': '', 'duration_ms': durationMs, 'search_online': true, + 'replace_release_metadata': true, // ignore: use_null_aware_elements if (updateFields != null) 'update_fields': updateFields, }; diff --git a/lib/screens/track_metadata_lyrics.dart b/lib/screens/track_metadata_lyrics.dart index 6a7063aa..fc698219 100644 --- a/lib/screens/track_metadata_lyrics.dart +++ b/lib/screens/track_metadata_lyrics.dart @@ -970,6 +970,7 @@ extension _TrackMetadataLyricsAndSaving on _TrackMetadataScreenState { 'composer': composer ?? '', 'duration_ms': durationMs, 'search_online': true, + 'replace_release_metadata': true, }; final result = await PlatformBridge.reEnrichFile(request);