feat: carry extension download metadata through host pipeline and avoid FLAC-only genre/label pre-embed on non-FLAC files

This commit is contained in:
zarzet
2026-04-14 19:20:55 +07:00
parent 10d30ac1a4
commit a4f11a5b30
4 changed files with 76 additions and 7 deletions
+1 -1
View File
@@ -168,7 +168,7 @@ Interested in contributing? Check out the [Contributing Guide](CONTRIBUTING.md)
|---|---|---|---|---|
| [hifi-api](https://github.com/binimum/hifi-api) | [music.binimum.org](https://music.binimum.org) | [qqdl.site](https://qqdl.site) | [squid.wtf](https://squid.wtf) | [spotisaver.net](https://spotisaver.net) |
| [dabmusic.xyz](https://dabmusic.xyz) | [AfkarXYZ](https://github.com/afkarxyz) | [LRCLib](https://lrclib.net) | [Paxsenix](https://lyrics.paxsenix.org) | [Cobalt](https://cobalt.tools) |
| [qwkuns.me](https://qwkuns.me) | [SpotubeDL](https://spotubedl.com) | [Song.link](https://song.link) | [IDHS](https://github.com/sjdonado/idonthavespotify) | |
| [qwkuns.me](https://qwkuns.me) | [SpotubeDL](https://spotubedl.com) | [Song.link](https://song.link) | [IDHS](https://github.com/sjdonado/idonthavespotify) | [Monochrome](https://monochrome.tf) |
---
+46
View File
@@ -118,9 +118,16 @@ type ExtDownloadResult struct {
AlbumArtist string `json:"album_artist,omitempty"`
TrackNumber int `json:"track_number,omitempty"`
DiscNumber int `json:"disc_number,omitempty"`
TotalTracks int `json:"total_tracks,omitempty"`
TotalDiscs int `json:"total_discs,omitempty"`
ReleaseDate string `json:"release_date,omitempty"`
CoverURL string `json:"cover_url,omitempty"`
ISRC string `json:"isrc,omitempty"`
Genre string `json:"genre,omitempty"`
Label string `json:"label,omitempty"`
Copyright string `json:"copyright,omitempty"`
Composer string `json:"composer,omitempty"`
LyricsLRC string `json:"lyrics_lrc,omitempty"`
DecryptionKey string `json:"decryption_key,omitempty"`
Decryption *DownloadDecryptionInfo `json:"decryption,omitempty"`
}
@@ -1415,6 +1422,12 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
if result.DiscNumber > 0 {
resp.DiscNumber = result.DiscNumber
}
if result.TotalTracks > 0 {
resp.TotalTracks = result.TotalTracks
}
if result.TotalDiscs > 0 {
resp.TotalDiscs = result.TotalDiscs
}
if result.ReleaseDate != "" {
resp.ReleaseDate = result.ReleaseDate
}
@@ -1424,8 +1437,29 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
if result.ISRC != "" {
resp.ISRC = result.ISRC
}
if result.Genre != "" {
resp.Genre = result.Genre
}
if result.Label != "" {
resp.Label = result.Label
}
if result.Copyright != "" {
resp.Copyright = result.Copyright
}
if result.Composer != "" {
resp.Composer = result.Composer
}
if result.LyricsLRC != "" {
resp.LyricsLRC = result.LyricsLRC
}
}
if req.TrackName != "" && resp.Title == "" {
resp.Title = req.TrackName
}
if req.ArtistName != "" && resp.Artist == "" {
resp.Artist = req.ArtistName
}
if req.AlbumName != "" && resp.Album == "" {
resp.Album = req.AlbumName
}
@@ -1444,9 +1478,18 @@ func DownloadWithExtensionFallback(req DownloadRequest) (*DownloadResponse, erro
if req.DiscNumber > 0 && resp.DiscNumber == 0 {
resp.DiscNumber = req.DiscNumber
}
if req.TotalTracks > 0 && resp.TotalTracks == 0 {
resp.TotalTracks = req.TotalTracks
}
if req.TotalDiscs > 0 && resp.TotalDiscs == 0 {
resp.TotalDiscs = req.TotalDiscs
}
if req.CoverURL != "" && resp.CoverURL == "" {
resp.CoverURL = req.CoverURL
}
if req.Composer != "" && resp.Composer == "" {
resp.Composer = req.Composer
}
return resp, nil
}
@@ -1877,6 +1920,9 @@ func canEmbedGenreLabel(filePath string) bool {
if path == "" || strings.HasPrefix(path, "content://") || strings.HasPrefix(path, "/proc/self/fd/") {
return false
}
if strings.ToLower(filepath.Ext(path)) != ".flac" {
return false
}
if !filepath.IsAbs(path) {
return false
}
+7
View File
@@ -185,6 +185,10 @@ func TestCanEmbedGenreLabelRequiresExistingAbsoluteLocalFile(t *testing.T) {
if err := os.WriteFile(tempFile, []byte("fLaC"), 0644); err != nil {
t.Fatalf("failed to create temp file: %v", err)
}
tempM4A := filepath.Join(t.TempDir(), "track.m4a")
if err := os.WriteFile(tempM4A, []byte("not-flac"), 0644); err != nil {
t.Fatalf("failed to create temp m4a file: %v", err)
}
if canEmbedGenreLabel("relative.flac") {
t.Fatal("expected relative path to be rejected")
@@ -195,6 +199,9 @@ func TestCanEmbedGenreLabelRequiresExistingAbsoluteLocalFile(t *testing.T) {
if canEmbedGenreLabel(filepath.Join(t.TempDir(), "missing.flac")) {
t.Fatal("expected missing file to be rejected")
}
if canEmbedGenreLabel(tempM4A) {
t.Fatalf("expected non-FLAC file %q to be rejected", tempM4A)
}
if !canEmbedGenreLabel(tempFile) {
t.Fatalf("expected existing absolute file %q to be accepted", tempFile)
}
+22 -6
View File
@@ -3704,6 +3704,8 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
) {
final backendTrackNum = _parsePositiveInt(backendResult['track_number']);
final backendDiscNum = _parsePositiveInt(backendResult['disc_number']);
final backendTotalTracks = _parsePositiveInt(backendResult['total_tracks']);
final backendTotalDiscs = _parsePositiveInt(backendResult['total_discs']);
final backendYear = normalizeOptionalString(
backendResult['release_date'] as String?,
);
@@ -3731,7 +3733,9 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
backendIsrc != null ||
backendCoverUrl != null ||
backendAlbumArtist != null ||
backendComposer != null;
backendComposer != null ||
backendTotalTracks != null ||
backendTotalDiscs != null;
if (!hasOverrides) {
return baseTrack;
@@ -3750,12 +3754,12 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
isrc: backendIsrc ?? baseTrack.isrc,
trackNumber: backendTrackNum ?? baseTrack.trackNumber,
discNumber: backendDiscNum ?? baseTrack.discNumber,
totalDiscs: baseTrack.totalDiscs,
totalDiscs: backendTotalDiscs ?? baseTrack.totalDiscs,
releaseDate: backendYear ?? baseTrack.releaseDate,
deezerId: baseTrack.deezerId,
availability: baseTrack.availability,
albumType: baseTrack.albumType,
totalTracks: baseTrack.totalTracks,
totalTracks: backendTotalTracks ?? baseTrack.totalTracks,
composer: backendComposer ?? baseTrack.composer,
source: baseTrack.source,
);
@@ -5808,12 +5812,15 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
final backendYear = result['release_date'] as String?;
final backendTrackNum = result['track_number'] as int?;
final backendDiscNum = result['disc_number'] as int?;
final backendTotalTracks = result['total_tracks'] as int?;
final backendTotalDiscs = result['total_discs'] as int?;
final backendBitDepth = result['actual_bit_depth'] as int?;
final backendSampleRate = result['actual_sample_rate'] as int?;
final backendISRC = result['isrc'] as String?;
final backendGenre = result['genre'] as String?;
final backendLabel = result['label'] as String?;
final backendCopyright = result['copyright'] as String?;
final backendComposer = result['composer'] as String?;
final effectiveGenre =
normalizeOptionalString(backendGenre) ??
normalizeOptionalString(genre) ??
@@ -5921,11 +5928,17 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
trackNumber: (backendTrackNum != null && backendTrackNum > 0)
? backendTrackNum
: trackToDownload.trackNumber,
totalTracks: trackToDownload.totalTracks,
totalTracks:
(backendTotalTracks != null && backendTotalTracks > 0)
? backendTotalTracks
: trackToDownload.totalTracks,
discNumber: (backendDiscNum != null && backendDiscNum > 0)
? backendDiscNum
: trackToDownload.discNumber,
totalDiscs: trackToDownload.totalDiscs,
totalDiscs:
(backendTotalDiscs != null && backendTotalDiscs > 0)
? backendTotalDiscs
: trackToDownload.totalDiscs,
duration: trackToDownload.duration,
releaseDate: (backendYear != null && backendYear.isNotEmpty)
? backendYear
@@ -5934,7 +5947,10 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
bitDepth: historyBitDepth,
sampleRate: historySampleRate,
genre: effectiveGenre,
composer: trackToDownload.composer,
composer:
(backendComposer != null && backendComposer.isNotEmpty)
? backendComposer
: trackToDownload.composer,
label: effectiveLabel,
copyright: effectiveCopyright,
),