add AlbumFilter to backend album iterators

This commit is contained in:
Drew Weymouth
2023-05-11 08:54:18 -07:00
parent 5634dfcfc1
commit 882f951aa1
6 changed files with 68 additions and 21 deletions
+51 -13
View File
@@ -3,8 +3,10 @@ package backend
import ( import (
"log" "log"
"strconv" "strconv"
"strings"
"github.com/dweymouth/go-subsonic/subsonic" "github.com/dweymouth/go-subsonic/subsonic"
"github.com/dweymouth/supersonic/sharedutil"
) )
type AlbumSortOrder string type AlbumSortOrder string
@@ -33,36 +35,69 @@ var (
} }
) )
func (l *LibraryManager) AlbumsIter(sort AlbumSortOrder) AlbumIterator { type AlbumFilter struct {
MinYear int
MaxYear int // 0 == unset/match any
Genres []string // len(0) == unset/match any
ExcludeFavorited bool // mut. exc. with ExcludeUnfavorited
ExcludeUnfavorited bool // mut. exc. with ExcludeFavorited
}
func (f *AlbumFilter) Matches(album *subsonic.AlbumID3) bool {
if album == nil {
return false
}
if f.ExcludeFavorited && !album.Starred.IsZero() {
return false
}
if f.ExcludeUnfavorited && album.Starred.IsZero() {
return false
}
if y := album.Year; y < f.MinYear || (f.MaxYear > 0 && y > f.MaxYear) {
return false
}
if len(f.Genres) == 0 {
return true
}
for _, g := range f.Genres {
if strings.EqualFold(g, album.Genre) {
return true
}
}
return false
}
func (l *LibraryManager) AlbumsIter(sort AlbumSortOrder, filter AlbumFilter) AlbumIterator {
switch sort { switch sort {
case AlbumSortRecentlyAdded: case AlbumSortRecentlyAdded:
return l.newBaseIter("newest", make(map[string]string)) return l.newBaseIter("newest", filter, make(map[string]string))
case AlbumSortRecentlyPlayed: case AlbumSortRecentlyPlayed:
return l.newBaseIter("recent", make(map[string]string)) return l.newBaseIter("recent", filter, make(map[string]string))
case AlbumSortFrequentlyPlayed: case AlbumSortFrequentlyPlayed:
return l.newBaseIter("frequent", make(map[string]string)) return l.newBaseIter("frequent", filter, make(map[string]string))
case AlbumSortRandom: case AlbumSortRandom:
return l.newRandomIter() return l.newRandomIter()
case AlbumSortTitleAZ: case AlbumSortTitleAZ:
return l.newBaseIter("alphabeticalByName", make(map[string]string)) return l.newBaseIter("alphabeticalByName", filter, make(map[string]string))
case AlbumSortArtistAZ: case AlbumSortArtistAZ:
return l.newBaseIter("alphabeticalByArtist", make(map[string]string)) return l.newBaseIter("alphabeticalByArtist", filter, make(map[string]string))
case AlbumSortYearAscending: case AlbumSortYearAscending:
return l.newBaseIter("byYear", map[string]string{"fromYear": "0", "toYear": "3000"}) return l.newBaseIter("byYear", filter, map[string]string{"fromYear": "0", "toYear": "3000"})
case AlbumSortYearDescending: case AlbumSortYearDescending:
return l.newBaseIter("byYear", map[string]string{"fromYear": "3000", "toYear": "0"}) return l.newBaseIter("byYear", filter, map[string]string{"fromYear": "3000", "toYear": "0"})
default: default:
log.Printf("Undefined album sort order: %s", sort) log.Printf("Undefined album sort order: %s", sort)
return nil return nil
} }
} }
func (l *LibraryManager) StarredIter() AlbumIterator { func (l *LibraryManager) StarredIter(filter AlbumFilter) AlbumIterator {
return l.newBaseIter("starred", make(map[string]string)) return l.newBaseIter("starred", filter, make(map[string]string))
} }
func (l *LibraryManager) GenreIter(genre string) AlbumIterator { func (l *LibraryManager) GenreIter(genre string, filter AlbumFilter) AlbumIterator {
return l.newBaseIter("byGenre", map[string]string{"genre": genre}) return l.newBaseIter("byGenre", filter, map[string]string{"genre": genre})
} }
func (l *LibraryManager) SearchIter(query string) AlbumIterator { func (l *LibraryManager) SearchIter(query string) AlbumIterator {
@@ -83,6 +118,7 @@ func (l *LibraryManager) GetAlbum(id string) (*subsonic.AlbumID3, error) {
type baseIter struct { type baseIter struct {
listType string listType string
filter AlbumFilter
pos int pos int
l *LibraryManager l *LibraryManager
s *subsonic.Client s *subsonic.Client
@@ -92,9 +128,10 @@ type baseIter struct {
done bool done bool
} }
func (l *LibraryManager) newBaseIter(listType string, opts map[string]string) *baseIter { func (l *LibraryManager) newBaseIter(listType string, filter AlbumFilter, opts map[string]string) *baseIter {
return &baseIter{ return &baseIter{
listType: listType, listType: listType,
filter: filter,
l: l, l: l,
s: l.s.Server, s: l.s.Server,
opts: opts, opts: opts,
@@ -123,6 +160,7 @@ func (r *baseIter) Next() *subsonic.AlbumID3 {
log.Println(err) log.Println(err)
albums = nil albums = nil
} }
albums = sharedutil.FilterSlice(albums, r.filter.Matches)
if len(albums) == 0 { if len(albums) == 0 {
r.done = true r.done = true
return nil return nil
+1 -1
View File
@@ -9,7 +9,7 @@ import (
func (l *LibraryManager) AllTracksIterator() TrackIterator { func (l *LibraryManager) AllTracksIterator() TrackIterator {
return &allTracksIterator{ return &allTracksIterator{
l: l, l: l,
albumIter: l.AlbumsIter(AlbumSortArtistAZ), albumIter: l.AlbumsIter(AlbumSortArtistAZ, AlbumFilter{}),
} }
} }
+6
View File
@@ -17,6 +17,9 @@ func SliceContains[T comparable](ts []T, t T) bool {
} }
func FilterSlice[T any](ss []T, test func(T) bool) []T { func FilterSlice[T any](ss []T, test func(T) bool) []T {
if ss == nil {
return nil
}
result := make([]T, 0) result := make([]T, 0)
for _, s := range ss { for _, s := range ss {
if test(s) { if test(s) {
@@ -27,6 +30,9 @@ func FilterSlice[T any](ss []T, test func(T) bool) []T {
} }
func MapSlice[T any, U any](ts []T, f func(T) U) []U { func MapSlice[T any, U any](ts []T, f func(T) U) []U {
if ts == nil {
return nil
}
result := make([]U, len(ts)) result := make([]U, len(ts))
for i, t := range ts { for i, t := range ts {
result[i] = f(t) result[i] = f(t)
+3 -3
View File
@@ -71,7 +71,7 @@ func NewAlbumsPage(cfg *backend.AlbumsPageConfig, contr *controller.Controller,
cfg.SortOrder = string(backend.AlbumSortRecentlyAdded) cfg.SortOrder = string(backend.AlbumSortRecentlyAdded)
} }
a.sortOrder.Selected = cfg.SortOrder a.sortOrder.Selected = cfg.SortOrder
iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected)) iter := lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected), backend.AlbumFilter{})
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), im) a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), im)
contr.ConnectAlbumGridActions(a.grid) contr.ConnectAlbumGridActions(a.grid)
a.searcher = widgets.NewSearchEntry() a.searcher = widgets.NewSearchEntry()
@@ -154,7 +154,7 @@ func (a *AlbumsPage) Reload() {
if a.searchText != "" { if a.searchText != "" {
a.doSearch(a.searchText) a.doSearch(a.searchText)
} else { } else {
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected)) iter := a.lm.AlbumsIter(backend.AlbumSortOrder(a.sortOrder.Selected), backend.AlbumFilter{})
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter)) a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
a.grid.Refresh() a.grid.Refresh()
} }
@@ -190,7 +190,7 @@ func (a *AlbumsPage) doSearch(query string) {
func (a *AlbumsPage) onSortOrderChanged(order string) { func (a *AlbumsPage) onSortOrderChanged(order string) {
a.cfg.SortOrder = a.sortOrder.Selected a.cfg.SortOrder = a.sortOrder.Selected
iter := a.lm.AlbumsIter(backend.AlbumSortOrder(order)) iter := a.lm.AlbumsIter(backend.AlbumSortOrder(order), backend.AlbumFilter{})
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter)) a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
if a.searchText == "" { if a.searchText == "" {
a.container.Objects[0] = a.grid a.container.Objects[0] = a.grid
+4 -2
View File
@@ -55,7 +55,8 @@ func NewFavoritesPage(cfg *backend.FavoritesPageConfig, contr *controller.Contro
} }
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
a.createHeader(0, "") a.createHeader(0, "")
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(lm.StarredIter()), a.im) iter := lm.StarredIter(backend.AlbumFilter{})
a.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), a.im)
a.contr.ConnectAlbumGridActions(a.grid) a.contr.ConnectAlbumGridActions(a.grid)
if cfg.InitialView == "Artists" { if cfg.InitialView == "Artists" {
a.toggleBtns.SetActivatedButton(1) a.toggleBtns.SetActivatedButton(1)
@@ -129,7 +130,8 @@ func (a *FavoritesPage) Reload() {
if a.searchText != "" { if a.searchText != "" {
a.doSearchAlbums(a.searchText) a.doSearchAlbums(a.searchText)
} else { } else {
a.grid.Reset(widgets.NewGridViewAlbumIterator(a.lm.StarredIter())) iter := a.lm.StarredIter(backend.AlbumFilter{})
a.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
} }
if a.tracklistCtr != nil || a.artistListCtr != nil { if a.tracklistCtr != nil || a.artistListCtr != nil {
go func() { go func() {
+3 -2
View File
@@ -52,7 +52,7 @@ func NewGenrePage(genre string, contr *controller.Controller, pm *backend.Playba
SizeName: theme.SizeNameHeadingText, SizeName: theme.SizeNameHeadingText,
} }
g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs) g.playRandom = widget.NewButtonWithIcon(" Play random", myTheme.ShuffleIcon, g.playRandomSongs)
iter := g.lm.GenreIter(g.genre) iter := g.lm.GenreIter(g.genre, backend.AlbumFilter{})
g.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im) g.grid = widgets.NewGridView(widgets.NewGridViewAlbumIterator(iter), g.im)
g.contr.ConnectAlbumGridActions(g.grid) g.contr.ConnectAlbumGridActions(g.grid)
g.searcher = widgets.NewSearchEntry() g.searcher = widgets.NewSearchEntry()
@@ -118,7 +118,8 @@ func (g *GenrePage) Reload() {
if g.searchText != "" { if g.searchText != "" {
g.doSearch(g.searchText) g.doSearch(g.searchText)
} else { } else {
g.grid.Reset(widgets.NewGridViewAlbumIterator(g.lm.GenreIter(g.genre))) iter := g.lm.GenreIter(g.genre, backend.AlbumFilter{})
g.grid.Reset(widgets.NewGridViewAlbumIterator(iter))
g.grid.Refresh() g.grid.Refresh()
} }
} }