Include both `Album Count` and `Random` sortings for the Artists page. This change also fixes the Artist search feature in Jellyfin, which was broken because of an open issue on Jellyfin [1]. The current workaround is to do the filtering locally after receiving all results from Jellyfin API. Also, as the Jellyfin API doesn't include a sorting option for `AlbumCount`, we need to disable pagination when that option is selected, to receive all artists, and run the sorting locally. [1] Related issue: https://github.com/jellyfin/jellyfin/issues/8222
127 lines
3.7 KiB
Go
127 lines
3.7 KiB
Go
package jellyfin
|
|
|
|
import (
|
|
"slices"
|
|
|
|
"github.com/dweymouth/go-jellyfin"
|
|
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
|
"github.com/dweymouth/supersonic/backend/mediaprovider/helpers"
|
|
"github.com/dweymouth/supersonic/sharedutil"
|
|
)
|
|
|
|
const (
|
|
ArtistSortAlbumCount string = "Album Count"
|
|
ArtistSortNameAZ string = "Name (A-Z)"
|
|
ArtistSortRandom string = "Random"
|
|
)
|
|
|
|
func (j *jellyfinMediaProvider) ArtistSortOrders() []string {
|
|
return []string{
|
|
ArtistSortAlbumCount,
|
|
ArtistSortNameAZ,
|
|
ArtistSortRandom,
|
|
}
|
|
}
|
|
|
|
func (j *jellyfinMediaProvider) IterateArtists(sortOrder string, filter mediaprovider.ArtistFilter) mediaprovider.ArtistIterator {
|
|
var jfSort jellyfin.Sort
|
|
var disablePagination bool
|
|
var sortFn func([]*jellyfin.Artist) []*jellyfin.Artist
|
|
|
|
if sortOrder == "" {
|
|
sortOrder = ArtistSortNameAZ // default
|
|
}
|
|
switch sortOrder {
|
|
case ArtistSortAlbumCount:
|
|
// Pagination needs to be disabled, to retrieve all results in a single request, and correctly sort them.
|
|
disablePagination = true
|
|
sortFn = func(artists []*jellyfin.Artist) []*jellyfin.Artist {
|
|
slices.SortStableFunc(artists, func(a, b *jellyfin.Artist) int {
|
|
return b.AlbumCount - a.AlbumCount
|
|
})
|
|
return artists
|
|
}
|
|
case ArtistSortNameAZ:
|
|
jfSort.Field = jellyfin.SortByName
|
|
jfSort.Mode = jellyfin.SortAsc
|
|
case ArtistSortRandom:
|
|
jfSort.Field = jellyfin.SortByRandom
|
|
}
|
|
|
|
fetcher := makeArtistFetchFn(
|
|
func(offs, limit int) ([]*jellyfin.Artist, error) {
|
|
if disablePagination && offs > 0 {
|
|
return nil, nil
|
|
}
|
|
var paging jellyfin.Paging
|
|
if !disablePagination {
|
|
paging = jellyfin.Paging{StartIndex: offs, Limit: limit}
|
|
}
|
|
return j.client.GetAlbumArtists(jellyfin.QueryOpts{
|
|
Sort: jfSort,
|
|
Paging: paging,
|
|
})
|
|
},
|
|
sortFn,
|
|
)
|
|
|
|
return helpers.NewArtistIterator(fetcher, filter, j.prefetchCoverCB)
|
|
}
|
|
|
|
func (j *jellyfinMediaProvider) SearchArtists(searchQuery string, filter mediaprovider.ArtistFilter) mediaprovider.ArtistIterator {
|
|
// TODO: Jellyfin API is not returning search results for artists.
|
|
// Uncomment the following code once the issue is resolved.
|
|
// Related issue: https://github.com/jellyfin/jellyfin/issues/8222
|
|
// fetcher := makeArtistFetchFn(
|
|
// func(offs, limit int) ([]*jellyfin.Artist, error) {
|
|
// log.Printf("Searching for artists: %s", searchQuery)
|
|
// sr, err := j.client.Search(searchQuery, jellyfin.TypeArtist, jellyfin.Paging{StartIndex: offs, Limit: limit})
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
// log.Printf("Found %d artists", len(sr.Artists))
|
|
// for _, a := range sr.Artists {
|
|
// log.Printf("Artist: %s", a.Name)
|
|
// }
|
|
// return sr.Artists, nil
|
|
// },
|
|
// nil,
|
|
// )
|
|
// return helpers.NewArtistIterator(fetcher, filter, j.prefetchCoverCB)
|
|
|
|
modifiedFilter := filter.Clone()
|
|
modifiedOptions := modifiedFilter.Options()
|
|
modifiedOptions.SearchQuery = searchQuery
|
|
modifiedFilter.SetOptions(modifiedOptions)
|
|
|
|
fetcher := makeArtistFetchFn(
|
|
func(offs, limit int) ([]*jellyfin.Artist, error) {
|
|
return j.client.GetAlbumArtists(jellyfin.QueryOpts{
|
|
Sort: jellyfin.Sort{
|
|
Field: jellyfin.SortByName,
|
|
Mode: jellyfin.SortAsc,
|
|
},
|
|
Paging: jellyfin.Paging{StartIndex: offs, Limit: limit},
|
|
})
|
|
},
|
|
nil,
|
|
)
|
|
return helpers.NewArtistIterator(fetcher, modifiedFilter, j.prefetchCoverCB)
|
|
}
|
|
|
|
func makeArtistFetchFn(
|
|
fetchFn func(offset, limit int) ([]*jellyfin.Artist, error),
|
|
sortFn func([]*jellyfin.Artist) []*jellyfin.Artist,
|
|
) helpers.ArtistFetchFn {
|
|
return func(offset, limit int) ([]*mediaprovider.Artist, error) {
|
|
ar, err := fetchFn(offset, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if sortFn != nil {
|
|
ar = sortFn(ar)
|
|
}
|
|
return sharedutil.MapSlice(ar, toArtist), nil
|
|
}
|
|
}
|