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]) 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) {}
+14 -10
View File
@@ -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
} }
+21 -2
View File
@@ -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