add format-aware tagging and replaygain fallback mapping

Write replaygain gain and peak tags from provider-specific metadata fields, then apply tagging across supported output containers with graceful cover-art fallback so non-FLAC downloads retain metadata.
This commit is contained in:
2026-04-19 22:54:07 +02:00
parent d4643d877e
commit 4da5114a70
4 changed files with 160 additions and 22 deletions

View File

@@ -680,10 +680,8 @@ func (m *Main) ripTrack(ctx context.Context, p provider.Client, source, id, fall
coverPath = tag.CoverPathForTrack(outPath, opts.albumFolder)
}
}
if strings.EqualFold(filepath.Ext(outPath), ".flac") {
if err = m.Tagger.TagFLAC(outPath, tagMeta, coverPath); err != nil {
m.logf("warning: tag failed for %s: %v\n", filepath.Base(outPath), err)
}
if err = m.Tagger.TagFLAC(outPath, tagMeta, coverPath); err != nil {
m.logf("warning: tag failed for %s: %v\n", filepath.Base(outPath), err)
}
if m.Config.Session.Conversion.Enabled {
@@ -847,15 +845,19 @@ func titleFromMetadata(meta map[string]any, fallback string) string {
}
func nestedString(v map[string]any, keys ...string) string {
return stringFromAny(nestedAny(v, keys...))
}
func nestedAny(v map[string]any, keys ...string) any {
cur := any(v)
for _, key := range keys {
m, ok := cur.(map[string]any)
if !ok {
return ""
return nil
}
cur = m[key]
}
return stringFromAny(cur)
return cur
}
func stringFromAny(v any) string {
@@ -904,6 +906,31 @@ func boolFromAny(v any) bool {
return b
}
func replaygainGainFromAny(v any) string {
s := strings.TrimSpace(stringFromAny(v))
if s == "" {
return ""
}
lower := strings.ToLower(s)
if strings.HasSuffix(lower, "db") {
n := strings.TrimSpace(s[:len(s)-2])
if n == "" {
return ""
}
return n + " dB"
}
if _, err := strconv.ParseFloat(s, 64); err == nil {
return s + " dB"
}
return s
}
func replaygainPeakFromAny(v any) string {
return strings.TrimSpace(stringFromAny(v))
}
func trackMetaAlbum(trackMeta map[string]any) map[string]any {
album, ok := trackMeta["album"].(map[string]any)
if !ok {
@@ -967,6 +994,22 @@ func buildTagMetadata(trackMeta map[string]any, title, source, trackID string, o
comment := stringFromAny(trackMeta["comment"])
description := stringFromAny(trackMeta["description"])
lyrics := stringFromAny(trackMeta["lyrics"])
trackGain := replaygainGainFromAny(trackMeta["replaygain_track_gain"])
if trackGain == "" {
trackGain = replaygainGainFromAny(trackMeta["replayGain"])
}
albumGain := replaygainGainFromAny(trackMeta["replaygain_album_gain"])
if albumGain == "" {
albumGain = replaygainGainFromAny(nestedAny(trackMeta, "album", "replaygain_album_gain"))
}
trackPeak := replaygainPeakFromAny(trackMeta["replaygain_track_peak"])
if trackPeak == "" {
trackPeak = replaygainPeakFromAny(trackMeta["peak"])
}
albumPeak := replaygainPeakFromAny(trackMeta["replaygain_album_peak"])
if albumPeak == "" {
albumPeak = replaygainPeakFromAny(nestedAny(trackMeta, "album", "replaygain_album_peak"))
}
sourceAlbumID := nestedString(trackMeta, "album", "id")
sourceArtistID := nestedString(trackMeta, "artist", "id")
@@ -990,8 +1033,10 @@ func buildTagMetadata(trackMeta map[string]any, title, source, trackID string, o
Lyrics: lyrics,
Copyright: stringFromAny(trackMeta["copyright"]),
ISRC: stringFromAny(trackMeta["isrc"]),
ReplaygainTrackGain: stringFromAny(trackMeta["replaygain_track_gain"]),
ReplaygainAlbumGain: stringFromAny(trackMeta["replaygain_album_gain"]),
ReplaygainTrackGain: trackGain,
ReplaygainAlbumGain: albumGain,
ReplaygainTrackPeak: trackPeak,
ReplaygainAlbumPeak: albumPeak,
SourcePlatform: source,
SourceTrackID: trackID,
SourceAlbumID: sourceAlbumID,

View File

@@ -357,3 +357,30 @@ func TestTrackOutputPathSinglesUsesAlbumID(t *testing.T) {
t.Fatalf("trackOutputPath() dir=%q want %q", got, want)
}
}
func TestBuildTagMetadataReplayGainFallbacks(t *testing.T) {
meta := map[string]any{
"replayGain": float64(-7.25),
"peak": float64(0.989),
"album": map[string]any{
"title": "Album",
"replaygain_album_gain": float64(-8.1),
"replaygain_album_peak": float64(1.001),
},
"performer": map[string]any{"name": "Artist"},
}
tags := buildTagMetadata(meta, "Song", "tidal", "t1", ripTrackOptions{})
if tags.ReplaygainTrackGain != "-7.25 dB" {
t.Fatalf("track replaygain gain=%q", tags.ReplaygainTrackGain)
}
if tags.ReplaygainAlbumGain != "-8.1 dB" {
t.Fatalf("album replaygain gain=%q", tags.ReplaygainAlbumGain)
}
if tags.ReplaygainTrackPeak != "0.989" {
t.Fatalf("track replaygain peak=%q", tags.ReplaygainTrackPeak)
}
if tags.ReplaygainAlbumPeak != "1.001" {
t.Fatalf("album replaygain peak=%q", tags.ReplaygainAlbumPeak)
}
}