fix: Add cloning logic to filters, make providers not update original filter

This commit is contained in:
Michael Manganiello
2024-03-17 00:56:49 -03:00
parent ab2ac363b0
commit b8cd79e6de
4 changed files with 48 additions and 19 deletions
+3 -1
View File
@@ -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]) Clone() mediaprovider.MediaFilter[M, nilFilterOptions] { return n }
func (n nilFilter[M]) Options() nilFilterOptions { return nilFilterOptions{} }
func (n nilFilter[M]) SetOptions(o nilFilterOptions) {}
func (n nilFilter[M]) SetOptions(options nilFilterOptions) {}
+14 -10
View File
@@ -58,7 +58,7 @@ func (j *jellyfinMediaProvider) IterateAlbums(sortOrder string, filter mediaprov
jfSort.Field = jellyfin.SortByYear
jfSort.Mode = jellyfin.SortDesc
}
jfFilt := jfFilterFromFilter(filter)
jfFilt, modifiedFilter := jfFilterFromFilter(filter)
fetcher := func(offs, limit int) ([]*mediaprovider.Album, error) {
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 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 {
@@ -151,15 +151,20 @@ func (j *jellyfinMediaProvider) IterateArtists(sortOrder string) mediaprovider.A
}
// Creates the Jellyfin filter to implement the given mediaprovider filter,
// and zeros out the now-unneeded fields in the mediaprovider filter.
func jfFilterFromFilter(filter mediaprovider.AlbumFilter) jellyfin.Filter {
// and returns a modified mediaprovider filter, with now-unneeded fields zeroed out.
func jfFilterFromFilter(filter mediaprovider.AlbumFilter) (jellyfin.Filter, mediaprovider.AlbumFilter) {
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 {
jfFilt.Favorite = true
filterOptions.ExcludeUnfavorited = false // Jellyfin will handle this filter
filterOptions.ExcludeUnfavorited = false
}
if filterOptions.MinYear > 0 && filterOptions.MaxYear > 0 {
jfFilt.YearRange = [2]int{filterOptions.MinYear, filterOptions.MaxYear}
@@ -174,7 +179,6 @@ func jfFilterFromFilter(filter mediaprovider.AlbumFilter) jellyfin.Filter {
jfFilt.Genres = filterOptions.Genres
filterOptions.Genres = nil
filter.SetOptions(filterOptions)
return jfFilt
modifiedFilter.SetOptions(filterOptions)
return jfFilt, modifiedFilter
}
+21 -2
View File
@@ -18,6 +18,7 @@ type TrackIterator = MediaIterator[Track]
type MediaFilter[M, F any] interface {
Options() F
SetOptions(F)
Clone() MediaFilter[M, F]
IsNil() bool
Matches(*M) bool
}
@@ -33,6 +34,19 @@ type AlbumFilterOptions struct {
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 {
options AlbumFilterOptions
}
@@ -45,8 +59,13 @@ func (a albumFilter) Options() AlbumFilterOptions {
return a.options
}
func (a *albumFilter) SetOptions(o AlbumFilterOptions) {
a.options = o
func (a *albumFilter) SetOptions(options AlbumFilterOptions) {
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
@@ -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.
// 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.
filterOptions.Genres = nil
modifiedFilter := filter.Clone()
modifiedOptions := modifiedFilter.Options()
modifiedOptions.Genres = nil
modifiedFilter.SetOptions(modifiedOptions)
fetchFn := func(offset, limit int) ([]*subsonic.AlbumID3, error) {
return s.client.GetAlbumList2("byGenre",
map[string]string{"genre": genre, "offset": strconv.Itoa(offset), "limit": strconv.Itoa(limit)})
}
filter.SetOptions(filterOptions)
return helpers.NewAlbumIterator(makeFetchFn(fetchFn), filter, s.prefetchCoverCB)
return helpers.NewAlbumIterator(makeFetchFn(fetchFn), modifiedFilter, s.prefetchCoverCB)
}
if sortOrder == "" && filterOptions.ExcludeUnfavorited {
filterOptions.ExcludeUnfavorited = false // we're already filtering by this
filter.SetOptions(filterOptions)
return s.baseIterFromSimpleSortOrder("starred", filter)
modifiedFilter := filter.Clone()
modifiedOptions := modifiedFilter.Options()
modifiedOptions.ExcludeUnfavorited = false // we're already filtering by this
modifiedFilter.SetOptions(modifiedOptions)
return s.baseIterFromSimpleSortOrder("starred", modifiedFilter)
}
if sortOrder == "" {
sortOrder = AlbumSortRecentlyAdded // default