update
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
This commit is contained in:
182
server/subsonic/filter/filters.go
Normal file
182
server/subsonic/filter/filters.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
. "github.com/Masterminds/squirrel"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/persistence"
|
||||
)
|
||||
|
||||
type Options = model.QueryOptions
|
||||
|
||||
var defaultFilters = Eq{"missing": false}
|
||||
|
||||
func addDefaultFilters(options Options) Options {
|
||||
if options.Filters == nil {
|
||||
options.Filters = defaultFilters
|
||||
} else {
|
||||
options.Filters = And{defaultFilters, options.Filters}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func AlbumsByNewest() Options {
|
||||
return addDefaultFilters(addDefaultFilters(Options{Sort: "recently_added", Order: "desc"}))
|
||||
}
|
||||
|
||||
func AlbumsByRecent() Options {
|
||||
return addDefaultFilters(Options{Sort: "playDate", Order: "desc", Filters: Gt{"play_date": time.Time{}}})
|
||||
}
|
||||
|
||||
func AlbumsByFrequent() Options {
|
||||
return addDefaultFilters(Options{Sort: "playCount", Order: "desc", Filters: Gt{"play_count": 0}})
|
||||
}
|
||||
|
||||
func AlbumsByRandom() Options {
|
||||
return addDefaultFilters(Options{Sort: "random"})
|
||||
}
|
||||
|
||||
func AlbumsByName() Options {
|
||||
return addDefaultFilters(Options{Sort: "name"})
|
||||
}
|
||||
|
||||
func AlbumsByArtist() Options {
|
||||
return addDefaultFilters(Options{Sort: "artist"})
|
||||
}
|
||||
|
||||
func AlbumsByArtistID(artistId string) Options {
|
||||
filters := []Sqlizer{
|
||||
persistence.Exists("json_tree(participants, '$.albumartist')", Eq{"value": artistId}),
|
||||
}
|
||||
if conf.Server.Subsonic.ArtistParticipations {
|
||||
filters = append(filters,
|
||||
persistence.Exists("json_tree(participants, '$.artist')", Eq{"value": artistId}),
|
||||
)
|
||||
}
|
||||
return addDefaultFilters(Options{
|
||||
Sort: "max_year",
|
||||
Filters: Or(filters),
|
||||
})
|
||||
}
|
||||
|
||||
func AlbumsByYear(fromYear, toYear int) Options {
|
||||
orderOption := ""
|
||||
if fromYear > toYear {
|
||||
fromYear, toYear = toYear, fromYear
|
||||
orderOption = "desc"
|
||||
}
|
||||
return addDefaultFilters(Options{
|
||||
Sort: "max_year",
|
||||
Order: orderOption,
|
||||
Filters: Or{
|
||||
And{
|
||||
GtOrEq{"min_year": fromYear},
|
||||
LtOrEq{"min_year": toYear},
|
||||
},
|
||||
And{
|
||||
GtOrEq{"max_year": fromYear},
|
||||
LtOrEq{"max_year": toYear},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func SongsByAlbum(albumId string) Options {
|
||||
return addDefaultFilters(Options{
|
||||
Filters: Eq{"album_id": albumId},
|
||||
Sort: "album",
|
||||
})
|
||||
}
|
||||
|
||||
func SongsByRandom(genre string, fromYear, toYear int) Options {
|
||||
options := Options{
|
||||
Sort: "random",
|
||||
}
|
||||
ff := And{}
|
||||
if genre != "" {
|
||||
ff = append(ff, filterByGenre(genre))
|
||||
}
|
||||
if fromYear != 0 {
|
||||
ff = append(ff, GtOrEq{"year": fromYear})
|
||||
}
|
||||
if toYear != 0 {
|
||||
ff = append(ff, LtOrEq{"year": toYear})
|
||||
}
|
||||
options.Filters = ff
|
||||
return addDefaultFilters(options)
|
||||
}
|
||||
|
||||
func SongsByArtistTitleWithLyricsFirst(artist, title string) Options {
|
||||
return addDefaultFilters(Options{
|
||||
Sort: "lyrics, updated_at",
|
||||
Order: "desc",
|
||||
Max: 1,
|
||||
Filters: And{
|
||||
Eq{"title": title},
|
||||
Or{
|
||||
persistence.Exists("json_tree(participants, '$.albumartist')", Eq{"value": artist}),
|
||||
persistence.Exists("json_tree(participants, '$.artist')", Eq{"value": artist}),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func ApplyLibraryFilter(opts Options, musicFolderIds []int) Options {
|
||||
if len(musicFolderIds) == 0 {
|
||||
return opts
|
||||
}
|
||||
|
||||
libraryFilter := Eq{"library_id": musicFolderIds}
|
||||
if opts.Filters == nil {
|
||||
opts.Filters = libraryFilter
|
||||
} else {
|
||||
opts.Filters = And{opts.Filters, libraryFilter}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// ApplyArtistLibraryFilter applies a filter to the given Options to ensure that only artists
|
||||
// that are associated with the specified music folders are included in the results.
|
||||
func ApplyArtistLibraryFilter(opts Options, musicFolderIds []int) Options {
|
||||
if len(musicFolderIds) == 0 {
|
||||
return opts
|
||||
}
|
||||
|
||||
artistLibraryFilter := Eq{"library_artist.library_id": musicFolderIds}
|
||||
if opts.Filters == nil {
|
||||
opts.Filters = artistLibraryFilter
|
||||
} else {
|
||||
opts.Filters = And{opts.Filters, artistLibraryFilter}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func ByGenre(genre string) Options {
|
||||
return addDefaultFilters(Options{
|
||||
Sort: "name",
|
||||
Filters: filterByGenre(genre),
|
||||
})
|
||||
}
|
||||
|
||||
func filterByGenre(genre string) Sqlizer {
|
||||
return persistence.Exists(`json_tree(tags, "$.genre")`, And{
|
||||
Like{"value": genre},
|
||||
NotEq{"atom": nil},
|
||||
})
|
||||
}
|
||||
|
||||
func ByRating() Options {
|
||||
return addDefaultFilters(Options{Sort: "rating", Order: "desc", Filters: Gt{"rating": 0}})
|
||||
}
|
||||
|
||||
func ByStarred() Options {
|
||||
return addDefaultFilters(Options{Sort: "starred_at", Order: "desc", Filters: Eq{"starred": true}})
|
||||
}
|
||||
|
||||
func ArtistsByStarred() Options {
|
||||
return Options{Sort: "starred_at", Order: "desc", Filters: Eq{"starred": true}}
|
||||
}
|
||||
Reference in New Issue
Block a user