navidrome/engine/list_generator.go
Deluan 67eeb218c4 Big Refactor:
- Create model.DataStore, with provision for transactions
- Change all layers dependencies on repositories to use DataStore
- Implemented persistence.SQLStore
- Removed iTunes Bridge/Importer support
2020-01-19 16:28:09 -05:00

163 lines
4.3 KiB
Go

package engine
import (
"math/rand"
"time"
"github.com/cloudsonic/sonic-server/model"
"github.com/cloudsonic/sonic-server/utils"
)
type ListGenerator interface {
GetNewest(offset int, size int) (Entries, error)
GetRecent(offset int, size int) (Entries, error)
GetFrequent(offset int, size int) (Entries, error)
GetHighest(offset int, size int) (Entries, error)
GetRandom(offset int, size int) (Entries, error)
GetByName(offset int, size int) (Entries, error)
GetByArtist(offset int, size int) (Entries, error)
GetStarred(offset int, size int) (Entries, error)
GetAllStarred() (artists Entries, albums Entries, mediaFiles Entries, err error)
GetNowPlaying() (Entries, error)
GetRandomSongs(size int) (Entries, error)
}
func NewListGenerator(ds model.DataStore, npRepo NowPlayingRepository) ListGenerator {
return &listGenerator{ds, npRepo}
}
type listGenerator struct {
ds model.DataStore
npRepo NowPlayingRepository
}
// TODO: Only return albums that have the SortBy field != empty
func (g *listGenerator) query(qo model.QueryOptions, offset int, size int) (Entries, error) {
qo.Offset = offset
qo.Size = size
albums, err := g.ds.Album().GetAll(qo)
return FromAlbums(albums), err
}
func (g *listGenerator) GetNewest(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "CreatedAt", Desc: true}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetRecent(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "PlayDate", Desc: true}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetFrequent(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "PlayCount", Desc: true}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetHighest(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "Rating", Desc: true}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetByName(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "Name"}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetByArtist(offset int, size int) (Entries, error) {
qo := model.QueryOptions{SortBy: "Artist"}
return g.query(qo, offset, size)
}
func (g *listGenerator) GetRandom(offset int, size int) (Entries, error) {
ids, err := g.ds.Album().GetAllIds()
if err != nil {
return nil, err
}
size = utils.MinInt(size, len(ids))
perm := rand.Perm(size)
r := make(Entries, size)
for i := 0; i < size; i++ {
v := perm[i]
al, err := g.ds.Album().Get((ids)[v])
if err != nil {
return nil, err
}
r[i] = FromAlbum(al)
}
return r, nil
}
func (g *listGenerator) GetRandomSongs(size int) (Entries, error) {
ids, err := g.ds.MediaFile().GetAllIds()
if err != nil {
return nil, err
}
size = utils.MinInt(size, len(ids))
perm := rand.Perm(size)
r := make(Entries, size)
for i := 0; i < size; i++ {
v := perm[i]
mf, err := g.ds.MediaFile().Get(ids[v])
if err != nil {
return nil, err
}
r[i] = FromMediaFile(mf)
}
return r, nil
}
func (g *listGenerator) GetStarred(offset int, size int) (Entries, error) {
qo := model.QueryOptions{Offset: offset, Size: size, SortBy: "starred_at", Desc: true}
albums, err := g.ds.Album().GetStarred(qo)
if err != nil {
return nil, err
}
return FromAlbums(albums), nil
}
// TODO Return is confusing
func (g *listGenerator) GetAllStarred() (Entries, Entries, Entries, error) {
artists, err := g.ds.Artist().GetStarred(model.QueryOptions{SortBy: "starred_at", Desc: true})
if err != nil {
return nil, nil, nil, err
}
albums, err := g.GetStarred(0, -1)
if err != nil {
return nil, nil, nil, err
}
mediaFiles, err := g.ds.MediaFile().GetStarred(model.QueryOptions{SortBy: "starred_at", Desc: true})
if err != nil {
return nil, nil, nil, err
}
return FromArtists(artists), albums, FromMediaFiles(mediaFiles), err
}
func (g *listGenerator) GetNowPlaying() (Entries, error) {
npInfo, err := g.npRepo.GetAll()
if err != nil {
return nil, err
}
entries := make(Entries, len(npInfo))
for i, np := range npInfo {
mf, err := g.ds.MediaFile().Get(np.TrackID)
if err != nil {
return nil, err
}
entries[i] = FromMediaFile(mf)
entries[i].UserName = np.Username
entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes())
entries[i].PlayerId = np.PlayerId
entries[i].PlayerName = np.PlayerName
}
return entries, nil
}