fix(metadata): preserve selected release artwork and title

This commit is contained in:
zarzet
2026-08-27 22:22:23 +07:00
parent 933a3c49e2
commit 862037a9d5
5 changed files with 150 additions and 39 deletions
+4 -4
View File
@@ -150,9 +150,9 @@ func buildDownloadSuccessResponse(
filePath string,
alreadyExists bool,
) DownloadResponse {
title := result.Title
title := strings.TrimSpace(req.TrackName)
if title == "" {
title = req.TrackName
title = strings.TrimSpace(result.Title)
}
artist := result.Artist
@@ -207,9 +207,9 @@ func buildDownloadSuccessResponse(
upc = req.UPC
}
coverURL := strings.TrimSpace(result.CoverURL)
coverURL := strings.TrimSpace(req.CoverURL)
if coverURL == "" {
coverURL = strings.TrimSpace(req.CoverURL)
coverURL = strings.TrimSpace(result.CoverURL)
}
return DownloadResponse{
+53 -5
View File
@@ -105,9 +105,54 @@ func TestPreferredReleaseMetadataPrefersRequestValues(t *testing.T) {
}
}
func TestBuildDownloadSuccessResponsePrefersProviderCoverURL(t *testing.T) {
func TestBuildDownloadSuccessResponsePreservesRequestedTrackAndCover(t *testing.T) {
req := DownloadRequest{
TrackName: "Album Track Title",
ArtistName: "Artist",
AlbumName: "Original Album",
AlbumArtist: "Artist",
CoverURL: "https://cdn.source.test/original-album.jpg",
ISRC: "USAAA2600001",
}
result := DownloadResult{
Title: "Single Version Title",
Artist: "Artist",
Album: "Single Version Title",
CoverURL: "https://cdn.provider.test/single.jpg",
ISRC: "USAAA2600001",
}
resp := buildDownloadSuccessResponse(
req,
result,
"generic-provider",
"ok",
"/tmp/test.flac",
false,
)
overlayExtensionDownloadMetadata(&resp, &ExtDownloadResult{
Title: result.Title,
Artist: result.Artist,
Album: result.Album,
CoverURL: result.CoverURL,
ISRC: result.ISRC,
})
applyExtensionRequestFallbacks(&resp, req)
if resp.Title != req.TrackName {
t.Fatalf("title = %q, want requested title %q", resp.Title, req.TrackName)
}
if resp.Album != req.AlbumName {
t.Fatalf("album = %q, want requested album %q", resp.Album, req.AlbumName)
}
if resp.CoverURL != req.CoverURL {
t.Fatalf("cover url = %q, want requested album cover %q", resp.CoverURL, req.CoverURL)
}
}
func TestBuildDownloadSuccessResponseFallsBackToProviderTrackAndCover(t *testing.T) {
req := DownloadRequest{
TrackName: "Track",
ArtistName: "Artist",
AlbumName: "Album",
AlbumArtist: "Artist",
@@ -117,20 +162,23 @@ func TestBuildDownloadSuccessResponsePrefersProviderCoverURL(t *testing.T) {
Title: "Track",
Artist: "Artist",
Album: "Album",
CoverURL: "https://cdn.qobuz.test/cover.jpg",
CoverURL: "https://cdn.provider.test/cover.jpg",
}
resp := buildDownloadSuccessResponse(
req,
result,
"qobuz",
"generic-provider",
"ok",
"/tmp/test.flac",
false,
)
if resp.Title != result.Title {
t.Fatalf("title = %q, want provider fallback %q", resp.Title, result.Title)
}
if resp.CoverURL != result.CoverURL {
t.Fatalf("cover url = %q, want %q", resp.CoverURL, result.CoverURL)
t.Fatalf("cover url = %q, want provider fallback %q", resp.CoverURL, result.CoverURL)
}
}
+2 -30
View File
@@ -430,30 +430,7 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
GoLog("[DownloadWithExtensionFallback] Enriching track from extension '%s'...\n", req.Source)
provider := newExtensionProviderWrapper(ext)
trackMeta := &ExtTrackMetadata{
ID: req.SpotifyID,
Name: req.TrackName,
Artists: req.ArtistName,
AlbumName: req.AlbumName,
AlbumArtist: req.AlbumArtist,
DurationMS: req.DurationMS,
CoverURL: req.CoverURL,
ISRC: req.ISRC,
ReleaseDate: req.ReleaseDate,
TrackNumber: req.TrackNumber,
TotalTracks: req.TotalTracks,
DiscNumber: req.DiscNumber,
TotalDiscs: req.TotalDiscs,
ProviderID: req.Source,
AlbumType: req.AlbumType,
Explicit: req.Explicit,
UPC: req.UPC,
Label: req.Label,
Copyright: req.Copyright,
Genre: req.Genre,
Composer: req.Composer,
Comment: req.Comment,
}
trackMeta := buildSourceExtensionTrackMetadata(req)
enrichedTrack, err := provider.EnrichTrackForItemID(trackMeta, req.ItemID)
if shouldAbortCancelledFallback(req.ItemID, err) {
@@ -476,12 +453,7 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
GoLog("[DownloadWithExtensionFallback] Deezer ID from Odesli: %s\n", enrichedTrack.DeezerID)
req.DeezerID = enrichedTrack.DeezerID
}
if enrichedTrack.Name != "" {
req.TrackName = enrichedTrack.Name
}
if enrichedTrack.Artists != "" {
req.ArtistName = enrichedTrack.Artists
}
overlaySourceExtensionTrackIdentity(&req, *enrichedTrack)
overlayStr(&req.AlbumName, enrichedTrack.AlbumName, "AlbumName")
overlayStr(&req.AlbumArtist, enrichedTrack.AlbumArtist, "")
overlayInt(&req.DurationMS, enrichedTrack.DurationMS, "DurationMS")
+43
View File
@@ -72,6 +72,49 @@ func trimKnownProviderPrefix(trackID, providerID string) string {
return trimmedID
}
func buildSourceExtensionTrackMetadata(req DownloadRequest) *ExtTrackMetadata {
return &ExtTrackMetadata{
ID: req.SpotifyID,
Name: req.TrackName,
Artists: req.ArtistName,
AlbumName: req.AlbumName,
AlbumArtist: req.AlbumArtist,
DurationMS: req.DurationMS,
CoverURL: req.CoverURL,
ISRC: req.ISRC,
ReleaseDate: req.ReleaseDate,
TrackNumber: req.TrackNumber,
TotalTracks: req.TotalTracks,
DiscNumber: req.DiscNumber,
TotalDiscs: req.TotalDiscs,
ProviderID: req.Source,
AlbumType: req.AlbumType,
Explicit: req.Explicit,
UPC: req.UPC,
TidalID: req.TidalID,
QobuzID: req.QobuzID,
DeezerID: req.DeezerID,
SpotifyID: req.SpotifyID,
Label: req.Label,
Copyright: req.Copyright,
Genre: req.Genre,
Composer: req.Composer,
Comment: req.Comment,
}
}
func overlaySourceExtensionTrackIdentity(req *DownloadRequest, enrichedTrack ExtTrackMetadata) {
if req == nil {
return
}
// The queued track describes the release selected by the user. Enrichment
// may fill missing identity fields, but must not rename it to another
// release's display title or artist spelling.
overlayStr(&req.TrackName, enrichedTrack.Name, "TrackName")
overlayStr(&req.ArtistName, enrichedTrack.Artists, "ArtistName")
}
func resolvePreferredTrackIDForExtension(ext *loadedExtension, req DownloadRequest, explicitTrackID string) string {
candidates := make([]string, 0, 8)
appendCandidate := func(value string) {
@@ -55,3 +55,51 @@ func TestOverlayExtensionReleaseMetadataDoesNotEraseExistingValues(t *testing.T)
t.Fatalf("existing release metadata changed: %#v", req)
}
}
func TestBuildSourceExtensionTrackMetadataCarriesKnownIdentifiers(t *testing.T) {
req := DownloadRequest{
SpotifyID: "source-id",
TidalID: "alternate-id-a",
QobuzID: "alternate-id-b",
DeezerID: "alternate-id-c",
}
track := buildSourceExtensionTrackMetadata(req)
if track.ID != req.SpotifyID || track.SpotifyID != req.SpotifyID {
t.Fatalf("primary identifier was not propagated: %#v", track)
}
if track.TidalID != req.TidalID || track.QobuzID != req.QobuzID || track.DeezerID != req.DeezerID {
t.Fatalf("alternate identifiers were not propagated: %#v", track)
}
}
func TestOverlaySourceExtensionTrackIdentityPreservesRequestedValues(t *testing.T) {
req := DownloadRequest{
TrackName: "Album Display Title",
ArtistName: "Album Artist Credit",
}
overlaySourceExtensionTrackIdentity(&req, ExtTrackMetadata{
Name: "Single Display Title",
Artists: "Provider Artist Credit",
})
if req.TrackName != "Album Display Title" {
t.Fatalf("track name = %q, want requested title", req.TrackName)
}
if req.ArtistName != "Album Artist Credit" {
t.Fatalf("artist name = %q, want requested credit", req.ArtistName)
}
}
func TestOverlaySourceExtensionTrackIdentityFillsMissingValues(t *testing.T) {
req := DownloadRequest{}
overlaySourceExtensionTrackIdentity(&req, ExtTrackMetadata{
Name: "Resolved Title",
Artists: "Resolved Artist",
})
if req.TrackName != "Resolved Title" || req.ArtistName != "Resolved Artist" {
t.Fatalf("missing identity fields were not enriched: %#v", req)
}
}