diff --git a/cmd/root.go b/cmd/root.go index 6700cf78a..a95a2bd5f 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -14,7 +14,6 @@ import ( "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/consts" "github.com/navidrome/navidrome/core" - "github.com/navidrome/navidrome/core/playback" "github.com/navidrome/navidrome/db" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/resources" @@ -164,7 +163,7 @@ func startScheduler(ctx context.Context) func() error { func startPlaybackServer(ctx context.Context) func() error { log.Info(ctx, "Starting playback server") - playbackInstance := playback.GetInstance() + playbackInstance := GetPlaybackServer() return func() error { return playbackInstance.Run(ctx) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index cb5197afb..25ca7a0c9 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -14,6 +14,7 @@ import ( "github.com/navidrome/navidrome/core/agents/listenbrainz" "github.com/navidrome/navidrome/core/artwork" "github.com/navidrome/navidrome/core/ffmpeg" + "github.com/navidrome/navidrome/core/playback" "github.com/navidrome/navidrome/core/scrobbler" "github.com/navidrome/navidrome/db" "github.com/navidrome/navidrome/persistence" @@ -23,7 +24,6 @@ import ( "github.com/navidrome/navidrome/server/nativeapi" "github.com/navidrome/navidrome/server/public" "github.com/navidrome/navidrome/server/subsonic" - "sync" ) // Injectors from wire_injectors.go: @@ -58,11 +58,13 @@ func CreateSubsonicAPIRouter() *subsonic.Router { share := core.NewShare(dataStore) archiver := core.NewArchiver(mediaStreamer, dataStore, share) players := core.NewPlayers(dataStore) - scanner := GetScanner() - broker := events.GetBroker() playlists := core.NewPlaylists(dataStore) + cacheWarmer := artwork.NewCacheWarmer(artworkArtwork, fileCache) + broker := events.GetBroker() + scannerScanner := scanner.GetInstance(dataStore, playlists, cacheWarmer, broker) playTracker := scrobbler.GetPlayTracker(dataStore, broker) - router := subsonic.New(dataStore, artworkArtwork, mediaStreamer, archiver, players, externalMetadata, scanner, broker, playlists, playTracker, share) + playbackServer := playback.GetInstance(dataStore) + router := subsonic.New(dataStore, artworkArtwork, mediaStreamer, archiver, players, externalMetadata, scannerScanner, broker, playlists, playTracker, share, playbackServer) return router } @@ -96,7 +98,7 @@ func CreateListenBrainzRouter() *listenbrainz.Router { return router } -func createScanner() scanner.Scanner { +func GetScanner() scanner.Scanner { sqlDB := db.Db() dataStore := persistence.New(sqlDB) playlists := core.NewPlaylists(dataStore) @@ -107,23 +109,17 @@ func createScanner() scanner.Scanner { artworkArtwork := artwork.NewArtwork(dataStore, fileCache, fFmpeg, externalMetadata) cacheWarmer := artwork.NewCacheWarmer(artworkArtwork, fileCache) broker := events.GetBroker() - scannerScanner := scanner.New(dataStore, playlists, cacheWarmer, broker) + scannerScanner := scanner.GetInstance(dataStore, playlists, cacheWarmer, broker) return scannerScanner } +func GetPlaybackServer() playback.PlaybackServer { + sqlDB := db.Db() + dataStore := persistence.New(sqlDB) + playbackServer := playback.GetInstance(dataStore) + return playbackServer +} + // wire_injectors.go: -var allProviders = wire.NewSet(core.Set, artwork.Set, subsonic.New, nativeapi.New, public.New, persistence.New, lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, db.Db) - -// Scanner must be a Singleton -var ( - onceScanner sync.Once - scannerInstance scanner.Scanner -) - -func GetScanner() scanner.Scanner { - onceScanner.Do(func() { - scannerInstance = createScanner() - }) - return scannerInstance -} +var allProviders = wire.NewSet(core.Set, artwork.Set, server.New, subsonic.New, nativeapi.New, public.New, persistence.New, lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, scanner.GetInstance, db.Db) diff --git a/cmd/wire_injectors.go b/cmd/wire_injectors.go index cc896421f..994056e37 100644 --- a/cmd/wire_injectors.go +++ b/cmd/wire_injectors.go @@ -3,13 +3,12 @@ package cmd import ( - "sync" - "github.com/google/wire" "github.com/navidrome/navidrome/core" "github.com/navidrome/navidrome/core/agents/lastfm" "github.com/navidrome/navidrome/core/agents/listenbrainz" "github.com/navidrome/navidrome/core/artwork" + "github.com/navidrome/navidrome/core/playback" "github.com/navidrome/navidrome/db" "github.com/navidrome/navidrome/persistence" "github.com/navidrome/navidrome/scanner" @@ -23,6 +22,7 @@ import ( var allProviders = wire.NewSet( core.Set, artwork.Set, + server.New, subsonic.New, nativeapi.New, public.New, @@ -30,12 +30,12 @@ var allProviders = wire.NewSet( lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, + scanner.GetInstance, db.Db, ) func CreateServer(musicFolder string) *server.Server { panic(wire.Build( - server.New, allProviders, )) } @@ -49,7 +49,6 @@ func CreateNativeAPIRouter() *nativeapi.Router { func CreateSubsonicAPIRouter() *subsonic.Router { panic(wire.Build( allProviders, - GetScanner, )) } @@ -71,22 +70,14 @@ func CreateListenBrainzRouter() *listenbrainz.Router { )) } -// Scanner must be a Singleton -var ( - onceScanner sync.Once - scannerInstance scanner.Scanner -) - func GetScanner() scanner.Scanner { - onceScanner.Do(func() { - scannerInstance = createScanner() - }) - return scannerInstance -} - -func createScanner() scanner.Scanner { panic(wire.Build( allProviders, - scanner.New, + )) +} + +func GetPlaybackServer() playback.PlaybackServer { + panic(wire.Build( + allProviders, )) } diff --git a/core/playback/playbackserver.go b/core/playback/playbackserver.go index 9687aadeb..510545a43 100644 --- a/core/playback/playbackserver.go +++ b/core/playback/playbackserver.go @@ -10,10 +10,8 @@ import ( "fmt" "github.com/navidrome/navidrome/conf" - "github.com/navidrome/navidrome/db" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" - "github.com/navidrome/navidrome/persistence" "github.com/navidrome/navidrome/utils/singleton" ) @@ -31,15 +29,14 @@ type playbackServer struct { } // GetInstance returns the playback-server singleton -func GetInstance() PlaybackServer { +func GetInstance(ds model.DataStore) PlaybackServer { return singleton.GetInstance(func() *playbackServer { - return &playbackServer{} + return &playbackServer{datastore: ds} }) } // Run starts the playback server which serves request until canceled using the given context func (ps *playbackServer) Run(ctx context.Context) error { - ps.datastore = persistence.New(db.Db()) devices, err := ps.initDeviceStatus(conf.Server.Jukebox.Devices, conf.Server.Jukebox.Default) ps.playbackDevices = devices diff --git a/core/wire_providers.go b/core/wire_providers.go index d7ee2b694..f4231814a 100644 --- a/core/wire_providers.go +++ b/core/wire_providers.go @@ -4,6 +4,7 @@ import ( "github.com/google/wire" "github.com/navidrome/navidrome/core/agents" "github.com/navidrome/navidrome/core/ffmpeg" + "github.com/navidrome/navidrome/core/playback" "github.com/navidrome/navidrome/core/scrobbler" ) @@ -18,4 +19,5 @@ var Set = wire.NewSet( agents.New, ffmpeg.New, scrobbler.GetPlayTracker, + playback.GetInstance, ) diff --git a/scanner/scanner.go b/scanner/scanner.go index fae5a9c20..abdc14fb6 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -13,6 +13,7 @@ import ( "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" "github.com/navidrome/navidrome/server/events" + "github.com/navidrome/navidrome/utils/singleton" ) type Scanner interface { @@ -57,18 +58,20 @@ type scanStatus struct { lastUpdate time.Time } -func New(ds model.DataStore, playlists core.Playlists, cacheWarmer artwork.CacheWarmer, broker events.Broker) Scanner { - s := &scanner{ - ds: ds, - pls: playlists, - broker: broker, - folders: map[string]FolderScanner{}, - status: map[string]*scanStatus{}, - lock: &sync.RWMutex{}, - cacheWarmer: cacheWarmer, - } - s.loadFolders() - return s +func GetInstance(ds model.DataStore, playlists core.Playlists, cacheWarmer artwork.CacheWarmer, broker events.Broker) Scanner { + return singleton.GetInstance(func() *scanner { + s := &scanner{ + ds: ds, + pls: playlists, + broker: broker, + folders: map[string]FolderScanner{}, + status: map[string]*scanStatus{}, + lock: &sync.RWMutex{}, + cacheWarmer: cacheWarmer, + } + s.loadFolders() + return s + }) } func (s *scanner) rescan(ctx context.Context, mediaFolder string, fullRescan bool) error { diff --git a/server/subsonic/album_lists_test.go b/server/subsonic/album_lists_test.go index 88f2e0aca..f187555e9 100644 --- a/server/subsonic/album_lists_test.go +++ b/server/subsonic/album_lists_test.go @@ -25,7 +25,7 @@ var _ = Describe("Album Lists", func() { BeforeEach(func() { ds = &tests.MockDataStore{} mockRepo = ds.Album(ctx).(*tests.MockAlbumRepo) - router = New(ds, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) + router = New(ds, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) w = httptest.NewRecorder() }) diff --git a/server/subsonic/api.go b/server/subsonic/api.go index f7134e815..bebe5d6e1 100644 --- a/server/subsonic/api.go +++ b/server/subsonic/api.go @@ -12,6 +12,7 @@ import ( "github.com/navidrome/navidrome/conf" "github.com/navidrome/navidrome/core" "github.com/navidrome/navidrome/core/artwork" + "github.com/navidrome/navidrome/core/playback" "github.com/navidrome/navidrome/core/scrobbler" "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" @@ -39,11 +40,13 @@ type Router struct { broker events.Broker scrobbler scrobbler.PlayTracker share core.Share + playback playback.PlaybackServer } func New(ds model.DataStore, artwork artwork.Artwork, streamer core.MediaStreamer, archiver core.Archiver, players core.Players, externalMetadata core.ExternalMetadata, scanner scanner.Scanner, broker events.Broker, - playlists core.Playlists, scrobbler scrobbler.PlayTracker, share core.Share) *Router { + playlists core.Playlists, scrobbler scrobbler.PlayTracker, share core.Share, playback playback.PlaybackServer, +) *Router { r := &Router{ ds: ds, artwork: artwork, @@ -56,6 +59,7 @@ func New(ds model.DataStore, artwork artwork.Artwork, streamer core.MediaStreame broker: broker, scrobbler: scrobbler, share: share, + playback: playback, } r.Handler = r.routes() return r diff --git a/server/subsonic/jukebox.go b/server/subsonic/jukebox.go index c7881e4e0..b49372c2b 100644 --- a/server/subsonic/jukebox.go +++ b/server/subsonic/jukebox.go @@ -43,8 +43,7 @@ func (api *Router) JukeboxControl(r *http.Request) (*responses.Subsonic, error) return nil, err } - pbServer := playback.GetInstance() - pb, err := pbServer.GetDeviceForUser(user.UserName) + pb, err := api.playback.GetDeviceForUser(user.UserName) if err != nil { return nil, err } diff --git a/server/subsonic/media_annotation_test.go b/server/subsonic/media_annotation_test.go index 8c64e0f1d..918ca5380 100644 --- a/server/subsonic/media_annotation_test.go +++ b/server/subsonic/media_annotation_test.go @@ -29,7 +29,7 @@ var _ = Describe("MediaAnnotationController", func() { ds = &tests.MockDataStore{} playTracker = &fakePlayTracker{} eventBroker = &fakeEventBroker{} - router = New(ds, nil, nil, nil, nil, nil, nil, eventBroker, nil, playTracker, nil) + router = New(ds, nil, nil, nil, nil, nil, nil, eventBroker, nil, playTracker, nil, nil) }) Describe("Scrobble", func() { diff --git a/server/subsonic/media_retrieval_test.go b/server/subsonic/media_retrieval_test.go index 12e32dad4..0be6eb89c 100644 --- a/server/subsonic/media_retrieval_test.go +++ b/server/subsonic/media_retrieval_test.go @@ -30,7 +30,7 @@ var _ = Describe("MediaRetrievalController", func() { MockedMediaFile: mockRepo, } artwork = &fakeArtwork{} - router = New(ds, artwork, nil, nil, nil, nil, nil, nil, nil, nil, nil) + router = New(ds, artwork, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil) w = httptest.NewRecorder() })