mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-03 20:47:35 +03:00
Removed list_generator completely
This commit is contained in:
parent
3037ea01e2
commit
6152fadd92
11 changed files with 99 additions and 149 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -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() {
|
|
@ -16,6 +16,7 @@ var Set = wire.NewSet(
|
|||
NewTranscodingCache,
|
||||
NewImageCache,
|
||||
NewArchiver,
|
||||
NewNowPlayingRepository,
|
||||
NewExternalInfo,
|
||||
NewCacheWarmer,
|
||||
LastFMNewClient,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -5,8 +5,6 @@ import (
|
|||
)
|
||||
|
||||
var Set = wire.NewSet(
|
||||
NewListGenerator,
|
||||
NewPlaylists,
|
||||
NewNowPlayingRepository,
|
||||
NewPlayers,
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
)
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue