From 0100e8893a06370abeeea5bd36879315c4fe58dc Mon Sep 17 00:00:00 2001 From: ranokay Date: Tue, 26 May 2026 20:26:40 +0300 Subject: [PATCH] fix: parse long embedded lyrics before truncation --- model/metadata/map_mediafile.go | 2 +- model/metadata/map_mediafile_test.go | 37 ++++++++++++++++++++++++++++ model/metadata/metadata.go | 10 ++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/model/metadata/map_mediafile.go b/model/metadata/map_mediafile.go index 2fbf893ac..ecb0a9195 100644 --- a/model/metadata/map_mediafile.go +++ b/model/metadata/map_mediafile.go @@ -130,7 +130,7 @@ func (md Metadata) mapGain(rg, r128 model.TagName) *float64 { } func (md Metadata) mapLyrics() string { - rawLyrics := md.Pairs(model.TagLyrics) + rawLyrics := md.rawPairs(model.TagLyrics) lyricList := make(model.LyricList, 0, len(rawLyrics)) diff --git a/model/metadata/map_mediafile_test.go b/model/metadata/map_mediafile_test.go index 15565111a..ef5cfb8a3 100644 --- a/model/metadata/map_mediafile_test.go +++ b/model/metadata/map_mediafile_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "os" "sort" + "strings" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/model/metadata" @@ -141,6 +142,42 @@ var _ = Describe("ToMediaFile", func() { })) }) + It("should parse embedded TTML lyrics longer than the metadata tag max length", func() { + padding := strings.Repeat(`padding`, 1400) + content := ` + + + + + ` + padding + ` + + + + + +
+

Long embedded TTML line

+
+ +
` + + Expect(len(content)).To(BeNumerically(">", 32768)) + + mf = toMediaFile(model.RawTags{ + "LYRICS:ENG": {content}, + }) + var actual model.LyricList + err := json.Unmarshal([]byte(mf.Lyrics), &actual) + Expect(err).ToNot(HaveOccurred()) + + Expect(actual).To(HaveLen(1)) + Expect(actual[0].Kind).To(Equal("main")) + Expect(actual[0].Lang).To(Equal("en")) + Expect(actual[0].Line).To(Equal([]model.Line{ + {Start: P(int64(1000)), End: P(int64(2500)), Value: "Long embedded TTML line"}, + })) + }) + It("should parse embedded SRT lyrics with the tag language", func() { mf = toMediaFile(model.RawTags{ "LYRICS:POR": {`1 diff --git a/model/metadata/metadata.go b/model/metadata/metadata.go index 48928f989..c62f33776 100644 --- a/model/metadata/metadata.go +++ b/model/metadata/metadata.go @@ -70,6 +70,7 @@ func New(filePath string, info Info) Metadata { return Metadata{ filePath: filePath, fileInfo: info.FileInfo, + rawTags: lowerTags(info.Tags), tags: clean(filePath, info.Tags), audioProps: info.AudioProperties, hasPicture: info.HasPicture, @@ -79,6 +80,7 @@ func New(filePath string, info Info) Metadata { type Metadata struct { filePath string fileInfo FileInfo + rawTags model.Tags tags model.Tags audioProps AudioProperties hasPicture bool @@ -114,6 +116,14 @@ func (md Metadata) Pairs(key model.TagName) []Pair { values := md.tags[key] return slice.Map(values, func(v string) Pair { return Pair(v) }) } +func (md Metadata) rawPairs(key model.TagName) []Pair { + mapping, ok := model.TagMappings()[key] + if !ok { + return nil + } + values := filterDuplicatedOrEmptyValues(processPairMapping(key, mapping, md.rawTags)) + return slice.Map(values, func(v string) Pair { return Pair(v) }) +} func (md Metadata) first(key model.TagName) string { if v, ok := md.tags[key]; ok && len(v) > 0 { return v[0]