Removed list_generator completely

This commit is contained in:
Deluan 2020-10-27 10:19:58 -04:00
parent 3037ea01e2
commit 6152fadd92
11 changed files with 99 additions and 149 deletions

View File

@ -44,8 +44,6 @@ func CreateSubsonicAPIRouter() *subsonic.Router {
dataStore := persistence.New()
artworkCache := core.NewImageCache()
artwork := core.NewArtwork(dataStore, artworkCache)
nowPlayingRepository := engine.NewNowPlayingRepository()
listGenerator := engine.NewListGenerator(dataStore, nowPlayingRepository)
playlists := engine.NewPlaylists(dataStore)
transcoderTranscoder := transcoder.New()
transcodingCache := core.NewTranscodingCache()
@ -55,7 +53,7 @@ func CreateSubsonicAPIRouter() *subsonic.Router {
client := core.LastFMNewClient()
spotifyClient := core.SpotifyNewClient()
externalInfo := core.NewExternalInfo(dataStore, client, spotifyClient)
router := subsonic.New(artwork, listGenerator, playlists, mediaStreamer, archiver, players, externalInfo, dataStore)
router := subsonic.New(artwork, playlists, mediaStreamer, archiver, players, externalInfo, dataStore)
return router
}

View File

@ -1,4 +1,4 @@
package engine
package core
import (
"container/list"
@ -17,22 +17,10 @@ type NowPlayingInfo struct {
}
// This repo must have the semantics of a FIFO queue, for each playerId
type NowPlayingRepository interface {
type NowPlaying interface {
// Insert at the head of the queue
Enqueue(*NowPlayingInfo) error
// Removes and returns the element at the end of the queue
Dequeue(playerId int) (*NowPlayingInfo, error)
// Returns the element at the head of the queue (last inserted one)
Head(playerId int) (*NowPlayingInfo, error)
// Returns the element at the end of the queue (first inserted one)
Tail(playerId int) (*NowPlayingInfo, error)
// Size of the queue for the playerId
Count(playerId int) (int64, error)
// Returns all heads from all playerIds
GetAll() ([]*NowPlayingInfo, error)
}
@ -41,55 +29,17 @@ var playerMap = sync.Map{}
type nowPlayingRepository struct{}
func NewNowPlayingRepository() NowPlayingRepository {
func NewNowPlayingRepository() NowPlaying {
r := &nowPlayingRepository{}
return r
}
func (r *nowPlayingRepository) getList(id int) *list.List {
l, _ := playerMap.LoadOrStore(id, list.New())
return l.(*list.List)
}
func (r *nowPlayingRepository) Enqueue(info *NowPlayingInfo) error {
l := r.getList(info.PlayerId)
l.PushFront(info)
return nil
}
func (r *nowPlayingRepository) Dequeue(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Back)
if e == nil {
return nil, nil
}
l.Remove(e)
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) Head(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Front)
if e == nil {
return nil, nil
}
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) Tail(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Back)
if e == nil {
return nil, nil
}
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) Count(playerId int) (int64, error) {
l := r.getList(playerId)
return int64(l.Len()), nil
}
func (r *nowPlayingRepository) GetAll() ([]*NowPlayingInfo, error) {
var all []*NowPlayingInfo
playerMap.Range(func(playerId, l interface{}) bool {
@ -103,6 +53,44 @@ func (r *nowPlayingRepository) GetAll() ([]*NowPlayingInfo, error) {
return all, nil
}
func (r *nowPlayingRepository) getList(id int) *list.List {
l, _ := playerMap.LoadOrStore(id, list.New())
return l.(*list.List)
}
func (r *nowPlayingRepository) dequeue(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Back)
if e == nil {
return nil, nil
}
l.Remove(e)
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) head(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Front)
if e == nil {
return nil, nil
}
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) tail(playerId int) (*NowPlayingInfo, error) {
l := r.getList(playerId)
e := checkExpired(l, l.Back)
if e == nil {
return nil, nil
}
return e.Value.(*NowPlayingInfo), nil
}
func (r *nowPlayingRepository) count(playerId int) (int64, error) {
l := r.getList(playerId)
return int64(l.Len()), nil
}
func checkExpired(l *list.List, f func() *list.Element) *list.Element {
for {
e := f()

View File

@ -1,4 +1,4 @@
package engine
package core
import (
"sync"
@ -8,27 +8,27 @@ import (
. "github.com/onsi/gomega"
)
var _ = Describe("NowPlayingRepository", func() {
var repo NowPlayingRepository
var _ = Describe("NowPlaying", func() {
var repo *nowPlayingRepository
var now = time.Now()
var past = time.Time{}
BeforeEach(func() {
playerMap = sync.Map{}
repo = NewNowPlayingRepository()
repo = NewNowPlayingRepository().(*nowPlayingRepository)
})
It("enqueues and dequeues records", func() {
Expect(repo.Enqueue(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now})).To(BeNil())
Expect(repo.Enqueue(&NowPlayingInfo{PlayerId: 1, TrackID: "BBB", Start: now})).To(BeNil())
Expect(repo.Tail(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.Head(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "BBB", Start: now}))
Expect(repo.tail(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.head(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "BBB", Start: now}))
Expect(repo.Count(1)).To(Equal(int64(2)))
Expect(repo.count(1)).To(Equal(int64(2)))
Expect(repo.Dequeue(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.Count(1)).To(Equal(int64(1)))
Expect(repo.dequeue(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.count(1)).To(Equal(int64(1)))
})
It("handles multiple players", func() {
@ -43,11 +43,11 @@ var _ = Describe("NowPlayingRepository", func() {
{PlayerId: 2, TrackID: "DDD", Start: now},
}))
Expect(repo.Count(2)).To(Equal(int64(2)))
Expect(repo.Count(2)).To(Equal(int64(2)))
Expect(repo.count(2)).To(Equal(int64(2)))
Expect(repo.count(2)).To(Equal(int64(2)))
Expect(repo.Tail(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.Head(2)).To(Equal(&NowPlayingInfo{PlayerId: 2, TrackID: "DDD", Start: now}))
Expect(repo.tail(1)).To(Equal(&NowPlayingInfo{PlayerId: 1, TrackID: "AAA", Start: now}))
Expect(repo.head(2)).To(Equal(&NowPlayingInfo{PlayerId: 2, TrackID: "DDD", Start: now}))
})
It("handles expired items", func() {

View File

@ -16,6 +16,7 @@ var Set = wire.NewSet(
NewTranscodingCache,
NewImageCache,
NewArchiver,
NewNowPlayingRepository,
NewExternalInfo,
NewCacheWarmer,
LastFMNewClient,

View File

@ -4,24 +4,25 @@ import (
"context"
"errors"
"net/http"
"time"
"github.com/deluan/navidrome/core"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/deluan/navidrome/server/subsonic/filter"
"github.com/deluan/navidrome/server/subsonic/responses"
"github.com/deluan/navidrome/utils"
)
type AlbumListController struct {
ds model.DataStore
listGen engine.ListGenerator
ds model.DataStore
nowPlaying core.NowPlaying
}
func NewAlbumListController(ds model.DataStore, listGen engine.ListGenerator) *AlbumListController {
func NewAlbumListController(ds model.DataStore, nowPlaying core.NowPlaying) *AlbumListController {
c := &AlbumListController{
ds: ds,
listGen: listGen,
ds: ds,
nowPlaying: nowPlaying,
}
return c
}
@ -132,7 +133,8 @@ func (c *AlbumListController) GetStarred2(w http.ResponseWriter, r *http.Request
}
func (c *AlbumListController) GetNowPlaying(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
npInfos, err := c.listGen.GetNowPlaying(r.Context())
ctx := r.Context()
npInfo, err := c.nowPlaying.GetAll()
if err != nil {
log.Error(r, "Error retrieving now playing list", "error", err)
return nil, newError(responses.ErrorGeneric, "Internal Error")
@ -140,13 +142,18 @@ func (c *AlbumListController) GetNowPlaying(w http.ResponseWriter, r *http.Reque
response := newResponse()
response.NowPlaying = &responses.NowPlaying{}
response.NowPlaying.Entry = make([]responses.NowPlayingEntry, len(npInfos))
for i, entry := range npInfos {
response.NowPlaying.Entry[i].Child = toChild(r.Context(), entry)
response.NowPlaying.Entry[i].UserName = entry.UserName
response.NowPlaying.Entry[i].MinutesAgo = entry.MinutesAgo
response.NowPlaying.Entry[i].PlayerId = entry.PlayerId
response.NowPlaying.Entry[i].PlayerName = entry.PlayerName
response.NowPlaying.Entry = make([]responses.NowPlayingEntry, len(npInfo))
for i, np := range npInfo {
mf, err := c.ds.MediaFile(ctx).Get(np.TrackID)
if err != nil {
return nil, newError(responses.ErrorGeneric, "Internal Error")
}
response.NowPlaying.Entry[i].Child = childFromMediaFile(ctx, *mf)
response.NowPlaying.Entry[i].UserName = np.Username
response.NowPlaying.Entry[i].MinutesAgo = int(time.Since(np.Start).Minutes())
response.NowPlaying.Entry[i].PlayerId = np.PlayerId
response.NowPlaying.Entry[i].PlayerName = np.PlayerName
}
return response, nil
}

View File

@ -23,22 +23,21 @@ const Version = "1.13.0"
type Handler = func(http.ResponseWriter, *http.Request) (*responses.Subsonic, error)
type Router struct {
Artwork core.Artwork
ListGenerator engine.ListGenerator
Playlists engine.Playlists
Streamer core.MediaStreamer
Archiver core.Archiver
Players engine.Players
ExternalInfo core.ExternalInfo
DataStore model.DataStore
Artwork core.Artwork
Playlists engine.Playlists
Streamer core.MediaStreamer
Archiver core.Archiver
Players engine.Players
ExternalInfo core.ExternalInfo
DataStore model.DataStore
mux http.Handler
}
func New(artwork core.Artwork, listGenerator engine.ListGenerator,
func New(artwork core.Artwork,
playlists engine.Playlists, streamer core.MediaStreamer,
archiver core.Archiver, players engine.Players, externalInfo core.ExternalInfo, ds model.DataStore) *Router {
r := &Router{Artwork: artwork, ListGenerator: listGenerator, Playlists: playlists,
r := &Router{Artwork: artwork, Playlists: playlists,
Streamer: streamer, Archiver: archiver, Players: players, ExternalInfo: externalInfo, DataStore: ds}
r.mux = r.routes()
return r

View File

@ -1,41 +0,0 @@
package engine
import (
"context"
"time"
"github.com/deluan/navidrome/model"
)
type ListGenerator interface {
GetNowPlaying(ctx context.Context) (Entries, error)
}
func NewListGenerator(ds model.DataStore, npRepo NowPlayingRepository) ListGenerator {
return &listGenerator{ds, npRepo}
}
type listGenerator struct {
ds model.DataStore
npRepo NowPlayingRepository
}
func (g *listGenerator) GetNowPlaying(ctx context.Context) (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(ctx).Get(np.TrackID)
if err != nil {
return nil, err
}
entries[i] = FromMediaFile(mf)
entries[i].UserName = np.Username
entries[i].MinutesAgo = int(time.Since(np.Start).Minutes())
entries[i].PlayerId = np.PlayerId
entries[i].PlayerName = np.PlayerName
}
return entries, nil
}

View File

@ -5,8 +5,6 @@ import (
)
var Set = wire.NewSet(
NewListGenerator,
NewPlaylists,
NewNowPlayingRepository,
NewPlayers,
)

View File

@ -6,20 +6,20 @@ import (
"net/http"
"time"
"github.com/deluan/navidrome/core"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/model/request"
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/deluan/navidrome/server/subsonic/responses"
"github.com/deluan/navidrome/utils"
)
type MediaAnnotationController struct {
ds model.DataStore
npRepo engine.NowPlayingRepository
npRepo core.NowPlaying
}
func NewMediaAnnotationController(ds model.DataStore, npr engine.NowPlayingRepository) *MediaAnnotationController {
func NewMediaAnnotationController(ds model.DataStore, npr core.NowPlaying) *MediaAnnotationController {
return &MediaAnnotationController{ds: ds, npRepo: npr}
}
@ -176,7 +176,7 @@ func (c *MediaAnnotationController) scrobblerNowPlaying(ctx context.Context, pla
log.Info("Now Playing", "title", mf.Title, "artist", mf.Artist, "user", username)
info := &engine.NowPlayingInfo{TrackID: trackId, Username: username, Start: time.Now(), PlayerId: playerId, PlayerName: playerName}
info := &core.NowPlayingInfo{TrackID: trackId, Username: username, Start: time.Now(), PlayerId: playerId, PlayerName: playerName}
return mf, c.npRepo.Enqueue(info)
}

View File

@ -6,7 +6,7 @@
package subsonic
import (
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/deluan/navidrome/core"
"github.com/google/wire"
)
@ -26,15 +26,15 @@ func initBrowsingController(router *Router) *BrowsingController {
func initAlbumListController(router *Router) *AlbumListController {
dataStore := router.DataStore
listGenerator := router.ListGenerator
albumListController := NewAlbumListController(dataStore, listGenerator)
nowPlaying := core.NewNowPlayingRepository()
albumListController := NewAlbumListController(dataStore, nowPlaying)
return albumListController
}
func initMediaAnnotationController(router *Router) *MediaAnnotationController {
dataStore := router.DataStore
nowPlayingRepository := engine.NewNowPlayingRepository()
mediaAnnotationController := NewMediaAnnotationController(dataStore, nowPlayingRepository)
nowPlaying := core.NewNowPlayingRepository()
mediaAnnotationController := NewMediaAnnotationController(dataStore, nowPlaying)
return mediaAnnotationController
}
@ -87,5 +87,5 @@ var allProviders = wire.NewSet(
NewUsersController,
NewMediaRetrievalController,
NewStreamController,
NewBookmarksController, engine.NewNowPlayingRepository, wire.FieldsOf(new(*Router), "Artwork", "ListGenerator", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
NewBookmarksController, core.NewNowPlayingRepository, wire.FieldsOf(new(*Router), "Artwork", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
)

View File

@ -3,7 +3,7 @@
package subsonic
import (
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/deluan/navidrome/core"
"github.com/google/wire"
)
@ -18,8 +18,8 @@ var allProviders = wire.NewSet(
NewMediaRetrievalController,
NewStreamController,
NewBookmarksController,
engine.NewNowPlayingRepository,
wire.FieldsOf(new(*Router), "Artwork", "ListGenerator", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
core.NewNowPlayingRepository,
wire.FieldsOf(new(*Router), "Artwork", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
)
func initSystemController(router *Router) *SystemController {