fix(subsonic): serve the main-kind track from legacy getLyrics

getLyrics emitted structuredLyrics[0] verbatim, trusting parser ordering to
put the main track first. With translation/pronunciation tracks now possible,
select the main-kind entry explicitly (falling back to the first for untyped
lyrics), matching the kind-filtering the v2 getLyricsBySongId endpoint already
does. Adds a test with a translation track ahead of the main track.
This commit is contained in:
Deluan 2026-06-18 21:05:48 -04:00
parent 943cbc5f08
commit 5cd2a672d6
3 changed files with 38 additions and 2 deletions

View File

@ -628,6 +628,21 @@ func buildLyricCues(cues []model.Cue, lineEnd *int64) []responses.LyricCue {
return out
}
// mainKindLyric returns the main-kind lyric to surface through the plain-text
// legacy getLyrics endpoint, which has no notion of translation/pronunciation
// tracks. It falls back to the first entry so untyped lyrics still resolve.
func mainKindLyric(lyricsList model.LyricList) (model.Lyrics, bool) {
if len(lyricsList) == 0 {
return model.Lyrics{}, false
}
for _, l := range lyricsList {
if model.LyricKindOrMain(l.Kind) == model.LyricKindMain {
return l, true
}
}
return lyricsList[0], true
}
func buildLyricsList(mf *model.MediaFile, lyricsList model.LyricList, enhanced bool) *responses.LyricsList {
var filtered model.LyricList
if enhanced {

View File

@ -119,7 +119,8 @@ func (api *Router) GetLyrics(r *http.Request) (*responses.Subsonic, error) {
return nil, err
}
if len(structuredLyrics) == 0 {
mainLyric, ok := mainKindLyric(structuredLyrics)
if !ok {
return response, nil
}
@ -127,7 +128,7 @@ func (api *Router) GetLyrics(r *http.Request) (*responses.Subsonic, error) {
lyricsResponse.Title = title
var lyricsText strings.Builder
for _, line := range structuredLyrics[0].Line {
for _, line := range mainLyric.Line {
lyricsText.WriteString(line.Value + "\n")
}
lyricsResponse.Value = lyricsText.String()

View File

@ -149,6 +149,26 @@ var _ = Describe("MediaRetrievalController", func() {
Expect(response.Lyrics.Title).To(Equal("Never Gonna Give You Up"))
Expect(response.Lyrics.Value).To(Equal("We're no strangers to love\nYou know the rules and so do I\n"))
})
It("should surface the main-kind track when translation tracks are present", func() {
r := newGetRequest("artist=Rick+Astley", "title=Never+Gonna+Give+You+Up")
start := int64(0)
lyricsJSON, err := json.Marshal(model.LyricList{
{Kind: model.LyricKindTranslation, Lang: "por", Line: []model.Line{{Start: &start, Value: "Nunca vou te decepcionar"}}},
{Kind: model.LyricKindMain, Lang: "eng", Line: []model.Line{{Start: &start, Value: "Never gonna let you down"}}},
})
Expect(err).ToNot(HaveOccurred())
mockRepo.SetData(model.MediaFiles{
{
ID: "1",
Artist: "Rick Astley",
Title: "Never Gonna Give You Up",
Lyrics: string(lyricsJSON),
},
})
response, err := router.GetLyrics(r)
Expect(err).ToNot(HaveOccurred())
Expect(response.Lyrics.Value).To(Equal("Never gonna let you down\n"))
})
It("should return empty subsonic response if the record corresponding to the given artist & title is not found", func() {
r := newGetRequest("artist=Dheeraj", "title=Rinkiya+Ke+Papa")
mockRepo.SetData(model.MediaFiles{})