fix: Add cloning logic to filters, make providers not update original filter
This commit is contained in:
@@ -195,6 +195,8 @@ func (n nilFilter[M]) IsNil() bool { return true }
|
|||||||
|
|
||||||
func (n nilFilter[M]) Matches(*M) bool { return true }
|
func (n nilFilter[M]) Matches(*M) bool { return true }
|
||||||
|
|
||||||
|
func (n nilFilter[M]) Clone() mediaprovider.MediaFilter[M, nilFilterOptions] { return n }
|
||||||
|
|
||||||
func (n nilFilter[M]) Options() nilFilterOptions { return nilFilterOptions{} }
|
func (n nilFilter[M]) Options() nilFilterOptions { return nilFilterOptions{} }
|
||||||
|
|
||||||
func (n nilFilter[M]) SetOptions(o nilFilterOptions) {}
|
func (n nilFilter[M]) SetOptions(options nilFilterOptions) {}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func (j *jellyfinMediaProvider) IterateAlbums(sortOrder string, filter mediaprov
|
|||||||
jfSort.Field = jellyfin.SortByYear
|
jfSort.Field = jellyfin.SortByYear
|
||||||
jfSort.Mode = jellyfin.SortDesc
|
jfSort.Mode = jellyfin.SortDesc
|
||||||
}
|
}
|
||||||
jfFilt := jfFilterFromFilter(filter)
|
jfFilt, modifiedFilter := jfFilterFromFilter(filter)
|
||||||
|
|
||||||
fetcher := func(offs, limit int) ([]*mediaprovider.Album, error) {
|
fetcher := func(offs, limit int) ([]*mediaprovider.Album, error) {
|
||||||
al, err := j.client.GetAlbums(jellyfin.QueryOpts{
|
al, err := j.client.GetAlbums(jellyfin.QueryOpts{
|
||||||
@@ -84,9 +84,9 @@ func (j *jellyfinMediaProvider) IterateAlbums(sortOrder string, filter mediaprov
|
|||||||
}
|
}
|
||||||
return sharedutil.MapSlice(al, toAlbum), nil
|
return sharedutil.MapSlice(al, toAlbum), nil
|
||||||
}
|
}
|
||||||
return helpers.NewRandomAlbumIter(determFetcher, fetcher, filter, j.prefetchCoverCB)
|
return helpers.NewRandomAlbumIter(determFetcher, fetcher, modifiedFilter, j.prefetchCoverCB)
|
||||||
}
|
}
|
||||||
return helpers.NewAlbumIterator(fetcher, filter, j.prefetchCoverCB)
|
return helpers.NewAlbumIterator(fetcher, modifiedFilter, j.prefetchCoverCB)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jellyfinMediaProvider) SearchAlbums(searchQuery string, filter mediaprovider.AlbumFilter) mediaprovider.AlbumIterator {
|
func (j *jellyfinMediaProvider) SearchAlbums(searchQuery string, filter mediaprovider.AlbumFilter) mediaprovider.AlbumIterator {
|
||||||
@@ -151,15 +151,20 @@ func (j *jellyfinMediaProvider) IterateArtists(sortOrder string) mediaprovider.A
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates the Jellyfin filter to implement the given mediaprovider filter,
|
// Creates the Jellyfin filter to implement the given mediaprovider filter,
|
||||||
// and zeros out the now-unneeded fields in the mediaprovider filter.
|
// and returns a modified mediaprovider filter, with now-unneeded fields zeroed out.
|
||||||
func jfFilterFromFilter(filter mediaprovider.AlbumFilter) jellyfin.Filter {
|
func jfFilterFromFilter(filter mediaprovider.AlbumFilter) (jellyfin.Filter, mediaprovider.AlbumFilter) {
|
||||||
var jfFilt jellyfin.Filter
|
var jfFilt jellyfin.Filter
|
||||||
|
|
||||||
filterOptions := filter.Options()
|
// Clone the original filter to not modify its options.
|
||||||
|
// Set filters must be maintained in the original filter, as they are used for the UI.
|
||||||
|
// Modified filter options are used to ignore further filtering that was already handled by the
|
||||||
|
// Jellyfin API.
|
||||||
|
modifiedFilter := filter.Clone()
|
||||||
|
filterOptions := modifiedFilter.Options()
|
||||||
|
|
||||||
if filterOptions.ExcludeUnfavorited {
|
if filterOptions.ExcludeUnfavorited {
|
||||||
jfFilt.Favorite = true
|
jfFilt.Favorite = true
|
||||||
filterOptions.ExcludeUnfavorited = false // Jellyfin will handle this filter
|
filterOptions.ExcludeUnfavorited = false
|
||||||
}
|
}
|
||||||
if filterOptions.MinYear > 0 && filterOptions.MaxYear > 0 {
|
if filterOptions.MinYear > 0 && filterOptions.MaxYear > 0 {
|
||||||
jfFilt.YearRange = [2]int{filterOptions.MinYear, filterOptions.MaxYear}
|
jfFilt.YearRange = [2]int{filterOptions.MinYear, filterOptions.MaxYear}
|
||||||
@@ -174,7 +179,6 @@ func jfFilterFromFilter(filter mediaprovider.AlbumFilter) jellyfin.Filter {
|
|||||||
jfFilt.Genres = filterOptions.Genres
|
jfFilt.Genres = filterOptions.Genres
|
||||||
filterOptions.Genres = nil
|
filterOptions.Genres = nil
|
||||||
|
|
||||||
filter.SetOptions(filterOptions)
|
modifiedFilter.SetOptions(filterOptions)
|
||||||
|
return jfFilt, modifiedFilter
|
||||||
return jfFilt
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type TrackIterator = MediaIterator[Track]
|
|||||||
type MediaFilter[M, F any] interface {
|
type MediaFilter[M, F any] interface {
|
||||||
Options() F
|
Options() F
|
||||||
SetOptions(F)
|
SetOptions(F)
|
||||||
|
Clone() MediaFilter[M, F]
|
||||||
IsNil() bool
|
IsNil() bool
|
||||||
Matches(*M) bool
|
Matches(*M) bool
|
||||||
}
|
}
|
||||||
@@ -33,6 +34,19 @@ type AlbumFilterOptions struct {
|
|||||||
ExcludeUnfavorited bool // mut. exc. with ExcludeFavorited
|
ExcludeUnfavorited bool // mut. exc. with ExcludeFavorited
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the filter options
|
||||||
|
func (o AlbumFilterOptions) Clone() AlbumFilterOptions {
|
||||||
|
genres := make([]string, len(o.Genres))
|
||||||
|
copy(genres, o.Genres)
|
||||||
|
return AlbumFilterOptions{
|
||||||
|
MinYear: o.MinYear,
|
||||||
|
MaxYear: o.MaxYear,
|
||||||
|
Genres: genres,
|
||||||
|
ExcludeFavorited: o.ExcludeFavorited,
|
||||||
|
ExcludeUnfavorited: o.ExcludeUnfavorited,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type albumFilter struct {
|
type albumFilter struct {
|
||||||
options AlbumFilterOptions
|
options AlbumFilterOptions
|
||||||
}
|
}
|
||||||
@@ -45,8 +59,13 @@ func (a albumFilter) Options() AlbumFilterOptions {
|
|||||||
return a.options
|
return a.options
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *albumFilter) SetOptions(o AlbumFilterOptions) {
|
func (a *albumFilter) SetOptions(options AlbumFilterOptions) {
|
||||||
a.options = o
|
a.options = options
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone returns a deep copy of the filter
|
||||||
|
func (a albumFilter) Clone() AlbumFilter {
|
||||||
|
return NewAlbumFilter(a.options.Clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the filter is the nil filter - i.e. matches everything
|
// Returns true if the filter is the nil filter - i.e. matches everything
|
||||||
|
|||||||
@@ -68,18 +68,22 @@ func (s *subsonicMediaProvider) IterateAlbums(sortOrder string, filter mediaprov
|
|||||||
// but servers do internally match against all the genres the album is categorized with.
|
// but servers do internally match against all the genres the album is categorized with.
|
||||||
// So we must not additionally filter by genre to avoid excluding results where
|
// So we must not additionally filter by genre to avoid excluding results where
|
||||||
// the single genre returned by Subsonic isn't the one we're iterating on.
|
// the single genre returned by Subsonic isn't the one we're iterating on.
|
||||||
filterOptions.Genres = nil
|
modifiedFilter := filter.Clone()
|
||||||
|
modifiedOptions := modifiedFilter.Options()
|
||||||
|
modifiedOptions.Genres = nil
|
||||||
|
modifiedFilter.SetOptions(modifiedOptions)
|
||||||
fetchFn := func(offset, limit int) ([]*subsonic.AlbumID3, error) {
|
fetchFn := func(offset, limit int) ([]*subsonic.AlbumID3, error) {
|
||||||
return s.client.GetAlbumList2("byGenre",
|
return s.client.GetAlbumList2("byGenre",
|
||||||
map[string]string{"genre": genre, "offset": strconv.Itoa(offset), "limit": strconv.Itoa(limit)})
|
map[string]string{"genre": genre, "offset": strconv.Itoa(offset), "limit": strconv.Itoa(limit)})
|
||||||
}
|
}
|
||||||
filter.SetOptions(filterOptions)
|
return helpers.NewAlbumIterator(makeFetchFn(fetchFn), modifiedFilter, s.prefetchCoverCB)
|
||||||
return helpers.NewAlbumIterator(makeFetchFn(fetchFn), filter, s.prefetchCoverCB)
|
|
||||||
}
|
}
|
||||||
if sortOrder == "" && filterOptions.ExcludeUnfavorited {
|
if sortOrder == "" && filterOptions.ExcludeUnfavorited {
|
||||||
filterOptions.ExcludeUnfavorited = false // we're already filtering by this
|
modifiedFilter := filter.Clone()
|
||||||
filter.SetOptions(filterOptions)
|
modifiedOptions := modifiedFilter.Options()
|
||||||
return s.baseIterFromSimpleSortOrder("starred", filter)
|
modifiedOptions.ExcludeUnfavorited = false // we're already filtering by this
|
||||||
|
modifiedFilter.SetOptions(modifiedOptions)
|
||||||
|
return s.baseIterFromSimpleSortOrder("starred", modifiedFilter)
|
||||||
}
|
}
|
||||||
if sortOrder == "" {
|
if sortOrder == "" {
|
||||||
sortOrder = AlbumSortRecentlyAdded // default
|
sortOrder = AlbumSortRecentlyAdded // default
|
||||||
|
|||||||
Reference in New Issue
Block a user