fix(subsonic): Sort songs by presence of lyrics for getLyrics (#4237)

* fix(subsonic): Sort songs by presence of lyrics for `getLyrics`

The current implementation of `getLyrics` fetches any songs matching the artist and title.
However, this misses a case where there may be multiple matches for the same artist/song, and one has lyrics while the other doesn't.
Resolve this by adding a custom SQL dynamic column that checks for the presence of lyrics.

* add options to selectMediaFile, update test

* more robust testing of GetAllByLyrics

* fix(subsonic): refactor GetAllByLyrics to GetAll with lyrics sorting

Signed-off-by: Deluan <deluan@navidrome.org>

* use has_lyrics, and properly support multiple sort parts

* better handle complicated internal sorts

* just use a simpler filter

* add note to setSortMappings

* remove custom sort mapping, improve test with different updatedat

* refactor tests and mock

Signed-off-by: Deluan <deluan@navidrome.org>

* default order when not specified is `asc`

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Kendall Garner
2025-06-16 16:04:41 +00:00
committed by GitHub
parent 873905bdf6
commit 8d594671c4
7 changed files with 106 additions and 11 deletions
+15 -1
View File
@@ -38,6 +38,9 @@ func mf(mf model.MediaFile) model.MediaFile {
model.Participant{Artist: model.Artist{ID: mf.ArtistID, Name: mf.Artist}},
},
}
if mf.Lyrics == "" {
mf.Lyrics = "[]"
}
return mf
}
@@ -78,11 +81,22 @@ var (
Path: p("/kraft/radio/antenna.mp3"),
RGAlbumGain: 1.0, RGAlbumPeak: 2.0, RGTrackGain: 3.0, RGTrackPeak: 4.0,
})
testSongs = model.MediaFiles{
songAntennaWithLyrics = mf(model.MediaFile{
ID: "1005",
Title: "Antenna",
ArtistID: "2",
Artist: "Kraftwerk",
AlbumID: "103",
Lyrics: `[{"lang":"xxx","line":[{"value":"This is a set of lyrics"}],"synced":false}]`,
})
songAntenna2 = mf(model.MediaFile{ID: "1006", Title: "Antenna", ArtistID: "2", Artist: "Kraftwerk", AlbumID: "103"})
testSongs = model.MediaFiles{
songDayInALife,
songComeTogether,
songRadioactivity,
songAntenna,
songAntennaWithLyrics,
songAntenna2,
}
)