fix(jellyfin): default album track listing to track order

Browsing an album's tracks (Items?ParentId=<albumId>&IncludeItemTypes=Audio)
took only SongsByAlbum's filters and dropped its Sort, so tracks came back
in arbitrary order. Default opts.Sort to the album (disc+track) order when
browsing an album without an explicit SortBy — matching Subsonic's GetAlbum
and real Jellyfin. An explicit SortBy still wins.
This commit is contained in:
Deluan 2026-07-06 08:12:53 -04:00
commit 90e28148db
3 changed files with 10 additions and 10 deletions

View file

@ -199,9 +199,6 @@ make test PKG=./server/jellyfin/...
Access control for artists is enforced by scoping the `Artists`/`Items?IncludeItemTypes=MusicArtist`
*list* to the user's libraries, plus the persistence layer's own defense-in-depth; a client
that already has an artist id from elsewhere is not re-checked against library membership.
- **Album track order.** Browsing an album's tracks (`Items?ParentId=<albumId>&IncludeItemTypes=Audio`)
without an explicit `SortBy` does not guarantee track order — clients that need it should pass a
sort. Track numbers are always present on each item (`IndexNumber`).
- **Playlists never match `Filters=IsFavorite`.** `GET Items?IncludeItemTypes=Playlist` (alone
or mixed with other types, e.g. Finamp's favorites screen sending
`IncludeItemTypes=Audio,MusicAlbum,Playlist`) is supported, but `model.Playlist` has no

View file

@ -76,15 +76,12 @@ var _ = Describe("Browsing", func() {
Expect(names(q.Items)).To(ConsistOf("Abbey Road", "Help!"))
})
It("browses an album's tracks with their track numbers", func() {
It("browses an album's tracks in track order by default", func() {
q := queryResult(get("/Items?IncludeItemTypes=Audio&ParentId=" + enc(albumID("Abbey Road"))))
Expect(q.TotalRecordCount).To(Equal(2))
Expect(names(q.Items)).To(ConsistOf("Come Together", "Something"))
idx := map[string]int{}
for _, it := range q.Items {
idx[it.Name] = *it.IndexNumber
}
Expect(idx).To(Equal(map[string]int{"Come Together": 1, "Something": 2}))
Expect(names(q.Items)).To(Equal([]string{"Come Together", "Something"}))
Expect(*q.Items[0].IndexNumber).To(Equal(1))
Expect(*q.Items[1].IndexNumber).To(Equal(2))
})
})

View file

@ -185,6 +185,12 @@ func (api *Router) listSongs(ctx context.Context, opts model.QueryOptions, paren
if search != "" {
mfs, err = repo.Search(search, opts)
} else {
// When browsing an album's tracks, default to track order (disc + track number) like
// Subsonic's GetAlbum and real Jellyfin do; an explicit SortBy from the client still wins,
// since applySort would already have set opts.Sort.
if parentId != "" && opts.Sort == "" {
opts.Sort = filter.SongsByAlbum(parentId).Sort
}
mfs, err = repo.GetAll(opts)
}
if err != nil {