mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-13 12:57:10 +02:00
* feat(jellyfin): compute the address advertised by auto-discovery * fix(jellyfin): use TLSEnabled and path.Join for the auto-discovery address * feat(jellyfin): answer LAN auto-discovery broadcasts * test(jellyfin): e2e check that auto-discovery matches the public server identity * feat(jellyfin): add opt-in AutoDiscovery option and start the listener * fix(jellyfin): close the auto-discovery socket on read errors and quiet reply failures * refactor(jellyfin): build the auto-discovery address with publicurl and log bind failures in place discoveryAddress now hands only the discovery-specific part (the requester-facing host) to publicurl.AbsoluteURL, so the BaseURL, scheme and BasePath rules live in one place. ServeDiscovery logs its own bind failure and returns nothing, so the caller cannot route the error into the server errgroup. Tests use a DescribeTable and no longer wait on a fixed timeout to prove a packet was ignored. * refactor(jellyfin): run auto-discovery as its own service in the main errgroup Discovery is now a small type that needs only a DataStore, started by startJellyfinDiscovery like the other background services, so the errgroup waits for it on shutdown and startServer is back to a one-line mount. The server id resolution moved to resolveServerID with a package-level lock: the Router and Discovery are separate objects, and a per-Router lock would let them persist two different ids on first boot. * refactor(jellyfin): build Discovery through wire and drop the serverName forwarder startJellyfinDiscovery now follows its siblings: negative guard with a DISABLED debug log, and the service comes from a CreateJellyfinDiscovery wire injector instead of an inline constructor. The Router.serverName method only forwarded to the package function, so its four call sites call the function directly. * fix(jellyfin): skip auto-discovery for unix socket servers without a BaseURL host With Address set to a unix socket nothing listens on Port, so the route-facing IP plus Port pointed clients at a dead URL. Discovery now logs a warning and does not start in that mode unless BaseURL names the proxy host, which AbsoluteURL already advertises as-is. * docs(jellyfin): note which address auto-discovery advertises on restricted binds Also stop using a hostname Address in the fallback spec: a hostname like localhost binds a single interface, so it is not an example of the route-facing fallback being right. An empty Address is.
265 lines
11 KiB
Go
265 lines
11 KiB
Go
// Code generated by Wire. DO NOT EDIT.
|
|
|
|
//go:generate go run -mod=mod github.com/google/wire/cmd/wire gen -tags "netgo sqlite_fts5"
|
|
//go:build !wireinject
|
|
// +build !wireinject
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"github.com/google/wire"
|
|
"github.com/navidrome/navidrome/adapters/lastfm"
|
|
"github.com/navidrome/navidrome/adapters/listenbrainz"
|
|
"github.com/navidrome/navidrome/core"
|
|
"github.com/navidrome/navidrome/core/agents"
|
|
"github.com/navidrome/navidrome/core/artwork"
|
|
"github.com/navidrome/navidrome/core/external"
|
|
"github.com/navidrome/navidrome/core/ffmpeg"
|
|
"github.com/navidrome/navidrome/core/lyrics"
|
|
"github.com/navidrome/navidrome/core/matcher"
|
|
"github.com/navidrome/navidrome/core/metrics"
|
|
"github.com/navidrome/navidrome/core/playback"
|
|
"github.com/navidrome/navidrome/core/playlists"
|
|
"github.com/navidrome/navidrome/core/scrobbler"
|
|
"github.com/navidrome/navidrome/core/sonic"
|
|
"github.com/navidrome/navidrome/core/stream"
|
|
"github.com/navidrome/navidrome/db"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/persistence"
|
|
"github.com/navidrome/navidrome/plugins"
|
|
"github.com/navidrome/navidrome/scanner"
|
|
"github.com/navidrome/navidrome/server"
|
|
"github.com/navidrome/navidrome/server/events"
|
|
"github.com/navidrome/navidrome/server/jellyfin"
|
|
"github.com/navidrome/navidrome/server/nativeapi"
|
|
"github.com/navidrome/navidrome/server/public"
|
|
"github.com/navidrome/navidrome/server/subsonic"
|
|
)
|
|
|
|
import (
|
|
_ "github.com/navidrome/navidrome/adapters/deezer"
|
|
_ "github.com/navidrome/navidrome/adapters/gotaglib"
|
|
_ "github.com/navidrome/navidrome/adapters/lastfm"
|
|
_ "github.com/navidrome/navidrome/adapters/listenbrainz"
|
|
)
|
|
|
|
// Injectors from wire_injectors.go:
|
|
|
|
func CreateDataStore() model.DataStore {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
return dataStore
|
|
}
|
|
|
|
func CreateServer() *server.Server {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
broker := events.GetBroker()
|
|
insights := metrics.GetInstance(dataStore)
|
|
serverServer := server.New(dataStore, broker, insights)
|
|
return serverServer
|
|
}
|
|
|
|
func CreateNativeAPIRouter(ctx context.Context) *nativeapi.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
share := core.NewShare(dataStore)
|
|
uploader := artwork.NewUploader(dataStore)
|
|
playlistsPlaylists := playlists.NewPlaylists(dataStore, uploader)
|
|
insights := metrics.GetInstance(dataStore)
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
modelScanner := scanner.GetInstance(ctx, dataStore, broker, playlistsPlaylists, metricsMetrics)
|
|
watcher := scanner.GetWatcher(dataStore, modelScanner)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
library := core.NewLibrary(dataStore, modelScanner, watcher, broker, manager)
|
|
user := core.NewUser(dataStore, manager)
|
|
maintenance := core.NewMaintenance(dataStore)
|
|
agentsAgents := agents.GetAgents(dataStore, manager)
|
|
matcherMatcher := matcher.New(dataStore)
|
|
provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher, broker)
|
|
router := nativeapi.New(dataStore, share, playlistsPlaylists, insights, library, user, maintenance, manager, uploader, provider)
|
|
return router
|
|
}
|
|
|
|
func CreateSubsonicAPIRouter(ctx context.Context) *subsonic.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
fileCache := artwork.GetImageCache()
|
|
imageStore := artwork.GetImageStore()
|
|
fFmpeg := ffmpeg.New()
|
|
artworkArtwork := artwork.NewArtwork(dataStore, fileCache, imageStore, fFmpeg)
|
|
transcodingCache := stream.GetTranscodingCache()
|
|
mediaStreamer := stream.NewMediaStreamer(dataStore, fFmpeg, transcodingCache)
|
|
share := core.NewShare(dataStore)
|
|
archiver := core.NewArchiver(mediaStreamer, dataStore, share)
|
|
players := core.NewPlayers(dataStore)
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
agentsAgents := agents.GetAgents(dataStore, manager)
|
|
matcherMatcher := matcher.New(dataStore)
|
|
provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher, broker)
|
|
uploader := artwork.NewUploader(dataStore)
|
|
playlistsPlaylists := playlists.NewPlaylists(dataStore, uploader)
|
|
modelScanner := scanner.GetInstance(ctx, dataStore, broker, playlistsPlaylists, metricsMetrics)
|
|
playTracker := scrobbler.GetPlayTracker(dataStore, broker, manager)
|
|
playbackServer := playback.GetInstance(dataStore)
|
|
lyricsLyrics := lyrics.NewLyrics(dataStore, manager)
|
|
transcodeDecider := stream.NewTranscodeDecider(dataStore, fFmpeg)
|
|
sonicSonic := sonic.New(dataStore, manager, matcherMatcher)
|
|
router := subsonic.New(dataStore, artworkArtwork, mediaStreamer, archiver, players, provider, modelScanner, broker, playlistsPlaylists, playTracker, share, playbackServer, metricsMetrics, lyricsLyrics, transcodeDecider, sonicSonic)
|
|
return router
|
|
}
|
|
|
|
func CreateJellyfinAPIRouter(ctx context.Context) *jellyfin.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
fileCache := artwork.GetImageCache()
|
|
imageStore := artwork.GetImageStore()
|
|
fFmpeg := ffmpeg.New()
|
|
artworkArtwork := artwork.NewArtwork(dataStore, fileCache, imageStore, fFmpeg)
|
|
transcodingCache := stream.GetTranscodingCache()
|
|
mediaStreamer := stream.NewMediaStreamer(dataStore, fFmpeg, transcodingCache)
|
|
transcodeDecider := stream.NewTranscodeDecider(dataStore, fFmpeg)
|
|
players := core.NewPlayers(dataStore)
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
playTracker := scrobbler.GetPlayTracker(dataStore, broker, manager)
|
|
uploader := artwork.NewUploader(dataStore)
|
|
playlistsPlaylists := playlists.NewPlaylists(dataStore, uploader)
|
|
agentsAgents := agents.GetAgents(dataStore, manager)
|
|
matcherMatcher := matcher.New(dataStore)
|
|
provider := external.NewProvider(dataStore, agentsAgents, matcherMatcher, broker)
|
|
sonicSonic := sonic.New(dataStore, manager, matcherMatcher)
|
|
lyricsLyrics := lyrics.NewLyrics(dataStore, manager)
|
|
router := jellyfin.New(dataStore, artworkArtwork, mediaStreamer, transcodeDecider, players, playTracker, playlistsPlaylists, provider, sonicSonic, lyricsLyrics, broker)
|
|
return router
|
|
}
|
|
|
|
func CreatePublicRouter() *public.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
fileCache := artwork.GetImageCache()
|
|
imageStore := artwork.GetImageStore()
|
|
fFmpeg := ffmpeg.New()
|
|
artworkArtwork := artwork.NewArtwork(dataStore, fileCache, imageStore, fFmpeg)
|
|
transcodingCache := stream.GetTranscodingCache()
|
|
mediaStreamer := stream.NewMediaStreamer(dataStore, fFmpeg, transcodingCache)
|
|
share := core.NewShare(dataStore)
|
|
archiver := core.NewArchiver(mediaStreamer, dataStore, share)
|
|
router := public.New(dataStore, artworkArtwork, mediaStreamer, share, archiver)
|
|
return router
|
|
}
|
|
|
|
func CreateLastFMRouter() *lastfm.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
router := lastfm.NewRouter(dataStore)
|
|
return router
|
|
}
|
|
|
|
func CreateListenBrainzRouter() *listenbrainz.Router {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
router := listenbrainz.NewRouter(dataStore)
|
|
return router
|
|
}
|
|
|
|
func CreateJellyfinDiscovery() *jellyfin.Discovery {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
discovery := jellyfin.NewDiscovery(dataStore)
|
|
return discovery
|
|
}
|
|
|
|
func CreateInsights() metrics.Insights {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
insights := metrics.GetInstance(dataStore)
|
|
return insights
|
|
}
|
|
|
|
func CreatePrometheus() metrics.Metrics {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
return metricsMetrics
|
|
}
|
|
|
|
func CreateScanner(ctx context.Context) model.Scanner {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
broker := events.GetBroker()
|
|
uploader := artwork.NewUploader(dataStore)
|
|
playlistsPlaylists := playlists.NewPlaylists(dataStore, uploader)
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
modelScanner := scanner.GetInstance(ctx, dataStore, broker, playlistsPlaylists, metricsMetrics)
|
|
return modelScanner
|
|
}
|
|
|
|
func CreateScanWatcher(ctx context.Context) scanner.Watcher {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
broker := events.GetBroker()
|
|
uploader := artwork.NewUploader(dataStore)
|
|
playlistsPlaylists := playlists.NewPlaylists(dataStore, uploader)
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
modelScanner := scanner.GetInstance(ctx, dataStore, broker, playlistsPlaylists, metricsMetrics)
|
|
watcher := scanner.GetWatcher(dataStore, modelScanner)
|
|
return watcher
|
|
}
|
|
|
|
func GetPlaybackServer() playback.PlaybackServer {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
playbackServer := playback.GetInstance(dataStore)
|
|
return playbackServer
|
|
}
|
|
|
|
func CreateArtworkWorker() *artwork.Worker {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
imageStore := artwork.GetImageStore()
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
agentsAgents := agents.GetAgents(dataStore, manager)
|
|
fFmpeg := ffmpeg.New()
|
|
fileCache := artwork.GetImageCache()
|
|
worker := artwork.NewWorker(dataStore, imageStore, agentsAgents, fFmpeg, broker, fileCache)
|
|
return worker
|
|
}
|
|
|
|
func CreateArtworkResolver(trace *artwork.ChainTrace, live bool) *artwork.TracingResolver {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
agentsAgents := agents.GetAgents(dataStore, manager)
|
|
fFmpeg := ffmpeg.New()
|
|
tracingResolver := artwork.NewTracingResolver(dataStore, agentsAgents, fFmpeg, trace, live)
|
|
return tracingResolver
|
|
}
|
|
|
|
func getPluginManager() *plugins.Manager {
|
|
sqlDB := db.Db()
|
|
dataStore := persistence.New(sqlDB)
|
|
broker := events.GetBroker()
|
|
metricsMetrics := metrics.GetPrometheusInstance(dataStore)
|
|
manager := plugins.GetManager(dataStore, broker, metricsMetrics)
|
|
return manager
|
|
}
|
|
|
|
// wire_injectors.go:
|
|
|
|
var allProviders = wire.NewSet(core.Set, artwork.Set, server.New, subsonic.New, jellyfin.New, jellyfin.NewDiscovery, nativeapi.New, public.New, persistence.New, lastfm.NewRouter, listenbrainz.NewRouter, events.GetBroker, scanner.GetInstance, scanner.GetWatcher, metrics.GetPrometheusInstance, db.Db, plugins.GetManager, sonic.New, wire.Bind(new(agents.PluginLoader), new(*plugins.Manager)), wire.Bind(new(scrobbler.PluginLoader), new(*plugins.Manager)), wire.Bind(new(lyrics.PluginLoader), new(*plugins.Manager)), wire.Bind(new(sonic.PluginLoader), new(*plugins.Manager)), wire.Bind(new(sonic.Engine), new(*sonic.Sonic)), wire.Bind(new(nativeapi.PluginManager), new(*plugins.Manager)), wire.Bind(new(core.PluginUnloader), new(*plugins.Manager)), wire.Bind(new(plugins.PluginMetricsRecorder), new(metrics.Metrics)), wire.Bind(new(core.Watcher), new(scanner.Watcher)), wire.Bind(new(playlists.ImageUploadService), new(artwork.Uploader)))
|
|
|
|
func GetPluginManager(ctx context.Context) *plugins.Manager {
|
|
manager := getPluginManager()
|
|
manager.SetSubsonicRouter(CreateSubsonicAPIRouter(ctx))
|
|
return manager
|
|
}
|