Completely removed engine package, fewer abstraction layers \o/

This commit is contained in:
Deluan 2020-10-27 13:52:01 -04:00
parent d0bf37a8a9
commit 0f418a93cd
12 changed files with 137 additions and 378 deletions

View File

@ -13,7 +13,6 @@ import (
"github.com/deluan/navidrome/server"
"github.com/deluan/navidrome/server/app"
"github.com/deluan/navidrome/server/subsonic"
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/google/wire"
)
@ -44,7 +43,6 @@ func CreateSubsonicAPIRouter() *subsonic.Router {
dataStore := persistence.New()
artworkCache := core.NewImageCache()
artwork := core.NewArtwork(dataStore, artworkCache)
playlists := engine.NewPlaylists(dataStore)
transcoderTranscoder := transcoder.New()
transcodingCache := core.NewTranscodingCache()
mediaStreamer := core.NewMediaStreamer(dataStore, transcoderTranscoder, transcodingCache)
@ -53,10 +51,10 @@ func CreateSubsonicAPIRouter() *subsonic.Router {
client := core.LastFMNewClient()
spotifyClient := core.SpotifyNewClient()
externalInfo := core.NewExternalInfo(dataStore, client, spotifyClient)
router := subsonic.New(artwork, playlists, mediaStreamer, archiver, players, externalInfo, dataStore)
router := subsonic.New(artwork, mediaStreamer, archiver, players, externalInfo, dataStore)
return router
}
// wire_injectors.go:
var allProviders = wire.NewSet(engine.Set, core.Set, scanner.New, subsonic.New, app.New, persistence.New)
var allProviders = wire.NewSet(core.Set, scanner.New, subsonic.New, app.New, persistence.New)

View File

@ -9,12 +9,10 @@ import (
"github.com/deluan/navidrome/server"
"github.com/deluan/navidrome/server/app"
"github.com/deluan/navidrome/server/subsonic"
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/google/wire"
)
var allProviders = wire.NewSet(
engine.Set,
core.Set,
scanner.New,
subsonic.New,

View File

@ -19,6 +19,7 @@ var Set = wire.NewSet(
NewNowPlayingRepository,
NewExternalInfo,
NewCacheWarmer,
NewPlayers,
LastFMNewClient,
SpotifyNewClient,
transcoder.New,

3
go.sum
View File

@ -311,8 +311,7 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=

View File

@ -11,7 +11,6 @@ import (
"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/responses"
"github.com/deluan/navidrome/utils"
"github.com/go-chi/chi"
@ -24,7 +23,6 @@ type Handler = func(http.ResponseWriter, *http.Request) (*responses.Subsonic, er
type Router struct {
Artwork core.Artwork
Playlists engine.Playlists
Streamer core.MediaStreamer
Archiver core.Archiver
Players core.Players
@ -34,11 +32,16 @@ type Router struct {
mux http.Handler
}
func New(artwork core.Artwork,
playlists engine.Playlists, streamer core.MediaStreamer,
archiver core.Archiver, players core.Players, externalInfo core.ExternalInfo, ds model.DataStore) *Router {
r := &Router{Artwork: artwork, Playlists: playlists,
Streamer: streamer, Archiver: archiver, Players: players, ExternalInfo: externalInfo, DataStore: ds}
func New(artwork core.Artwork, streamer core.MediaStreamer, archiver core.Archiver, players core.Players,
externalInfo core.ExternalInfo, ds model.DataStore) *Router {
r := &Router{
Artwork: artwork,
Streamer: streamer,
Archiver: archiver,
Players: players,
ExternalInfo: externalInfo,
DataStore: ds,
}
r.mux = r.routes()
return r
}
@ -181,7 +184,7 @@ func HGone(r chi.Router, path string) {
func SendError(w http.ResponseWriter, r *http.Request, err error) {
response := newResponse()
code := responses.ErrorGeneric
if e, ok := err.(SubsonicError); ok {
if e, ok := err.(Error); ok {
code = e.code
}
response.Status = "fail"

View File

@ -1,106 +0,0 @@
package engine
import (
"fmt"
"time"
"github.com/deluan/navidrome/consts"
"github.com/deluan/navidrome/model"
)
type Entry struct {
Id string
Title string
IsDir bool
Parent string
Album string
Year int
Artist string
Genre string
CoverArt string
Starred time.Time
Track int
Duration int
Size int64
Suffix string
BitRate int
ContentType string
Path string
PlayCount int32
DiscNumber int
Created time.Time
AlbumId string
ArtistId string
Type string
UserRating int
SongCount int
UserName string
MinutesAgo int
PlayerId int
PlayerName string
AlbumCount int
BookmarkPosition int64
AbsolutePath string
}
type Entries []Entry
func FromMediaFile(mf *model.MediaFile) Entry {
e := Entry{}
e.Id = mf.ID
e.Title = mf.Title
e.IsDir = false
e.Parent = mf.AlbumID
e.Album = mf.Album
e.Year = mf.Year
e.Artist = mf.Artist
e.Genre = mf.Genre
e.Track = mf.TrackNumber
e.Duration = int(mf.Duration)
e.Size = mf.Size
e.Suffix = mf.Suffix
e.BitRate = mf.BitRate
if mf.HasCoverArt {
e.CoverArt = mf.ID
} else {
e.CoverArt = "al-" + mf.AlbumID
}
e.ContentType = mf.ContentType()
e.AbsolutePath = mf.Path
// Creates a "pseudo" Path, to avoid sending absolute paths to the client
if mf.Path != "" {
e.Path = fmt.Sprintf("%s/%s/%s.%s", realArtistName(mf), mf.Album, mf.Title, mf.Suffix)
}
e.DiscNumber = mf.DiscNumber
e.Created = mf.CreatedAt
e.AlbumId = mf.AlbumID
e.ArtistId = mf.ArtistID
e.Type = "music"
e.PlayCount = int32(mf.PlayCount)
if mf.Starred {
e.Starred = mf.StarredAt
}
e.UserRating = mf.Rating
e.BookmarkPosition = mf.BookmarkPosition
return e
}
func realArtistName(mf *model.MediaFile) string {
switch {
case mf.Compilation:
return consts.VariousArtists
case mf.AlbumArtist != "":
return mf.AlbumArtist
}
return mf.Artist
}
func FromMediaFiles(mfs model.MediaFiles) Entries {
entries := make(Entries, len(mfs))
for i := range mfs {
mf := mfs[i]
entries[i] = FromMediaFile(&mf)
}
return entries
}

View File

@ -1,151 +0,0 @@
package engine
import (
"context"
"time"
"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/model/request"
"github.com/deluan/navidrome/utils"
)
type Playlists interface {
GetAll(ctx context.Context) (model.Playlists, error)
Get(ctx context.Context, id string) (*PlaylistInfo, error)
Create(ctx context.Context, playlistId, name string, ids []string) error
Delete(ctx context.Context, playlistId string) error
Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error
}
func NewPlaylists(ds model.DataStore) Playlists {
return &playlists{ds}
}
type playlists struct {
ds model.DataStore
}
func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []string) error {
return p.ds.WithTx(func(tx model.DataStore) error {
owner := p.getUser(ctx)
var pls *model.Playlist
var err error
// If playlistID is present, override tracks
if playlistId != "" {
pls, err = tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
if owner != pls.Owner {
return model.ErrNotAuthorized
}
pls.Tracks = nil
} else {
pls = &model.Playlist{
Name: name,
Owner: owner,
}
}
for _, id := range ids {
pls.Tracks = append(pls.Tracks, model.MediaFile{ID: id})
}
return tx.Playlist(ctx).Put(pls)
})
}
func (p *playlists) getUser(ctx context.Context) string {
user, ok := request.UserFrom(ctx)
if ok {
return user.UserName
}
return ""
}
func (p *playlists) Delete(ctx context.Context, playlistId string) error {
return p.ds.WithTx(func(tx model.DataStore) error {
pls, err := tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
owner := p.getUser(ctx)
if owner != pls.Owner {
return model.ErrNotAuthorized
}
return tx.Playlist(ctx).Delete(playlistId)
})
}
func (p *playlists) Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
return p.ds.WithTx(func(tx model.DataStore) error {
pls, err := tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
owner := p.getUser(ctx)
if owner != pls.Owner {
return model.ErrNotAuthorized
}
if name != nil {
pls.Name = *name
}
newTracks := model.MediaFiles{}
for i, t := range pls.Tracks {
if utils.IntInSlice(i, idxToRemove) {
continue
}
newTracks = append(newTracks, t)
}
for _, id := range idsToAdd {
newTracks = append(newTracks, model.MediaFile{ID: id})
}
pls.Tracks = newTracks
return tx.Playlist(ctx).Put(pls)
})
}
func (p *playlists) GetAll(ctx context.Context) (model.Playlists, error) {
return p.ds.Playlist(ctx).GetAll()
}
type PlaylistInfo struct {
Id string
Name string
Entries Entries
SongCount int
Duration int
Public bool
Owner string
Comment string
Created time.Time
Changed time.Time
}
func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
pl, err := p.ds.Playlist(ctx).Get(id)
if err != nil {
return nil, err
}
// TODO Use model.Playlist when got rid of Entries
plsInfo := &PlaylistInfo{
Id: pl.ID,
Name: pl.Name,
SongCount: pl.SongCount,
Duration: int(pl.Duration),
Public: pl.Public,
Owner: pl.Owner,
Comment: pl.Comment,
Changed: pl.UpdatedAt,
Created: pl.CreatedAt,
}
plsInfo.Entries = FromMediaFiles(pl.Tracks)
return plsInfo, nil
}

View File

@ -1,11 +0,0 @@
package engine
import (
"github.com/deluan/navidrome/core"
"github.com/google/wire"
)
var Set = wire.NewSet(
NewPlaylists,
core.NewPlayers,
)

View File

@ -9,7 +9,6 @@ import (
"github.com/deluan/navidrome/consts"
"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"
)
@ -42,19 +41,19 @@ func requiredParamInt(r *http.Request, param string, msg string) (int, error) {
return utils.ParamInt(r, param, 0), nil
}
type SubsonicError struct {
type Error struct {
code int
messages []interface{}
}
func newError(code int, message ...interface{}) error {
return SubsonicError{
return Error{
code: code,
messages: message,
}
}
func (e SubsonicError) Error() string {
func (e Error) Error() string {
var msg string
if len(e.messages) == 0 {
msg = responses.ErrorMsg(e.code)
@ -64,6 +63,14 @@ func (e SubsonicError) Error() string {
return msg
}
func getUser(ctx context.Context) string {
user, ok := request.UserFrom(ctx)
if ok {
return user.UserName
}
return ""
}
func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
as := make([]responses.Artist, len(artists))
for i, artist := range artists {
@ -80,55 +87,6 @@ func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
return as
}
func toChildren(ctx context.Context, entries engine.Entries) []responses.Child {
children := make([]responses.Child, len(entries))
for i, entry := range entries {
children[i] = toChild(ctx, entry)
}
return children
}
func toChild(ctx context.Context, entry engine.Entry) responses.Child {
child := responses.Child{}
child.Id = entry.Id
child.Title = entry.Title
child.IsDir = entry.IsDir
child.Parent = entry.Parent
child.Album = entry.Album
child.Year = entry.Year
child.Artist = entry.Artist
child.Genre = entry.Genre
child.CoverArt = entry.CoverArt
child.Track = entry.Track
child.Duration = entry.Duration
child.Size = entry.Size
child.Suffix = entry.Suffix
child.BitRate = entry.BitRate
child.ContentType = entry.ContentType
if !entry.Starred.IsZero() {
child.Starred = &entry.Starred
}
child.Path = entry.Path
child.PlayCount = int64(entry.PlayCount)
child.DiscNumber = entry.DiscNumber
if !entry.Created.IsZero() {
child.Created = &entry.Created
}
child.AlbumId = entry.AlbumId
child.ArtistId = entry.ArtistId
child.Type = entry.Type
child.IsVideo = false
child.UserRating = entry.UserRating
child.SongCount = entry.SongCount
format, _ := getTranscoding(ctx)
if entry.Suffix != "" && format != "" && entry.Suffix != format {
child.TranscodedSuffix = format
child.TranscodedContentType = mime.TypeByExtension("." + format)
}
child.BookmarkPosition = entry.BookmarkPosition
return child
}
func toGenres(genres model.Genres) *responses.Genres {
response := make([]responses.Genre, len(genres))
for i, g := range genres {

View File

@ -8,36 +8,28 @@ import (
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model"
"github.com/deluan/navidrome/server/subsonic/engine"
"github.com/deluan/navidrome/server/subsonic/responses"
"github.com/deluan/navidrome/utils"
)
type PlaylistsController struct {
pls engine.Playlists
ds model.DataStore
}
func NewPlaylistsController(pls engine.Playlists) *PlaylistsController {
return &PlaylistsController{pls: pls}
func NewPlaylistsController(ds model.DataStore) *PlaylistsController {
return &PlaylistsController{ds: ds}
}
func (c *PlaylistsController) GetPlaylists(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
allPls, err := c.pls.GetAll(r.Context())
ctx := r.Context()
allPls, err := c.ds.Playlist(ctx).GetAll()
if err != nil {
log.Error(r, err)
return nil, newError(responses.ErrorGeneric, "Internal error")
}
playlists := make([]responses.Playlist, len(allPls))
for i, p := range allPls {
playlists[i].Id = p.ID
playlists[i].Name = p.Name
playlists[i].Comment = p.Comment
playlists[i].SongCount = p.SongCount
playlists[i].Duration = int(p.Duration)
playlists[i].Owner = p.Owner
playlists[i].Public = p.Public
playlists[i].Created = p.CreatedAt
playlists[i].Changed = p.UpdatedAt
playlists[i] = *c.buildPlaylist(p)
}
response := newResponse()
response.Playlists = &responses.Playlists{Playlist: playlists}
@ -45,11 +37,12 @@ func (c *PlaylistsController) GetPlaylists(w http.ResponseWriter, r *http.Reques
}
func (c *PlaylistsController) GetPlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
ctx := r.Context()
id, err := requiredParamString(r, "id", "id parameter required")
if err != nil {
return nil, err
}
pinfo, err := c.pls.Get(r.Context(), id)
pls, err := c.ds.Playlist(ctx).Get(id)
switch {
case err == model.ErrNotFound:
log.Error(r, err.Error(), "id", id)
@ -60,18 +53,48 @@ func (c *PlaylistsController) GetPlaylist(w http.ResponseWriter, r *http.Request
}
response := newResponse()
response.Playlist = c.buildPlaylistWithSongs(r.Context(), pinfo)
response.Playlist = c.buildPlaylistWithSongs(ctx, pls)
return response, nil
}
func (c *PlaylistsController) create(ctx context.Context, playlistId, name string, ids []string) error {
return c.ds.WithTx(func(tx model.DataStore) error {
owner := getUser(ctx)
var pls *model.Playlist
var err error
// If playlistID is present, override tracks
if playlistId != "" {
pls, err = tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
if owner != pls.Owner {
return model.ErrNotAuthorized
}
pls.Tracks = nil
} else {
pls = &model.Playlist{
Name: name,
Owner: owner,
}
}
for _, id := range ids {
pls.Tracks = append(pls.Tracks, model.MediaFile{ID: id})
}
return tx.Playlist(ctx).Put(pls)
})
}
func (c *PlaylistsController) CreatePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
songIds := utils.ParamStrings(r, "songId")
playlistId := utils.ParamString(r, "playlistId")
name := utils.ParamString(r, "name")
if playlistId == "" && name == "" {
return nil, errors.New("Required parameter name is missing")
return nil, errors.New("required parameter name is missing")
}
err := c.pls.Create(r.Context(), playlistId, name, songIds)
err := c.create(r.Context(), playlistId, name, songIds)
if err != nil {
log.Error(r, err)
return nil, newError(responses.ErrorGeneric, "Internal Error")
@ -79,12 +102,27 @@ func (c *PlaylistsController) CreatePlaylist(w http.ResponseWriter, r *http.Requ
return newResponse(), nil
}
func (c *PlaylistsController) delete(ctx context.Context, playlistId string) error {
return c.ds.WithTx(func(tx model.DataStore) error {
pls, err := tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
owner := getUser(ctx)
if owner != pls.Owner {
return model.ErrNotAuthorized
}
return tx.Playlist(ctx).Delete(playlistId)
})
}
func (c *PlaylistsController) DeletePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
id, err := requiredParamString(r, "id", "Required parameter id is missing")
if err != nil {
return nil, err
}
err = c.pls.Delete(r.Context(), id)
err = c.delete(r.Context(), id)
if err == model.ErrNotAuthorized {
return nil, newError(responses.ErrorAuthorizationFail)
}
@ -95,6 +133,38 @@ func (c *PlaylistsController) DeletePlaylist(w http.ResponseWriter, r *http.Requ
return newResponse(), nil
}
func (p *PlaylistsController) update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
return p.ds.WithTx(func(tx model.DataStore) error {
pls, err := tx.Playlist(ctx).Get(playlistId)
if err != nil {
return err
}
owner := getUser(ctx)
if owner != pls.Owner {
return model.ErrNotAuthorized
}
if name != nil {
pls.Name = *name
}
newTracks := model.MediaFiles{}
for i, t := range pls.Tracks {
if utils.IntInSlice(i, idxToRemove) {
continue
}
newTracks = append(newTracks, t)
}
for _, id := range idsToAdd {
newTracks = append(newTracks, model.MediaFile{ID: id})
}
pls.Tracks = newTracks
return tx.Playlist(ctx).Put(pls)
})
}
func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
playlistId, err := requiredParamString(r, "playlistId", "Required parameter playlistId is missing")
if err != nil {
@ -103,20 +173,20 @@ func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Requ
songsToAdd := utils.ParamStrings(r, "songIdToAdd")
songIndexesToRemove := utils.ParamInts(r, "songIndexToRemove")
var pname *string
var plsName *string
if len(r.URL.Query()["name"]) > 0 {
s := r.URL.Query()["name"][0]
pname = &s
plsName = &s
}
log.Debug(r, "Updating playlist", "id", playlistId)
if pname != nil {
log.Trace(r, fmt.Sprintf("-- New Name: '%s'", *pname))
if plsName != nil {
log.Trace(r, fmt.Sprintf("-- New Name: '%s'", *plsName))
}
log.Trace(r, fmt.Sprintf("-- Adding: '%v'", songsToAdd))
log.Trace(r, fmt.Sprintf("-- Removing: '%v'", songIndexesToRemove))
err = c.pls.Update(r.Context(), playlistId, pname, songsToAdd, songIndexesToRemove)
err = c.update(r.Context(), playlistId, plsName, songsToAdd, songIndexesToRemove)
if err == model.ErrNotAuthorized {
return nil, newError(responses.ErrorAuthorizationFail)
}
@ -127,24 +197,24 @@ func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Requ
return newResponse(), nil
}
func (c *PlaylistsController) buildPlaylistWithSongs(ctx context.Context, d *engine.PlaylistInfo) *responses.PlaylistWithSongs {
func (c *PlaylistsController) buildPlaylistWithSongs(ctx context.Context, p *model.Playlist) *responses.PlaylistWithSongs {
pls := &responses.PlaylistWithSongs{
Playlist: *c.buildPlaylist(d),
Playlist: *c.buildPlaylist(*p),
}
pls.Entry = toChildren(ctx, d.Entries)
pls.Entry = childrenFromMediaFiles(ctx, p.Tracks)
return pls
}
func (c *PlaylistsController) buildPlaylist(d *engine.PlaylistInfo) *responses.Playlist {
func (c *PlaylistsController) buildPlaylist(p model.Playlist) *responses.Playlist {
pls := &responses.Playlist{}
pls.Id = d.Id
pls.Name = d.Name
pls.Comment = d.Comment
pls.SongCount = d.SongCount
pls.Owner = d.Owner
pls.Duration = d.Duration
pls.Public = d.Public
pls.Created = d.Created
pls.Changed = d.Changed
pls.Id = p.ID
pls.Name = p.Name
pls.Comment = p.Comment
pls.SongCount = p.SongCount
pls.Owner = p.Owner
pls.Duration = int(p.Duration)
pls.Public = p.Public
pls.Created = p.CreatedAt
pls.Changed = p.UpdatedAt
return pls
}

View File

@ -39,8 +39,8 @@ func initMediaAnnotationController(router *Router) *MediaAnnotationController {
}
func initPlaylistsController(router *Router) *PlaylistsController {
playlists := router.Playlists
playlistsController := NewPlaylistsController(playlists)
dataStore := router.DataStore
playlistsController := NewPlaylistsController(dataStore)
return playlistsController
}
@ -87,5 +87,5 @@ var allProviders = wire.NewSet(
NewUsersController,
NewMediaRetrievalController,
NewStreamController,
NewBookmarksController, core.NewNowPlayingRepository, wire.FieldsOf(new(*Router), "Artwork", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
NewBookmarksController, core.NewNowPlayingRepository, wire.FieldsOf(new(*Router), "Artwork", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
)

View File

@ -19,7 +19,7 @@ var allProviders = wire.NewSet(
NewStreamController,
NewBookmarksController,
core.NewNowPlayingRepository,
wire.FieldsOf(new(*Router), "Artwork", "Playlists", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
wire.FieldsOf(new(*Router), "Artwork", "Streamer", "Archiver", "DataStore", "ExternalInfo"),
)
func initSystemController(router *Router) *SystemController {