Simplify Subsonic API handler implementation
This commit is contained in:
parent
cd41d9a419
commit
19af11efbe
|
@ -6,7 +6,6 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/navidrome/navidrome/core/scrobbler"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/server/subsonic/filter"
|
||||
|
@ -14,20 +13,7 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type AlbumListController struct {
|
||||
ds model.DataStore
|
||||
scrobbler scrobbler.PlayTracker
|
||||
}
|
||||
|
||||
func NewAlbumListController(ds model.DataStore, scrobbler scrobbler.PlayTracker) *AlbumListController {
|
||||
c := &AlbumListController{
|
||||
ds: ds,
|
||||
scrobbler: scrobbler,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *AlbumListController) getAlbumList(r *http.Request) (model.Albums, int64, error) {
|
||||
func (api *Router) getAlbumList(r *http.Request) (model.Albums, int64, error) {
|
||||
typ, err := requiredParamString(r, "type")
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
|
@ -74,14 +60,14 @@ func (c *AlbumListController) getAlbumList(r *http.Request) (model.Albums, int64
|
|||
|
||||
opts.Offset = utils.ParamInt(r, "offset", 0)
|
||||
opts.Max = utils.MinInt(utils.ParamInt(r, "size", 10), 500)
|
||||
albums, err := c.ds.Album(r.Context()).GetAllWithoutGenres(opts)
|
||||
albums, err := api.ds.Album(r.Context()).GetAllWithoutGenres(opts)
|
||||
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving albums", "error", err)
|
||||
return nil, 0, newError(responses.ErrorGeneric, "internal error")
|
||||
}
|
||||
|
||||
count, err := c.ds.Album(r.Context()).CountAll(opts)
|
||||
count, err := api.ds.Album(r.Context()).CountAll(opts)
|
||||
if err != nil {
|
||||
log.Error(r, "Error counting albums", "error", err)
|
||||
return nil, 0, newError(responses.ErrorGeneric, "internal error")
|
||||
|
@ -90,8 +76,8 @@ func (c *AlbumListController) getAlbumList(r *http.Request) (model.Albums, int64
|
|||
return albums, count, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetAlbumList(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
albums, count, err := c.getAlbumList(r)
|
||||
func (api *Router) GetAlbumList(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
albums, count, err := api.getAlbumList(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -103,8 +89,8 @@ func (c *AlbumListController) GetAlbumList(w http.ResponseWriter, r *http.Reques
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetAlbumList2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
albums, pageCount, err := c.getAlbumList(r)
|
||||
func (api *Router) GetAlbumList2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
albums, pageCount, err := api.getAlbumList(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -116,20 +102,20 @@ func (c *AlbumListController) GetAlbumList2(w http.ResponseWriter, r *http.Reque
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetStarred(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetStarred(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
options := filter.Starred()
|
||||
artists, err := c.ds.Artist(ctx).GetAll(options)
|
||||
artists, err := api.ds.Artist(ctx).GetAll(options)
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving starred artists", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(options)
|
||||
albums, err := api.ds.Album(ctx).GetAllWithoutGenres(options)
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving starred albums", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
mediaFiles, err := c.ds.MediaFile(ctx).GetAll(options)
|
||||
mediaFiles, err := api.ds.MediaFile(ctx).GetAll(options)
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving starred mediaFiles", "error", err)
|
||||
return nil, err
|
||||
|
@ -143,8 +129,8 @@ func (c *AlbumListController) GetStarred(w http.ResponseWriter, r *http.Request)
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetStarred2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
resp, err := c.GetStarred(w, r)
|
||||
func (api *Router) GetStarred2(r *http.Request) (*responses.Subsonic, error) {
|
||||
resp, err := api.GetStarred(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -154,9 +140,9 @@ func (c *AlbumListController) GetStarred2(w http.ResponseWriter, r *http.Request
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetNowPlaying(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetNowPlaying(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
npInfo, err := c.scrobbler.GetNowPlaying(ctx)
|
||||
npInfo, err := api.scrobbler.GetNowPlaying(ctx)
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving now playing list", "error", err)
|
||||
return nil, err
|
||||
|
@ -166,7 +152,7 @@ func (c *AlbumListController) GetNowPlaying(w http.ResponseWriter, r *http.Reque
|
|||
response.NowPlaying = &responses.NowPlaying{}
|
||||
response.NowPlaying.Entry = make([]responses.NowPlayingEntry, len(npInfo))
|
||||
for i, np := range npInfo {
|
||||
mf, err := c.ds.MediaFile(ctx).Get(np.TrackID)
|
||||
mf, err := api.ds.MediaFile(ctx).Get(np.TrackID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -180,13 +166,13 @@ func (c *AlbumListController) GetNowPlaying(w http.ResponseWriter, r *http.Reque
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetRandomSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetRandomSongs(r *http.Request) (*responses.Subsonic, error) {
|
||||
size := utils.MinInt(utils.ParamInt(r, "size", 10), 500)
|
||||
genre := utils.ParamString(r, "genre")
|
||||
fromYear := utils.ParamInt(r, "fromYear", 0)
|
||||
toYear := utils.ParamInt(r, "toYear", 0)
|
||||
|
||||
songs, err := c.getSongs(r.Context(), 0, size, filter.SongsByRandom(genre, fromYear, toYear))
|
||||
songs, err := api.getSongs(r.Context(), 0, size, filter.SongsByRandom(genre, fromYear, toYear))
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving random songs", "error", err)
|
||||
return nil, err
|
||||
|
@ -198,12 +184,12 @@ func (c *AlbumListController) GetRandomSongs(w http.ResponseWriter, r *http.Requ
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) GetSongsByGenre(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetSongsByGenre(r *http.Request) (*responses.Subsonic, error) {
|
||||
count := utils.MinInt(utils.ParamInt(r, "count", 10), 500)
|
||||
offset := utils.MinInt(utils.ParamInt(r, "offset", 0), 500)
|
||||
genre := utils.ParamString(r, "genre")
|
||||
|
||||
songs, err := c.getSongs(r.Context(), offset, count, filter.SongsByGenre(genre))
|
||||
songs, err := api.getSongs(r.Context(), offset, count, filter.SongsByGenre(genre))
|
||||
if err != nil {
|
||||
log.Error(r, "Error retrieving random songs", "error", err)
|
||||
return nil, err
|
||||
|
@ -215,8 +201,8 @@ func (c *AlbumListController) GetSongsByGenre(w http.ResponseWriter, r *http.Req
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *AlbumListController) getSongs(ctx context.Context, offset, size int, opts filter.Options) (model.MediaFiles, error) {
|
||||
func (api *Router) getSongs(ctx context.Context, offset, size int, opts filter.Options) (model.MediaFiles, error) {
|
||||
opts.Offset = offset
|
||||
opts.Max = size
|
||||
return c.ds.MediaFile(ctx).GetAll(opts)
|
||||
return api.ds.MediaFile(ctx).GetAll(opts)
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@ import (
|
|||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("AlbumListController", func() {
|
||||
var controller *AlbumListController
|
||||
var _ = Describe("Album Lists", func() {
|
||||
var router *Router
|
||||
var ds model.DataStore
|
||||
var mockRepo *tests.MockAlbumRepo
|
||||
var w *httptest.ResponseRecorder
|
||||
|
@ -24,7 +24,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
BeforeEach(func() {
|
||||
ds = &tests.MockDataStore{}
|
||||
mockRepo = ds.Album(ctx).(*tests.MockAlbumRepo)
|
||||
controller = NewAlbumListController(ds, nil)
|
||||
router = New(ds, nil, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
w = httptest.NewRecorder()
|
||||
})
|
||||
|
||||
|
@ -34,7 +34,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
mockRepo.SetData(model.Albums{
|
||||
{ID: "1"}, {ID: "2"},
|
||||
})
|
||||
resp, err := controller.GetAlbumList(w, r)
|
||||
resp, err := router.GetAlbumList(w, r)
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
Expect(resp.AlbumList.Album[0].Id).To(Equal("1"))
|
||||
|
@ -46,7 +46,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
|
||||
It("should fail if missing type parameter", func() {
|
||||
r := newGetRequest()
|
||||
_, err := controller.GetAlbumList(w, r)
|
||||
_, err := router.GetAlbumList(w, r)
|
||||
var subErr subError
|
||||
isSubError := errors.As(err, &subErr)
|
||||
|
||||
|
@ -59,7 +59,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
mockRepo.SetError(true)
|
||||
r := newGetRequest("type=newest")
|
||||
|
||||
_, err := controller.GetAlbumList(w, r)
|
||||
_, err := router.GetAlbumList(w, r)
|
||||
|
||||
Expect(err).ToNot(BeNil())
|
||||
var subErr subError
|
||||
|
@ -74,7 +74,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
mockRepo.SetData(model.Albums{
|
||||
{ID: "1"}, {ID: "2"},
|
||||
})
|
||||
resp, err := controller.GetAlbumList2(w, r)
|
||||
resp, err := router.GetAlbumList2(w, r)
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
Expect(resp.AlbumList2.Album[0].Id).To(Equal("1"))
|
||||
|
@ -86,7 +86,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
|
||||
It("should fail if missing type parameter", func() {
|
||||
r := newGetRequest()
|
||||
_, err := controller.GetAlbumList2(w, r)
|
||||
_, err := router.GetAlbumList2(w, r)
|
||||
|
||||
var subErr subError
|
||||
errors.As(err, &subErr)
|
||||
|
@ -99,7 +99,7 @@ var _ = Describe("AlbumListController", func() {
|
|||
mockRepo.SetError(true)
|
||||
r := newGetRequest("type=newest")
|
||||
|
||||
_, err := controller.GetAlbumList2(w, r)
|
||||
_, err := router.GetAlbumList2(w, r)
|
||||
|
||||
var subErr subError
|
||||
errors.As(err, &subErr)
|
||||
|
|
|
@ -23,36 +23,37 @@ import (
|
|||
|
||||
const Version = "1.16.1"
|
||||
|
||||
type handler = func(http.ResponseWriter, *http.Request) (*responses.Subsonic, error)
|
||||
type handler = func(*http.Request) (*responses.Subsonic, error)
|
||||
type handlerRaw = func(http.ResponseWriter, *http.Request) (*responses.Subsonic, error)
|
||||
|
||||
type Router struct {
|
||||
http.Handler
|
||||
DataStore model.DataStore
|
||||
Artwork core.Artwork
|
||||
Streamer core.MediaStreamer
|
||||
Archiver core.Archiver
|
||||
Players core.Players
|
||||
ExternalMetadata core.ExternalMetadata
|
||||
Playlists core.Playlists
|
||||
Scanner scanner.Scanner
|
||||
Broker events.Broker
|
||||
Scrobbler scrobbler.PlayTracker
|
||||
ds model.DataStore
|
||||
artwork core.Artwork
|
||||
streamer core.MediaStreamer
|
||||
archiver core.Archiver
|
||||
players core.Players
|
||||
externalMetadata core.ExternalMetadata
|
||||
playlists core.Playlists
|
||||
scanner scanner.Scanner
|
||||
broker events.Broker
|
||||
scrobbler scrobbler.PlayTracker
|
||||
}
|
||||
|
||||
func New(ds model.DataStore, artwork core.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) *Router {
|
||||
r := &Router{
|
||||
DataStore: ds,
|
||||
Artwork: artwork,
|
||||
Streamer: streamer,
|
||||
Archiver: archiver,
|
||||
Players: players,
|
||||
ExternalMetadata: externalMetadata,
|
||||
Playlists: playlists,
|
||||
Scanner: scanner,
|
||||
Broker: broker,
|
||||
Scrobbler: scrobbler,
|
||||
ds: ds,
|
||||
artwork: artwork,
|
||||
streamer: streamer,
|
||||
archiver: archiver,
|
||||
players: players,
|
||||
externalMetadata: externalMetadata,
|
||||
playlists: playlists,
|
||||
scanner: scanner,
|
||||
broker: broker,
|
||||
scrobbler: scrobbler,
|
||||
}
|
||||
r.Handler = r.routes()
|
||||
return r
|
||||
|
@ -63,100 +64,89 @@ func (api *Router) routes() http.Handler {
|
|||
|
||||
r.Use(postFormToQueryParams)
|
||||
r.Use(checkRequiredParameters)
|
||||
r.Use(authenticate(api.DataStore))
|
||||
r.Use(authenticate(api.ds))
|
||||
// TODO Validate version
|
||||
|
||||
// Subsonic endpoints, grouped by controller
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initSystemController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "ping", c.Ping)
|
||||
h(withPlayer, "getLicense", c.GetLicense)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "ping", api.Ping)
|
||||
h(r, "getLicense", api.GetLicense)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initBrowsingController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "getMusicFolders", c.GetMusicFolders)
|
||||
h(withPlayer, "getIndexes", c.GetIndexes)
|
||||
h(withPlayer, "getArtists", c.GetArtists)
|
||||
h(withPlayer, "getGenres", c.GetGenres)
|
||||
h(withPlayer, "getMusicDirectory", c.GetMusicDirectory)
|
||||
h(withPlayer, "getArtist", c.GetArtist)
|
||||
h(withPlayer, "getAlbum", c.GetAlbum)
|
||||
h(withPlayer, "getSong", c.GetSong)
|
||||
h(withPlayer, "getArtistInfo", c.GetArtistInfo)
|
||||
h(withPlayer, "getArtistInfo2", c.GetArtistInfo2)
|
||||
h(withPlayer, "getTopSongs", c.GetTopSongs)
|
||||
h(withPlayer, "getSimilarSongs", c.GetSimilarSongs)
|
||||
h(withPlayer, "getSimilarSongs2", c.GetSimilarSongs2)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "getMusicFolders", api.GetMusicFolders)
|
||||
h(r, "getIndexes", api.GetIndexes)
|
||||
h(r, "getArtists", api.GetArtists)
|
||||
h(r, "getGenres", api.GetGenres)
|
||||
h(r, "getMusicDirectory", api.GetMusicDirectory)
|
||||
h(r, "getArtist", api.GetArtist)
|
||||
h(r, "getAlbum", api.GetAlbum)
|
||||
h(r, "getSong", api.GetSong)
|
||||
h(r, "getArtistInfo", api.GetArtistInfo)
|
||||
h(r, "getArtistInfo2", api.GetArtistInfo2)
|
||||
h(r, "getTopSongs", api.GetTopSongs)
|
||||
h(r, "getSimilarSongs", api.GetSimilarSongs)
|
||||
h(r, "getSimilarSongs2", api.GetSimilarSongs2)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initAlbumListController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "getAlbumList", c.GetAlbumList)
|
||||
h(withPlayer, "getAlbumList2", c.GetAlbumList2)
|
||||
h(withPlayer, "getStarred", c.GetStarred)
|
||||
h(withPlayer, "getStarred2", c.GetStarred2)
|
||||
h(withPlayer, "getNowPlaying", c.GetNowPlaying)
|
||||
h(withPlayer, "getRandomSongs", c.GetRandomSongs)
|
||||
h(withPlayer, "getSongsByGenre", c.GetSongsByGenre)
|
||||
r.Use(getPlayer(api.players))
|
||||
hr(r, "getAlbumList", api.GetAlbumList)
|
||||
hr(r, "getAlbumList2", api.GetAlbumList2)
|
||||
h(r, "getStarred", api.GetStarred)
|
||||
h(r, "getStarred2", api.GetStarred2)
|
||||
h(r, "getNowPlaying", api.GetNowPlaying)
|
||||
h(r, "getRandomSongs", api.GetRandomSongs)
|
||||
h(r, "getSongsByGenre", api.GetSongsByGenre)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initMediaAnnotationController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "setRating", c.SetRating)
|
||||
h(withPlayer, "star", c.Star)
|
||||
h(withPlayer, "unstar", c.Unstar)
|
||||
h(withPlayer, "scrobble", c.Scrobble)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "setRating", api.SetRating)
|
||||
h(r, "star", api.Star)
|
||||
h(r, "unstar", api.Unstar)
|
||||
h(r, "scrobble", api.Scrobble)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initPlaylistsController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "getPlaylists", c.GetPlaylists)
|
||||
h(withPlayer, "getPlaylist", c.GetPlaylist)
|
||||
h(withPlayer, "createPlaylist", c.CreatePlaylist)
|
||||
h(withPlayer, "deletePlaylist", c.DeletePlaylist)
|
||||
h(withPlayer, "updatePlaylist", c.UpdatePlaylist)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "getPlaylists", api.GetPlaylists)
|
||||
h(r, "getPlaylist", api.GetPlaylist)
|
||||
h(r, "createPlaylist", api.CreatePlaylist)
|
||||
h(r, "deletePlaylist", api.DeletePlaylist)
|
||||
h(r, "updatePlaylist", api.UpdatePlaylist)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initBookmarksController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "getBookmarks", c.GetBookmarks)
|
||||
h(withPlayer, "createBookmark", c.CreateBookmark)
|
||||
h(withPlayer, "deleteBookmark", c.DeleteBookmark)
|
||||
h(withPlayer, "getPlayQueue", c.GetPlayQueue)
|
||||
h(withPlayer, "savePlayQueue", c.SavePlayQueue)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "getBookmarks", api.GetBookmarks)
|
||||
h(r, "createBookmark", api.CreateBookmark)
|
||||
h(r, "deleteBookmark", api.DeleteBookmark)
|
||||
h(r, "getPlayQueue", api.GetPlayQueue)
|
||||
h(r, "savePlayQueue", api.SavePlayQueue)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initSearchingController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "search2", c.Search2)
|
||||
h(withPlayer, "search3", c.Search3)
|
||||
r.Use(getPlayer(api.players))
|
||||
h(r, "search2", api.Search2)
|
||||
h(r, "search3", api.Search3)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initUsersController(api)
|
||||
h(r, "getUser", c.GetUser)
|
||||
h(r, "getUsers", c.GetUsers)
|
||||
h(r, "getUser", api.GetUser)
|
||||
h(r, "getUsers", api.GetUsers)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initLibraryScanningController(api)
|
||||
h(r, "getScanStatus", c.GetScanStatus)
|
||||
h(r, "startScan", c.StartScan)
|
||||
h(r, "getScanStatus", api.GetScanStatus)
|
||||
h(r, "startScan", api.StartScan)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initMediaRetrievalController(api)
|
||||
// configure request throttling
|
||||
maxRequests := utils.MaxInt(2, runtime.NumCPU())
|
||||
withThrottle := r.With(middleware.ThrottleBacklog(maxRequests, consts.RequestThrottleBacklogLimit, consts.RequestThrottleBacklogTimeout))
|
||||
h(withThrottle, "getAvatar", c.GetAvatar)
|
||||
h(withThrottle, "getCoverArt", c.GetCoverArt)
|
||||
h(withThrottle, "getLyrics", c.GetLyrics)
|
||||
r.Use(middleware.ThrottleBacklog(maxRequests, consts.RequestThrottleBacklogLimit, consts.RequestThrottleBacklogTimeout))
|
||||
hr(r, "getAvatar", api.GetAvatar)
|
||||
hr(r, "getCoverArt", api.GetCoverArt)
|
||||
h(r, "getLyrics", api.GetLyrics)
|
||||
})
|
||||
r.Group(func(r chi.Router) {
|
||||
c := initStreamController(api)
|
||||
withPlayer := r.With(getPlayer(api.Players))
|
||||
h(withPlayer, "stream", c.Stream)
|
||||
h(withPlayer, "download", c.Download)
|
||||
r.Use(getPlayer(api.players))
|
||||
hr(r, "stream", api.Stream)
|
||||
hr(r, "download", api.Download)
|
||||
})
|
||||
|
||||
// Not Implemented (yet?)
|
||||
|
@ -176,9 +166,9 @@ func (api *Router) routes() http.Handler {
|
|||
return r
|
||||
}
|
||||
|
||||
// Add the Subsonic handler, with and without `.view` extension
|
||||
// Ex: if path = `ping` it will create the routes `/ping` and `/ping.view`
|
||||
func h(r chi.Router, path string, f handler) {
|
||||
// Add the Subsonic handler that requires a http.ResponseWriter, with and without `.view` extension.
|
||||
// Ex: if path = `stream` it will create the routes `/stream` and `/stream.view`
|
||||
func hr(r chi.Router, path string, f handlerRaw) {
|
||||
handle := func(w http.ResponseWriter, r *http.Request) {
|
||||
res, err := f(w, r)
|
||||
if err != nil {
|
||||
|
@ -208,6 +198,14 @@ func h(r chi.Router, path string, f handler) {
|
|||
r.HandleFunc("/"+path+".view", handle)
|
||||
}
|
||||
|
||||
// Add the Subsonic handler, with and without `.view` extension
|
||||
// Ex: if path = `ping` it will create the routes `/ping` and `/ping.view`
|
||||
func h(r chi.Router, path string, f handler) {
|
||||
hr(r, path, func(_ http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
return f(r)
|
||||
})
|
||||
}
|
||||
|
||||
// Add a handler that returns 501 - Not implemented. Used to signal that an endpoint is not implemented yet
|
||||
func h501(r *chi.Mux, paths ...string) {
|
||||
for _, path := range paths {
|
||||
|
|
|
@ -10,18 +10,10 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type BookmarksController struct {
|
||||
ds model.DataStore
|
||||
}
|
||||
|
||||
func NewBookmarksController(ds model.DataStore) *BookmarksController {
|
||||
return &BookmarksController{ds: ds}
|
||||
}
|
||||
|
||||
func (c *BookmarksController) GetBookmarks(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetBookmarks(r *http.Request) (*responses.Subsonic, error) {
|
||||
user, _ := request.UserFrom(r.Context())
|
||||
|
||||
repo := c.ds.MediaFile(r.Context())
|
||||
repo := api.ds.MediaFile(r.Context())
|
||||
bmks, err := repo.GetBookmarks()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -43,7 +35,7 @@ func (c *BookmarksController) GetBookmarks(w http.ResponseWriter, r *http.Reques
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BookmarksController) CreateBookmark(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) CreateBookmark(r *http.Request) (*responses.Subsonic, error) {
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -52,7 +44,7 @@ func (c *BookmarksController) CreateBookmark(w http.ResponseWriter, r *http.Requ
|
|||
comment := utils.ParamString(r, "comment")
|
||||
position := utils.ParamInt64(r, "position", 0)
|
||||
|
||||
repo := c.ds.MediaFile(r.Context())
|
||||
repo := api.ds.MediaFile(r.Context())
|
||||
err = repo.AddBookmark(id, comment, position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -60,13 +52,13 @@ func (c *BookmarksController) CreateBookmark(w http.ResponseWriter, r *http.Requ
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *BookmarksController) DeleteBookmark(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) DeleteBookmark(r *http.Request) (*responses.Subsonic, error) {
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
repo := c.ds.MediaFile(r.Context())
|
||||
repo := api.ds.MediaFile(r.Context())
|
||||
err = repo.DeleteBookmark(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -74,10 +66,10 @@ func (c *BookmarksController) DeleteBookmark(w http.ResponseWriter, r *http.Requ
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *BookmarksController) GetPlayQueue(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetPlayQueue(r *http.Request) (*responses.Subsonic, error) {
|
||||
user, _ := request.UserFrom(r.Context())
|
||||
|
||||
repo := c.ds.PlayQueue(r.Context())
|
||||
repo := api.ds.PlayQueue(r.Context())
|
||||
pq, err := repo.Retrieve(user.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -95,7 +87,7 @@ func (c *BookmarksController) GetPlayQueue(w http.ResponseWriter, r *http.Reques
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BookmarksController) SavePlayQueue(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) SavePlayQueue(r *http.Request) (*responses.Subsonic, error) {
|
||||
ids, err := requiredParamStrings(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -122,7 +114,7 @@ func (c *BookmarksController) SavePlayQueue(w http.ResponseWriter, r *http.Reque
|
|||
UpdatedAt: time.Time{},
|
||||
}
|
||||
|
||||
repo := c.ds.PlayQueue(r.Context())
|
||||
repo := api.ds.PlayQueue(r.Context())
|
||||
err = repo.Store(pq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -16,17 +16,8 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type BrowsingController struct {
|
||||
ds model.DataStore
|
||||
em core.ExternalMetadata
|
||||
}
|
||||
|
||||
func NewBrowsingController(ds model.DataStore, em core.ExternalMetadata) *BrowsingController {
|
||||
return &BrowsingController{ds: ds, em: em}
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetMusicFolders(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
mediaFolderList, _ := c.ds.MediaFolder(r.Context()).GetAll()
|
||||
func (api *Router) GetMusicFolders(r *http.Request) (*responses.Subsonic, error) {
|
||||
mediaFolderList, _ := api.ds.MediaFolder(r.Context()).GetAll()
|
||||
folders := make([]responses.MusicFolder, len(mediaFolderList))
|
||||
for i, f := range mediaFolderList {
|
||||
folders[i].Id = f.ID
|
||||
|
@ -37,14 +28,14 @@ func (c *BrowsingController) GetMusicFolders(w http.ResponseWriter, r *http.Requ
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) getArtistIndex(ctx context.Context, mediaFolderId int, ifModifiedSince time.Time) (*responses.Indexes, error) {
|
||||
folder, err := c.ds.MediaFolder(ctx).Get(int32(mediaFolderId))
|
||||
func (api *Router) getArtistIndex(ctx context.Context, mediaFolderId int, ifModifiedSince time.Time) (*responses.Indexes, error) {
|
||||
folder, err := api.ds.MediaFolder(ctx).Get(int32(mediaFolderId))
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving MediaFolder", "id", mediaFolderId, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := c.ds.Property(ctx).DefaultGet(model.PropLastScan+"-"+folder.Path, "-1")
|
||||
l, err := api.ds.Property(ctx).DefaultGet(model.PropLastScan+"-"+folder.Path, "-1")
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving LastScan property", err)
|
||||
return nil, err
|
||||
|
@ -54,7 +45,7 @@ func (c *BrowsingController) getArtistIndex(ctx context.Context, mediaFolderId i
|
|||
ms, _ := strconv.ParseInt(l, 10, 64)
|
||||
lastModified := utils.ToTime(ms)
|
||||
if lastModified.After(ifModifiedSince) {
|
||||
indexes, err = c.ds.Artist(ctx).GetIndex()
|
||||
indexes, err = api.ds.Artist(ctx).GetIndex()
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving Indexes", err)
|
||||
return nil, err
|
||||
|
@ -74,11 +65,11 @@ func (c *BrowsingController) getArtistIndex(ctx context.Context, mediaFolderId i
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetIndexes(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetIndexes(r *http.Request) (*responses.Subsonic, error) {
|
||||
musicFolderId := utils.ParamInt(r, "musicFolderId", 0)
|
||||
ifModifiedSince := utils.ParamTime(r, "ifModifiedSince", time.Time{})
|
||||
|
||||
res, err := c.getArtistIndex(r.Context(), musicFolderId, ifModifiedSince)
|
||||
res, err := api.getArtistIndex(r.Context(), musicFolderId, ifModifiedSince)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -88,9 +79,9 @@ func (c *BrowsingController) GetIndexes(w http.ResponseWriter, r *http.Request)
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetArtists(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetArtists(r *http.Request) (*responses.Subsonic, error) {
|
||||
musicFolderId := utils.ParamInt(r, "musicFolderId", 0)
|
||||
res, err := c.getArtistIndex(r.Context(), musicFolderId, time.Time{})
|
||||
res, err := api.getArtistIndex(r.Context(), musicFolderId, time.Time{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -100,11 +91,11 @@ func (c *BrowsingController) GetArtists(w http.ResponseWriter, r *http.Request)
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetMusicDirectory(r *http.Request) (*responses.Subsonic, error) {
|
||||
id := utils.ParamString(r, "id")
|
||||
ctx := r.Context()
|
||||
|
||||
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
||||
entity, err := core.GetEntityByID(ctx, api.ds, id)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(r, "Requested ID not found ", "id", id)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Directory not found")
|
||||
|
@ -118,9 +109,9 @@ func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Re
|
|||
|
||||
switch v := entity.(type) {
|
||||
case *model.Artist:
|
||||
dir, err = c.buildArtistDirectory(ctx, v)
|
||||
dir, err = api.buildArtistDirectory(ctx, v)
|
||||
case *model.Album:
|
||||
dir, err = c.buildAlbumDirectory(ctx, v)
|
||||
dir, err = api.buildAlbumDirectory(ctx, v)
|
||||
default:
|
||||
log.Error(r, "Requested ID of invalid type", "id", id, "entity", v)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Directory not found")
|
||||
|
@ -136,11 +127,11 @@ func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Re
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetArtist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetArtist(r *http.Request) (*responses.Subsonic, error) {
|
||||
id := utils.ParamString(r, "id")
|
||||
ctx := r.Context()
|
||||
|
||||
artist, err := c.ds.Artist(ctx).Get(id)
|
||||
artist, err := api.ds.Artist(ctx).Get(id)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(ctx, "Requested ArtistID not found ", "id", id)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Artist not found")
|
||||
|
@ -150,22 +141,22 @@ func (c *BrowsingController) GetArtist(w http.ResponseWriter, r *http.Request) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(id))
|
||||
albums, err := api.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(id))
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving albums by artist", "id", id, "name", artist.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.ArtistWithAlbumsID3 = c.buildArtist(ctx, artist, albums)
|
||||
response.ArtistWithAlbumsID3 = api.buildArtist(ctx, artist, albums)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetAlbum(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetAlbum(r *http.Request) (*responses.Subsonic, error) {
|
||||
id := utils.ParamString(r, "id")
|
||||
ctx := r.Context()
|
||||
|
||||
album, err := c.ds.Album(ctx).Get(id)
|
||||
album, err := api.ds.Album(ctx).Get(id)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(ctx, "Requested AlbumID not found ", "id", id)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Album not found")
|
||||
|
@ -175,22 +166,22 @@ func (c *BrowsingController) GetAlbum(w http.ResponseWriter, r *http.Request) (*
|
|||
return nil, err
|
||||
}
|
||||
|
||||
mfs, err := c.ds.MediaFile(ctx).GetAll(filter.SongsByAlbum(id))
|
||||
mfs, err := api.ds.MediaFile(ctx).GetAll(filter.SongsByAlbum(id))
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving tracks from album", "id", id, "name", album.Name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.AlbumWithSongsID3 = c.buildAlbum(ctx, album, mfs)
|
||||
response.AlbumWithSongsID3 = api.buildAlbum(ctx, album, mfs)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetSong(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetSong(r *http.Request) (*responses.Subsonic, error) {
|
||||
id := utils.ParamString(r, "id")
|
||||
ctx := r.Context()
|
||||
|
||||
mf, err := c.ds.MediaFile(ctx).Get(id)
|
||||
mf, err := api.ds.MediaFile(ctx).Get(id)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(r, "Requested MediaFileID not found ", "id", id)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Song not found")
|
||||
|
@ -206,9 +197,9 @@ func (c *BrowsingController) GetSong(w http.ResponseWriter, r *http.Request) (*r
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetGenres(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetGenres(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
genres, err := c.ds.Genre(ctx).GetAll(model.QueryOptions{Sort: "song_count, album_count, name desc", Order: "desc"})
|
||||
genres, err := api.ds.Genre(ctx).GetAll(model.QueryOptions{Sort: "song_count, album_count, name desc", Order: "desc"})
|
||||
if err != nil {
|
||||
log.Error(r, err)
|
||||
return nil, err
|
||||
|
@ -224,7 +215,7 @@ func (c *BrowsingController) GetGenres(w http.ResponseWriter, r *http.Request) (
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
|
@ -233,7 +224,7 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
|
|||
count := utils.ParamInt(r, "count", 20)
|
||||
includeNotPresent := utils.ParamBool(r, "includeNotPresent", false)
|
||||
|
||||
artist, err := c.em.UpdateArtistInfo(ctx, id, count, includeNotPresent)
|
||||
artist, err := api.externalMetadata.UpdateArtistInfo(ctx, id, count, includeNotPresent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -253,8 +244,8 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetArtistInfo2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
info, err := c.GetArtistInfo(w, r)
|
||||
func (api *Router) GetArtistInfo2(r *http.Request) (*responses.Subsonic, error) {
|
||||
info, err := api.GetArtistInfo(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -275,7 +266,7 @@ func (c *BrowsingController) GetArtistInfo2(w http.ResponseWriter, r *http.Reque
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetSimilarSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetSimilarSongs(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
|
@ -283,7 +274,7 @@ func (c *BrowsingController) GetSimilarSongs(w http.ResponseWriter, r *http.Requ
|
|||
}
|
||||
count := utils.ParamInt(r, "count", 50)
|
||||
|
||||
songs, err := c.em.SimilarSongs(ctx, id, count)
|
||||
songs, err := api.externalMetadata.SimilarSongs(ctx, id, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -295,8 +286,8 @@ func (c *BrowsingController) GetSimilarSongs(w http.ResponseWriter, r *http.Requ
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetSimilarSongs2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
res, err := c.GetSimilarSongs(w, r)
|
||||
func (api *Router) GetSimilarSongs2(r *http.Request) (*responses.Subsonic, error) {
|
||||
res, err := api.GetSimilarSongs(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -308,7 +299,7 @@ func (c *BrowsingController) GetSimilarSongs2(w http.ResponseWriter, r *http.Req
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetTopSongs(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
artist, err := requiredParamString(r, "artist")
|
||||
if err != nil {
|
||||
|
@ -316,7 +307,7 @@ func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request)
|
|||
}
|
||||
count := utils.ParamInt(r, "count", 50)
|
||||
|
||||
songs, err := c.em.TopSongs(ctx, artist, count)
|
||||
songs, err := api.externalMetadata.TopSongs(ctx, artist, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -328,7 +319,7 @@ func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request)
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *model.Artist) (*responses.Directory, error) {
|
||||
func (api *Router) buildArtistDirectory(ctx context.Context, artist *model.Artist) (*responses.Directory, error) {
|
||||
dir := &responses.Directory{}
|
||||
dir.Id = artist.ID
|
||||
dir.Name = artist.Name
|
||||
|
@ -342,7 +333,7 @@ func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *m
|
|||
dir.Starred = &artist.StarredAt
|
||||
}
|
||||
|
||||
albums, err := c.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(artist.ID))
|
||||
albums, err := api.ds.Album(ctx).GetAllWithoutGenres(filter.AlbumsByArtistID(artist.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -351,14 +342,14 @@ func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *m
|
|||
return dir, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) buildArtist(ctx context.Context, artist *model.Artist, albums model.Albums) *responses.ArtistWithAlbumsID3 {
|
||||
func (api *Router) buildArtist(ctx context.Context, artist *model.Artist, albums model.Albums) *responses.ArtistWithAlbumsID3 {
|
||||
a := &responses.ArtistWithAlbumsID3{}
|
||||
a.ArtistID3 = toArtistID3(ctx, *artist)
|
||||
a.Album = childrenFromAlbums(ctx, albums)
|
||||
return a
|
||||
}
|
||||
|
||||
func (c *BrowsingController) buildAlbumDirectory(ctx context.Context, album *model.Album) (*responses.Directory, error) {
|
||||
func (api *Router) buildAlbumDirectory(ctx context.Context, album *model.Album) (*responses.Directory, error) {
|
||||
dir := &responses.Directory{}
|
||||
dir.Id = album.ID
|
||||
dir.Name = album.Name
|
||||
|
@ -374,7 +365,7 @@ func (c *BrowsingController) buildAlbumDirectory(ctx context.Context, album *mod
|
|||
dir.Starred = &album.StarredAt
|
||||
}
|
||||
|
||||
mfs, err := c.ds.MediaFile(ctx).GetAll(filter.SongsByAlbum(album.ID))
|
||||
mfs, err := api.ds.MediaFile(ctx).GetAll(filter.SongsByAlbum(album.ID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -383,7 +374,7 @@ func (c *BrowsingController) buildAlbumDirectory(ctx context.Context, album *mod
|
|||
return dir, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) buildAlbum(ctx context.Context, album *model.Album, mfs model.MediaFiles) *responses.AlbumWithSongsID3 {
|
||||
func (api *Router) buildAlbum(ctx context.Context, album *model.Album, mfs model.MediaFiles) *responses.AlbumWithSongsID3 {
|
||||
dir := &responses.AlbumWithSongsID3{}
|
||||
dir.Id = album.ID
|
||||
dir.Name = album.Name
|
||||
|
|
|
@ -7,24 +7,15 @@ import (
|
|||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
"github.com/navidrome/navidrome/scanner"
|
||||
"github.com/navidrome/navidrome/server/subsonic/responses"
|
||||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type LibraryScanningController struct {
|
||||
scanner scanner.Scanner
|
||||
}
|
||||
|
||||
func NewLibraryScanningController(scanner scanner.Scanner) *LibraryScanningController {
|
||||
return &LibraryScanningController{scanner: scanner}
|
||||
}
|
||||
|
||||
func (c *LibraryScanningController) GetScanStatus(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetScanStatus(r *http.Request) (*responses.Subsonic, error) {
|
||||
// TODO handle multiple mediafolders
|
||||
ctx := r.Context()
|
||||
mediaFolder := conf.Server.MusicFolder
|
||||
status, err := c.scanner.Status(mediaFolder)
|
||||
status, err := api.scanner.Status(mediaFolder)
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error retrieving Scanner status", err)
|
||||
return nil, newError(responses.ErrorGeneric, "Internal Error")
|
||||
|
@ -39,7 +30,7 @@ func (c *LibraryScanningController) GetScanStatus(w http.ResponseWriter, r *http
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) StartScan(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
loggedUser, ok := request.UserFrom(ctx)
|
||||
if !ok {
|
||||
|
@ -55,7 +46,7 @@ func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Req
|
|||
go func() {
|
||||
start := time.Now()
|
||||
log.Info(ctx, "Triggering manual scan", "fullScan", fullScan, "user", loggedUser.UserName)
|
||||
err := c.scanner.RescanAll(ctx, fullScan)
|
||||
err := api.scanner.RescanAll(ctx, fullScan)
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error scanning", err)
|
||||
return
|
||||
|
@ -63,5 +54,5 @@ func (c *LibraryScanningController) StartScan(w http.ResponseWriter, r *http.Req
|
|||
log.Info(ctx, "Manual scan complete", "user", loggedUser.UserName, "elapsed", time.Since(start).Round(100*time.Millisecond))
|
||||
}()
|
||||
|
||||
return c.GetScanStatus(w, r)
|
||||
return api.GetScanStatus(r)
|
||||
}
|
||||
|
|
|
@ -17,17 +17,7 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type MediaAnnotationController struct {
|
||||
ds model.DataStore
|
||||
playTracker scrobbler.PlayTracker
|
||||
broker events.Broker
|
||||
}
|
||||
|
||||
func NewMediaAnnotationController(ds model.DataStore, playTracker scrobbler.PlayTracker, broker events.Broker) *MediaAnnotationController {
|
||||
return &MediaAnnotationController{ds: ds, playTracker: playTracker, broker: broker}
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) SetRating(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) SetRating(r *http.Request) (*responses.Subsonic, error) {
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -38,7 +28,7 @@ func (c *MediaAnnotationController) SetRating(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
|
||||
log.Debug(r, "Setting rating", "rating", rating, "id", id)
|
||||
err = c.setRating(r.Context(), id, rating)
|
||||
err = api.setRating(r.Context(), id, rating)
|
||||
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(r, err)
|
||||
|
@ -52,23 +42,23 @@ func (c *MediaAnnotationController) SetRating(w http.ResponseWriter, r *http.Req
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) setRating(ctx context.Context, id string, rating int) error {
|
||||
func (api *Router) setRating(ctx context.Context, id string, rating int) error {
|
||||
var repo model.AnnotatedRepository
|
||||
var resource string
|
||||
|
||||
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
||||
entity, err := core.GetEntityByID(ctx, api.ds, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch entity.(type) {
|
||||
case *model.Artist:
|
||||
repo = c.ds.Artist(ctx)
|
||||
repo = api.ds.Artist(ctx)
|
||||
resource = "artist"
|
||||
case *model.Album:
|
||||
repo = c.ds.Album(ctx)
|
||||
repo = api.ds.Album(ctx)
|
||||
resource = "album"
|
||||
default:
|
||||
repo = c.ds.MediaFile(ctx)
|
||||
repo = api.ds.MediaFile(ctx)
|
||||
resource = "song"
|
||||
}
|
||||
err = repo.SetRating(rating, id)
|
||||
|
@ -76,11 +66,11 @@ func (c *MediaAnnotationController) setRating(ctx context.Context, id string, ra
|
|||
return err
|
||||
}
|
||||
event := &events.RefreshResource{}
|
||||
c.broker.SendMessage(ctx, event.With(resource, id))
|
||||
api.broker.SendMessage(ctx, event.With(resource, id))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) Star(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Star(r *http.Request) (*responses.Subsonic, error) {
|
||||
ids := utils.ParamStrings(r, "id")
|
||||
albumIds := utils.ParamStrings(r, "albumId")
|
||||
artistIds := utils.ParamStrings(r, "artistId")
|
||||
|
@ -90,7 +80,7 @@ func (c *MediaAnnotationController) Star(w http.ResponseWriter, r *http.Request)
|
|||
ids = append(ids, albumIds...)
|
||||
ids = append(ids, artistIds...)
|
||||
|
||||
err := c.setStar(r.Context(), true, ids...)
|
||||
err := api.setStar(r.Context(), true, ids...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -98,7 +88,7 @@ func (c *MediaAnnotationController) Star(w http.ResponseWriter, r *http.Request)
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) Unstar(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Unstar(r *http.Request) (*responses.Subsonic, error) {
|
||||
ids := utils.ParamStrings(r, "id")
|
||||
albumIds := utils.ParamStrings(r, "albumId")
|
||||
artistIds := utils.ParamStrings(r, "artistId")
|
||||
|
@ -108,7 +98,7 @@ func (c *MediaAnnotationController) Unstar(w http.ResponseWriter, r *http.Reques
|
|||
ids = append(ids, albumIds...)
|
||||
ids = append(ids, artistIds...)
|
||||
|
||||
err := c.setStar(r.Context(), false, ids...)
|
||||
err := api.setStar(r.Context(), false, ids...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -116,7 +106,7 @@ func (c *MediaAnnotationController) Unstar(w http.ResponseWriter, r *http.Reques
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) setStar(ctx context.Context, star bool, ids ...string) error {
|
||||
func (api *Router) setStar(ctx context.Context, star bool, ids ...string) error {
|
||||
if len(ids) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -126,7 +116,7 @@ func (c *MediaAnnotationController) setStar(ctx context.Context, star bool, ids
|
|||
return nil
|
||||
}
|
||||
event := &events.RefreshResource{}
|
||||
err := c.ds.WithTx(func(tx model.DataStore) error {
|
||||
err := api.ds.WithTx(func(tx model.DataStore) error {
|
||||
for _, id := range ids {
|
||||
exist, err := tx.Album(ctx).Exists(id)
|
||||
if err != nil {
|
||||
|
@ -158,7 +148,7 @@ func (c *MediaAnnotationController) setStar(ctx context.Context, star bool, ids
|
|||
}
|
||||
event = event.With("song", id)
|
||||
}
|
||||
c.broker.SendMessage(ctx, event)
|
||||
api.broker.SendMessage(ctx, event)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
@ -173,7 +163,7 @@ func (c *MediaAnnotationController) setStar(ctx context.Context, star bool, ids
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) Scrobble(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Scrobble(r *http.Request) (*responses.Subsonic, error) {
|
||||
ids, err := requiredParamStrings(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -186,12 +176,12 @@ func (c *MediaAnnotationController) Scrobble(w http.ResponseWriter, r *http.Requ
|
|||
ctx := r.Context()
|
||||
|
||||
if submission {
|
||||
err := c.scrobblerSubmit(ctx, ids, times)
|
||||
err := api.scrobblerSubmit(ctx, ids, times)
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error registering scrobbles", "ids", ids, "times", times, err)
|
||||
}
|
||||
} else {
|
||||
err := c.scrobblerNowPlaying(ctx, ids[0])
|
||||
err := api.scrobblerNowPlaying(ctx, ids[0])
|
||||
if err != nil {
|
||||
log.Error(ctx, "Error setting NowPlaying", "id", ids[0], err)
|
||||
}
|
||||
|
@ -200,7 +190,7 @@ func (c *MediaAnnotationController) Scrobble(w http.ResponseWriter, r *http.Requ
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) scrobblerSubmit(ctx context.Context, ids []string, times []time.Time) error {
|
||||
func (api *Router) scrobblerSubmit(ctx context.Context, ids []string, times []time.Time) error {
|
||||
var submissions []scrobbler.Submission
|
||||
log.Debug(ctx, "Scrobbling tracks", "ids", ids, "times", times)
|
||||
for i, id := range ids {
|
||||
|
@ -213,11 +203,11 @@ func (c *MediaAnnotationController) scrobblerSubmit(ctx context.Context, ids []s
|
|||
submissions = append(submissions, scrobbler.Submission{TrackID: id, Timestamp: t})
|
||||
}
|
||||
|
||||
return c.playTracker.Submit(ctx, submissions)
|
||||
return api.scrobbler.Submit(ctx, submissions)
|
||||
}
|
||||
|
||||
func (c *MediaAnnotationController) scrobblerNowPlaying(ctx context.Context, trackId string) error {
|
||||
mf, err := c.ds.MediaFile(ctx).Get(trackId)
|
||||
func (api *Router) scrobblerNowPlaying(ctx context.Context, trackId string) error {
|
||||
mf, err := api.ds.MediaFile(ctx).Get(trackId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -234,6 +224,6 @@ func (c *MediaAnnotationController) scrobblerNowPlaying(ctx context.Context, tra
|
|||
}
|
||||
|
||||
log.Info(ctx, "Now Playing", "title", mf.Title, "artist", mf.Artist, "user", username, "player", player.Name)
|
||||
err = c.playTracker.NowPlaying(ctx, clientId, client, trackId)
|
||||
err = api.scrobbler.NowPlaying(ctx, clientId, client, trackId)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"time"
|
||||
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
|
@ -19,8 +18,7 @@ import (
|
|||
)
|
||||
|
||||
var _ = Describe("MediaAnnotationController", func() {
|
||||
var controller *MediaAnnotationController
|
||||
var w *httptest.ResponseRecorder
|
||||
var router *Router
|
||||
var ds model.DataStore
|
||||
var playTracker *fakePlayTracker
|
||||
var eventBroker *fakeEventBroker
|
||||
|
@ -31,8 +29,7 @@ var _ = Describe("MediaAnnotationController", func() {
|
|||
ds = &tests.MockDataStore{}
|
||||
playTracker = &fakePlayTracker{}
|
||||
eventBroker = &fakeEventBroker{}
|
||||
controller = NewMediaAnnotationController(ds, playTracker, eventBroker)
|
||||
w = httptest.NewRecorder()
|
||||
router = New(ds, nil, nil, nil, nil, nil, nil, eventBroker, nil, playTracker)
|
||||
})
|
||||
|
||||
Describe("Scrobble", func() {
|
||||
|
@ -40,7 +37,7 @@ var _ = Describe("MediaAnnotationController", func() {
|
|||
submissionTime := time.Now()
|
||||
r := newGetRequest("id=12", "id=34")
|
||||
|
||||
_, err := controller.Scrobble(w, r)
|
||||
_, err := router.Scrobble(r)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(playTracker.Submissions).To(HaveLen(2))
|
||||
|
@ -57,7 +54,7 @@ var _ = Describe("MediaAnnotationController", func() {
|
|||
t2 := utils.ToMillis(time2)
|
||||
r := newGetRequest("id=12", "id=34", fmt.Sprintf("time=%d", t1), fmt.Sprintf("time=%d", t2))
|
||||
|
||||
_, err := controller.Scrobble(w, r)
|
||||
_, err := router.Scrobble(r)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(playTracker.Submissions).To(HaveLen(2))
|
||||
|
@ -70,7 +67,7 @@ var _ = Describe("MediaAnnotationController", func() {
|
|||
It("checks if number of ids match number of times", func() {
|
||||
r := newGetRequest("id=12", "id=34", "time=1111")
|
||||
|
||||
_, err := controller.Scrobble(w, r)
|
||||
_, err := router.Scrobble(r)
|
||||
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(playTracker.Submissions).To(BeEmpty())
|
||||
|
@ -86,14 +83,14 @@ var _ = Describe("MediaAnnotationController", func() {
|
|||
})
|
||||
|
||||
It("does not scrobble", func() {
|
||||
_, err := controller.Scrobble(w, req)
|
||||
_, err := router.Scrobble(req)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(playTracker.Submissions).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("registers a NowPlaying", func() {
|
||||
_, err := controller.Scrobble(w, req)
|
||||
_, err := router.Scrobble(req)
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(playTracker.Playing).To(HaveLen(1))
|
||||
|
@ -109,7 +106,7 @@ type fakePlayTracker struct {
|
|||
Error error
|
||||
}
|
||||
|
||||
func (f *fakePlayTracker) NowPlaying(ctx context.Context, playerId string, playerName string, trackId string) error {
|
||||
func (f *fakePlayTracker) NowPlaying(_ context.Context, playerId string, _ string, trackId string) error {
|
||||
if f.Error != nil {
|
||||
return f.Error
|
||||
}
|
||||
|
@ -120,11 +117,11 @@ func (f *fakePlayTracker) NowPlaying(ctx context.Context, playerId string, playe
|
|||
return nil
|
||||
}
|
||||
|
||||
func (f *fakePlayTracker) GetNowPlaying(ctx context.Context) ([]scrobbler.NowPlayingInfo, error) {
|
||||
func (f *fakePlayTracker) GetNowPlaying(_ context.Context) ([]scrobbler.NowPlayingInfo, error) {
|
||||
return nil, f.Error
|
||||
}
|
||||
|
||||
func (f *fakePlayTracker) Submit(ctx context.Context, submissions []scrobbler.Submission) error {
|
||||
func (f *fakePlayTracker) Submit(_ context.Context, submissions []scrobbler.Submission) error {
|
||||
if f.Error != nil {
|
||||
return f.Error
|
||||
}
|
||||
|
@ -139,7 +136,7 @@ type fakeEventBroker struct {
|
|||
Events []events.Event
|
||||
}
|
||||
|
||||
func (f *fakeEventBroker) SendMessage(ctx context.Context, event events.Event) {
|
||||
func (f *fakeEventBroker) SendMessage(_ context.Context, event events.Event) {
|
||||
f.Events = append(f.Events, event)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/consts"
|
||||
"github.com/navidrome/navidrome/core"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/resources"
|
||||
|
@ -18,37 +17,28 @@ import (
|
|||
"github.com/navidrome/navidrome/utils/gravatar"
|
||||
)
|
||||
|
||||
type MediaRetrievalController struct {
|
||||
artwork core.Artwork
|
||||
ds model.DataStore
|
||||
}
|
||||
|
||||
func NewMediaRetrievalController(artwork core.Artwork, ds model.DataStore) *MediaRetrievalController {
|
||||
return &MediaRetrievalController{artwork: artwork, ds: ds}
|
||||
}
|
||||
|
||||
func (c *MediaRetrievalController) GetAvatar(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetAvatar(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
if !conf.Server.EnableGravatar {
|
||||
return c.getPlaceHolderAvatar(w, r)
|
||||
return api.getPlaceHolderAvatar(w, r)
|
||||
}
|
||||
username, err := requiredParamString(r, "username")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx := r.Context()
|
||||
u, err := c.ds.User(ctx).FindByUsername(username)
|
||||
u, err := api.ds.User(ctx).FindByUsername(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Email == "" {
|
||||
log.Warn(ctx, "User needs an email for gravatar to work", "username", username)
|
||||
return c.getPlaceHolderAvatar(w, r)
|
||||
return api.getPlaceHolderAvatar(w, r)
|
||||
}
|
||||
http.Redirect(w, r, gravatar.Url(u.Email, 0), http.StatusFound)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *MediaRetrievalController) getPlaceHolderAvatar(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) getPlaceHolderAvatar(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
f, err := resources.FS().Open(consts.PlaceholderAvatar)
|
||||
if err != nil {
|
||||
log.Error(r, "Image not found", err)
|
||||
|
@ -60,13 +50,13 @@ func (c *MediaRetrievalController) getPlaceHolderAvatar(w http.ResponseWriter, r
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *MediaRetrievalController) GetCoverArt(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetCoverArt(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
id := utils.ParamStringDefault(r, "id", "non-existent")
|
||||
size := utils.ParamInt(r, "size", 0)
|
||||
|
||||
w.Header().Set("cache-control", "public, max-age=315360000")
|
||||
|
||||
imgReader, err := c.artwork.Get(r.Context(), id, size)
|
||||
imgReader, err := api.artwork.Get(r.Context(), id, size)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(r, "Couldn't find coverArt", "id", id, err)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Artwork not found")
|
||||
|
@ -92,13 +82,13 @@ func isSynced(rawLyrics string) bool {
|
|||
return r.MatchString(rawLyrics)
|
||||
}
|
||||
|
||||
func (c *MediaRetrievalController) GetLyrics(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetLyrics(r *http.Request) (*responses.Subsonic, error) {
|
||||
artist := utils.ParamString(r, "artist")
|
||||
title := utils.ParamString(r, "title")
|
||||
response := newResponse()
|
||||
lyrics := responses.Lyrics{}
|
||||
response.Lyrics = &lyrics
|
||||
media_files, err := c.ds.MediaFile(r.Context()).GetAll(filter.SongsWithLyrics(artist, title))
|
||||
media_files, err := api.ds.MediaFile(r.Context()).GetAll(filter.SongsWithLyrics(artist, title))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
)
|
||||
|
||||
var _ = Describe("MediaRetrievalController", func() {
|
||||
var controller *MediaRetrievalController
|
||||
var router *Router
|
||||
var ds model.DataStore
|
||||
mockRepo := &mockedMediaFile{}
|
||||
var artwork *fakeArtwork
|
||||
|
@ -26,7 +26,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
MockedMediaFile: mockRepo,
|
||||
}
|
||||
artwork = &fakeArtwork{}
|
||||
controller = NewMediaRetrievalController(artwork, ds)
|
||||
router = New(ds, artwork, nil, nil, nil, nil, nil, nil, nil, nil)
|
||||
w = httptest.NewRecorder()
|
||||
})
|
||||
|
||||
|
@ -34,7 +34,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
It("should return data for that id", func() {
|
||||
artwork.data = "image data"
|
||||
r := newGetRequest("id=34", "size=128")
|
||||
_, err := controller.GetCoverArt(w, r)
|
||||
_, err := router.GetCoverArt(w, r)
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
Expect(artwork.recvId).To(Equal("34"))
|
||||
|
@ -44,7 +44,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
|
||||
It("should return placeholder if id parameter is missing (mimicking Subsonic)", func() {
|
||||
r := newGetRequest()
|
||||
_, err := controller.GetCoverArt(w, r)
|
||||
_, err := router.GetCoverArt(w, r)
|
||||
|
||||
Expect(err).To(BeNil())
|
||||
Expect(w.Body.String()).To(Equal(artwork.data))
|
||||
|
@ -53,7 +53,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
It("should fail when the file is not found", func() {
|
||||
artwork.err = model.ErrNotFound
|
||||
r := newGetRequest("id=34", "size=128")
|
||||
_, err := controller.GetCoverArt(w, r)
|
||||
_, err := router.GetCoverArt(w, r)
|
||||
|
||||
Expect(err).To(MatchError("Artwork not found"))
|
||||
})
|
||||
|
@ -61,7 +61,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
It("should fail when there is an unknown error", func() {
|
||||
artwork.err = errors.New("weird error")
|
||||
r := newGetRequest("id=34", "size=128")
|
||||
_, err := controller.GetCoverArt(w, r)
|
||||
_, err := router.GetCoverArt(w, r)
|
||||
|
||||
Expect(err).To(MatchError("weird error"))
|
||||
})
|
||||
|
@ -78,7 +78,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
Lyrics: "[00:18.80]We're no strangers to love\n[00:22.80]You know the rules and so do I",
|
||||
},
|
||||
})
|
||||
response, err := controller.GetLyrics(w, r)
|
||||
response, err := router.GetLyrics(r)
|
||||
if err != nil {
|
||||
log.Error("You're missing something.", err)
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ var _ = Describe("MediaRetrievalController", func() {
|
|||
It("should return empty subsonic response if the record corresponding to the given artist & title is not found", func() {
|
||||
r := newGetRequest("artist=Dheeraj", "title=Rinkiya+Ke+Papa")
|
||||
mockRepo.SetData(model.MediaFiles{})
|
||||
response, err := controller.GetLyrics(w, r)
|
||||
response, err := router.GetLyrics(r)
|
||||
if err != nil {
|
||||
log.Error("You're missing something.", err)
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ type fakeArtwork struct {
|
|||
recvSize int
|
||||
}
|
||||
|
||||
func (c *fakeArtwork) Get(ctx context.Context, id string, size int) (io.ReadCloser, error) {
|
||||
func (c *fakeArtwork) Get(_ context.Context, id string, size int) (io.ReadCloser, error) {
|
||||
if c.err != nil {
|
||||
return nil, c.err
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ var _ = Describe("isSynced", func() {
|
|||
})
|
||||
It("returns true if lyrics contain timestamps", func() {
|
||||
Expect(isSynced(`NF Real Music
|
||||
[00:00] ksdjjs
|
||||
[00:00] First line
|
||||
[00:00.85] JUST LIKE YOU
|
||||
[00:00.85] Just in case my car goes off the highway`)).To(Equal(true))
|
||||
Expect(isSynced("[04:02:50.85] Never gonna give you up")).To(Equal(true))
|
||||
|
@ -148,6 +148,6 @@ func (m *mockedMediaFile) SetData(mfs model.MediaFiles) {
|
|||
m.data = mfs
|
||||
}
|
||||
|
||||
func (m *mockedMediaFile) GetAll(options ...model.QueryOptions) (model.MediaFiles, error) {
|
||||
func (m *mockedMediaFile) GetAll(...model.QueryOptions) (model.MediaFiles, error) {
|
||||
return m.data, nil
|
||||
}
|
||||
|
|
|
@ -6,49 +6,39 @@ import (
|
|||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/navidrome/navidrome/core"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/server/subsonic/responses"
|
||||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type PlaylistsController struct {
|
||||
ds model.DataStore
|
||||
pls core.Playlists
|
||||
}
|
||||
|
||||
func NewPlaylistsController(ds model.DataStore, pls core.Playlists) *PlaylistsController {
|
||||
return &PlaylistsController{ds: ds, pls: pls}
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) GetPlaylists(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetPlaylists(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
allPls, err := c.ds.Playlist(ctx).GetAll(model.QueryOptions{Sort: "name"})
|
||||
allPls, err := api.ds.Playlist(ctx).GetAll(model.QueryOptions{Sort: "name"})
|
||||
if err != nil {
|
||||
log.Error(r, err)
|
||||
return nil, err
|
||||
}
|
||||
playlists := make([]responses.Playlist, len(allPls))
|
||||
for i, p := range allPls {
|
||||
playlists[i] = *c.buildPlaylist(p)
|
||||
playlists[i] = *api.buildPlaylist(p)
|
||||
}
|
||||
response := newResponse()
|
||||
response.Playlists = &responses.Playlists{Playlist: playlists}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) GetPlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetPlaylist(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.getPlaylist(ctx, id)
|
||||
return api.getPlaylist(ctx, id)
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) getPlaylist(ctx context.Context, id string) (*responses.Subsonic, error) {
|
||||
pls, err := c.ds.Playlist(ctx).GetWithTracks(id)
|
||||
func (api *Router) getPlaylist(ctx context.Context, id string) (*responses.Subsonic, error) {
|
||||
pls, err := api.ds.Playlist(ctx).GetWithTracks(id)
|
||||
if errors.Is(err, model.ErrNotFound) {
|
||||
log.Error(ctx, err.Error(), "id", id)
|
||||
return nil, newError(responses.ErrorDataNotFound, "Directory not found")
|
||||
|
@ -59,12 +49,12 @@ func (c *PlaylistsController) getPlaylist(ctx context.Context, id string) (*resp
|
|||
}
|
||||
|
||||
response := newResponse()
|
||||
response.Playlist = c.buildPlaylistWithSongs(ctx, pls)
|
||||
response.Playlist = api.buildPlaylistWithSongs(ctx, pls)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) create(ctx context.Context, playlistId, name string, ids []string) (string, error) {
|
||||
err := c.ds.WithTx(func(tx model.DataStore) error {
|
||||
func (api *Router) create(ctx context.Context, playlistId, name string, ids []string) (string, error) {
|
||||
err := api.ds.WithTx(func(tx model.DataStore) error {
|
||||
owner := getUser(ctx)
|
||||
var pls *model.Playlist
|
||||
var err error
|
||||
|
@ -91,7 +81,7 @@ func (c *PlaylistsController) create(ctx context.Context, playlistId, name strin
|
|||
return playlistId, err
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) CreatePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) CreatePlaylist(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
songIds := utils.ParamStrings(r, "songId")
|
||||
playlistId := utils.ParamString(r, "playlistId")
|
||||
|
@ -99,20 +89,20 @@ func (c *PlaylistsController) CreatePlaylist(w http.ResponseWriter, r *http.Requ
|
|||
if playlistId == "" && name == "" {
|
||||
return nil, errors.New("required parameter name is missing")
|
||||
}
|
||||
id, err := c.create(ctx, playlistId, name, songIds)
|
||||
id, err := api.create(ctx, playlistId, name, songIds)
|
||||
if err != nil {
|
||||
log.Error(r, err)
|
||||
return nil, err
|
||||
}
|
||||
return c.getPlaylist(ctx, id)
|
||||
return api.getPlaylist(ctx, id)
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) DeletePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) DeletePlaylist(r *http.Request) (*responses.Subsonic, error) {
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.ds.Playlist(r.Context()).Delete(id)
|
||||
err = api.ds.Playlist(r.Context()).Delete(id)
|
||||
if errors.Is(err, model.ErrNotAuthorized) {
|
||||
return nil, newError(responses.ErrorAuthorizationFail)
|
||||
}
|
||||
|
@ -123,7 +113,7 @@ func (c *PlaylistsController) DeletePlaylist(w http.ResponseWriter, r *http.Requ
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) UpdatePlaylist(r *http.Request) (*responses.Subsonic, error) {
|
||||
playlistId, err := requiredParamString(r, "playlistId")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -151,7 +141,7 @@ func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Requ
|
|||
log.Trace(r, fmt.Sprintf("-- Adding: '%v'", songsToAdd))
|
||||
log.Trace(r, fmt.Sprintf("-- Removing: '%v'", songIndexesToRemove))
|
||||
|
||||
err = c.pls.Update(r.Context(), playlistId, plsName, comment, public, songsToAdd, songIndexesToRemove)
|
||||
err = api.playlists.Update(r.Context(), playlistId, plsName, comment, public, songsToAdd, songIndexesToRemove)
|
||||
if errors.Is(err, model.ErrNotAuthorized) {
|
||||
return nil, newError(responses.ErrorAuthorizationFail)
|
||||
}
|
||||
|
@ -162,15 +152,15 @@ func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Requ
|
|||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) buildPlaylistWithSongs(ctx context.Context, p *model.Playlist) *responses.PlaylistWithSongs {
|
||||
func (api *Router) buildPlaylistWithSongs(ctx context.Context, p *model.Playlist) *responses.PlaylistWithSongs {
|
||||
pls := &responses.PlaylistWithSongs{
|
||||
Playlist: *c.buildPlaylist(*p),
|
||||
Playlist: *api.buildPlaylist(*p),
|
||||
}
|
||||
pls.Entry = childrenFromMediaFiles(ctx, p.MediaFiles())
|
||||
return pls
|
||||
}
|
||||
|
||||
func (c *PlaylistsController) buildPlaylist(p model.Playlist) *responses.Playlist {
|
||||
func (api *Router) buildPlaylist(p model.Playlist) *responses.Playlist {
|
||||
pls := &responses.Playlist{}
|
||||
pls.Id = p.ID
|
||||
pls.Name = p.Name
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//go:build linux || darwin
|
||||
//go:build unix
|
||||
|
||||
// TODO Fix snapshot tests in Windows
|
||||
// Response Snapshot tests. Only run in Linux and macOS, as they fail in Windows
|
||||
|
|
|
@ -16,10 +16,6 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type SearchingController struct {
|
||||
ds model.DataStore
|
||||
}
|
||||
|
||||
type searchParams struct {
|
||||
query string
|
||||
artistCount int
|
||||
|
@ -30,11 +26,7 @@ type searchParams struct {
|
|||
songOffset int
|
||||
}
|
||||
|
||||
func NewSearchingController(ds model.DataStore) *SearchingController {
|
||||
return &SearchingController{ds: ds}
|
||||
}
|
||||
|
||||
func (c *SearchingController) getParams(r *http.Request) (*searchParams, error) {
|
||||
func (api *Router) getParams(r *http.Request) (*searchParams, error) {
|
||||
var err error
|
||||
sp := &searchParams{}
|
||||
sp.query, err = requiredParamString(r, "query")
|
||||
|
@ -78,15 +70,19 @@ func doSearch[T any](ctx context.Context, wg *sync.WaitGroup, s searchFunc[T], q
|
|||
return res
|
||||
}
|
||||
|
||||
func (c *SearchingController) searchAll(r *http.Request, sp *searchParams) (mediaFiles model.MediaFiles, albums model.Albums, artists model.Artists) {
|
||||
func (api *Router) searchAll(r *http.Request, sp *searchParams) (mediaFiles model.MediaFiles, albums model.Albums, artists model.Artists) {
|
||||
start := time.Now()
|
||||
q := sanitize.Accents(strings.ToLower(strings.TrimSuffix(sp.query, "*")))
|
||||
ctx := r.Context()
|
||||
wg := &sync.WaitGroup{}
|
||||
wg.Add(3)
|
||||
go func() { mediaFiles = doSearch(ctx, wg, c.ds.MediaFile(ctx).Search, q, sp.songOffset, sp.songCount) }()
|
||||
go func() { albums = doSearch(ctx, wg, c.ds.Album(ctx).Search, q, sp.albumOffset, sp.albumCount) }()
|
||||
go func() { artists = doSearch(ctx, wg, c.ds.Artist(ctx).Search, q, sp.artistOffset, sp.artistCount) }()
|
||||
go func() {
|
||||
mediaFiles = doSearch(ctx, wg, api.ds.MediaFile(ctx).Search, q, sp.songOffset, sp.songCount)
|
||||
}()
|
||||
go func() { albums = doSearch(ctx, wg, api.ds.Album(ctx).Search, q, sp.albumOffset, sp.albumCount) }()
|
||||
go func() {
|
||||
artists = doSearch(ctx, wg, api.ds.Artist(ctx).Search, q, sp.artistOffset, sp.artistCount)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
if ctx.Err() == nil {
|
||||
|
@ -98,12 +94,12 @@ func (c *SearchingController) searchAll(r *http.Request, sp *searchParams) (medi
|
|||
return mediaFiles, albums, artists
|
||||
}
|
||||
|
||||
func (c *SearchingController) Search2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
sp, err := c.getParams(r)
|
||||
func (api *Router) Search2(r *http.Request) (*responses.Subsonic, error) {
|
||||
sp, err := api.getParams(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mfs, als, as := c.searchAll(r, sp)
|
||||
mfs, als, as := api.searchAll(r, sp)
|
||||
|
||||
response := newResponse()
|
||||
searchResult2 := &responses.SearchResult2{}
|
||||
|
@ -126,13 +122,13 @@ func (c *SearchingController) Search2(w http.ResponseWriter, r *http.Request) (*
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *SearchingController) Search3(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Search3(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
sp, err := c.getParams(r)
|
||||
sp, err := api.getParams(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mfs, als, as := c.searchAll(r, sp)
|
||||
mfs, als, as := api.searchAll(r, sp)
|
||||
|
||||
response := newResponse()
|
||||
searchResult3 := &responses.SearchResult3{}
|
||||
|
|
|
@ -16,17 +16,7 @@ import (
|
|||
"github.com/navidrome/navidrome/utils"
|
||||
)
|
||||
|
||||
type StreamController struct {
|
||||
streamer core.MediaStreamer
|
||||
archiver core.Archiver
|
||||
ds model.DataStore
|
||||
}
|
||||
|
||||
func NewStreamController(streamer core.MediaStreamer, archiver core.Archiver, ds model.DataStore) *StreamController {
|
||||
return &StreamController{streamer: streamer, archiver: archiver, ds: ds}
|
||||
}
|
||||
|
||||
func (c *StreamController) Stream(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Stream(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
id, err := requiredParamString(r, "id")
|
||||
if err != nil {
|
||||
|
@ -36,7 +26,7 @@ func (c *StreamController) Stream(w http.ResponseWriter, r *http.Request) (*resp
|
|||
format := utils.ParamString(r, "format")
|
||||
estimateContentLength := utils.ParamBool(r, "estimateContentLength", false)
|
||||
|
||||
stream, err := c.streamer.NewStream(ctx, id, format, maxBitRate)
|
||||
stream, err := api.streamer.NewStream(ctx, id, format, maxBitRate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -82,7 +72,7 @@ func (c *StreamController) Stream(w http.ResponseWriter, r *http.Request) (*resp
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (c *StreamController) Download(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Download(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
username, _ := request.UsernameFrom(ctx)
|
||||
id, err := requiredParamString(r, "id")
|
||||
|
@ -95,7 +85,7 @@ func (c *StreamController) Download(w http.ResponseWriter, r *http.Request) (*re
|
|||
return nil, newError(responses.ErrorAuthorizationFail, "downloads are disabled")
|
||||
}
|
||||
|
||||
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
||||
entity, err := core.GetEntityByID(ctx, api.ds, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -109,7 +99,7 @@ func (c *StreamController) Download(w http.ResponseWriter, r *http.Request) (*re
|
|||
|
||||
switch v := entity.(type) {
|
||||
case *model.MediaFile:
|
||||
stream, err := c.streamer.NewStream(ctx, id, "raw", 0)
|
||||
stream, err := api.streamer.NewStream(ctx, id, "raw", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -120,13 +110,13 @@ func (c *StreamController) Download(w http.ResponseWriter, r *http.Request) (*re
|
|||
return nil, nil
|
||||
case *model.Album:
|
||||
setHeaders(v.Name)
|
||||
err = c.archiver.ZipAlbum(ctx, id, w)
|
||||
err = api.archiver.ZipAlbum(ctx, id, w)
|
||||
case *model.Artist:
|
||||
setHeaders(v.Name)
|
||||
err = c.archiver.ZipArtist(ctx, id, w)
|
||||
err = api.archiver.ZipArtist(ctx, id, w)
|
||||
case *model.Playlist:
|
||||
setHeaders(v.Name)
|
||||
err = c.archiver.ZipPlaylist(ctx, id, w)
|
||||
err = api.archiver.ZipPlaylist(ctx, id, w)
|
||||
default:
|
||||
err = model.ErrNotFound
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ func NewSystemController() *SystemController {
|
|||
return &SystemController{}
|
||||
}
|
||||
|
||||
func (c *SystemController) Ping(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) Ping(_ *http.Request) (*responses.Subsonic, error) {
|
||||
return newResponse(), nil
|
||||
}
|
||||
|
||||
func (c *SystemController) GetLicense(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetLicense(_ *http.Request) (*responses.Subsonic, error) {
|
||||
response := newResponse()
|
||||
response.License = &responses.License{Valid: true}
|
||||
return response, nil
|
||||
|
|
|
@ -7,14 +7,8 @@ import (
|
|||
"github.com/navidrome/navidrome/server/subsonic/responses"
|
||||
)
|
||||
|
||||
type UsersController struct{}
|
||||
|
||||
func NewUsersController() *UsersController {
|
||||
return &UsersController{}
|
||||
}
|
||||
|
||||
// TODO This is a placeholder. The real one has to read this info from a config file or the database
|
||||
func (c *UsersController) GetUser(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetUser(r *http.Request) (*responses.Subsonic, error) {
|
||||
loggedUser, ok := request.UserFrom(r.Context())
|
||||
if !ok {
|
||||
return nil, newError(responses.ErrorGeneric, "Internal error")
|
||||
|
@ -30,7 +24,7 @@ func (c *UsersController) GetUser(w http.ResponseWriter, r *http.Request) (*resp
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (c *UsersController) GetUsers(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) GetUsers(r *http.Request) (*responses.Subsonic, error) {
|
||||
loggedUser, ok := request.UserFrom(r.Context())
|
||||
if !ok {
|
||||
return nil, newError(responses.ErrorGeneric, "Internal error")
|
||||
|
|
|
@ -1,112 +0,0 @@
|
|||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate go run github.com/google/wire/cmd/wire
|
||||
//go:build !wireinject
|
||||
// +build !wireinject
|
||||
|
||||
package subsonic
|
||||
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
// Injectors from wire_injectors.go:
|
||||
|
||||
func initSystemController(router *Router) *SystemController {
|
||||
systemController := NewSystemController()
|
||||
return systemController
|
||||
}
|
||||
|
||||
func initBrowsingController(router *Router) *BrowsingController {
|
||||
dataStore := router.DataStore
|
||||
externalMetadata := router.ExternalMetadata
|
||||
browsingController := NewBrowsingController(dataStore, externalMetadata)
|
||||
return browsingController
|
||||
}
|
||||
|
||||
func initAlbumListController(router *Router) *AlbumListController {
|
||||
dataStore := router.DataStore
|
||||
playTracker := router.Scrobbler
|
||||
albumListController := NewAlbumListController(dataStore, playTracker)
|
||||
return albumListController
|
||||
}
|
||||
|
||||
func initMediaAnnotationController(router *Router) *MediaAnnotationController {
|
||||
dataStore := router.DataStore
|
||||
playTracker := router.Scrobbler
|
||||
broker := router.Broker
|
||||
mediaAnnotationController := NewMediaAnnotationController(dataStore, playTracker, broker)
|
||||
return mediaAnnotationController
|
||||
}
|
||||
|
||||
func initPlaylistsController(router *Router) *PlaylistsController {
|
||||
dataStore := router.DataStore
|
||||
playlists := router.Playlists
|
||||
playlistsController := NewPlaylistsController(dataStore, playlists)
|
||||
return playlistsController
|
||||
}
|
||||
|
||||
func initSearchingController(router *Router) *SearchingController {
|
||||
dataStore := router.DataStore
|
||||
searchingController := NewSearchingController(dataStore)
|
||||
return searchingController
|
||||
}
|
||||
|
||||
func initUsersController(router *Router) *UsersController {
|
||||
usersController := NewUsersController()
|
||||
return usersController
|
||||
}
|
||||
|
||||
func initMediaRetrievalController(router *Router) *MediaRetrievalController {
|
||||
artwork := router.Artwork
|
||||
dataStore := router.DataStore
|
||||
mediaRetrievalController := NewMediaRetrievalController(artwork, dataStore)
|
||||
return mediaRetrievalController
|
||||
}
|
||||
|
||||
func initStreamController(router *Router) *StreamController {
|
||||
mediaStreamer := router.Streamer
|
||||
archiver := router.Archiver
|
||||
dataStore := router.DataStore
|
||||
streamController := NewStreamController(mediaStreamer, archiver, dataStore)
|
||||
return streamController
|
||||
}
|
||||
|
||||
func initBookmarksController(router *Router) *BookmarksController {
|
||||
dataStore := router.DataStore
|
||||
bookmarksController := NewBookmarksController(dataStore)
|
||||
return bookmarksController
|
||||
}
|
||||
|
||||
func initLibraryScanningController(router *Router) *LibraryScanningController {
|
||||
scanner := router.Scanner
|
||||
libraryScanningController := NewLibraryScanningController(scanner)
|
||||
return libraryScanningController
|
||||
}
|
||||
|
||||
// wire_injectors.go:
|
||||
|
||||
var allProviders = wire.NewSet(
|
||||
NewSystemController,
|
||||
NewBrowsingController,
|
||||
NewAlbumListController,
|
||||
NewMediaAnnotationController,
|
||||
NewPlaylistsController,
|
||||
NewSearchingController,
|
||||
NewUsersController,
|
||||
NewMediaRetrievalController,
|
||||
NewStreamController,
|
||||
NewBookmarksController,
|
||||
NewLibraryScanningController, wire.FieldsOf(
|
||||
new(*Router),
|
||||
"DataStore",
|
||||
"Artwork",
|
||||
"Streamer",
|
||||
"Archiver",
|
||||
"ExternalMetadata",
|
||||
"Scanner",
|
||||
"Broker",
|
||||
"Scrobbler",
|
||||
"Playlists",
|
||||
),
|
||||
)
|
|
@ -1,77 +0,0 @@
|
|||
//go:build wireinject
|
||||
|
||||
package subsonic
|
||||
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
)
|
||||
|
||||
var allProviders = wire.NewSet(
|
||||
NewSystemController,
|
||||
NewBrowsingController,
|
||||
NewAlbumListController,
|
||||
NewMediaAnnotationController,
|
||||
NewPlaylistsController,
|
||||
NewSearchingController,
|
||||
NewUsersController,
|
||||
NewMediaRetrievalController,
|
||||
NewStreamController,
|
||||
NewBookmarksController,
|
||||
NewLibraryScanningController,
|
||||
wire.FieldsOf(
|
||||
new(*Router),
|
||||
"DataStore",
|
||||
"Artwork",
|
||||
"Streamer",
|
||||
"Archiver",
|
||||
"ExternalMetadata",
|
||||
"Scanner",
|
||||
"Broker",
|
||||
"Scrobbler",
|
||||
"Playlists",
|
||||
),
|
||||
)
|
||||
|
||||
func initSystemController(router *Router) *SystemController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initBrowsingController(router *Router) *BrowsingController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initAlbumListController(router *Router) *AlbumListController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initMediaAnnotationController(router *Router) *MediaAnnotationController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initPlaylistsController(router *Router) *PlaylistsController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initSearchingController(router *Router) *SearchingController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initUsersController(router *Router) *UsersController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initMediaRetrievalController(router *Router) *MediaRetrievalController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initStreamController(router *Router) *StreamController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initBookmarksController(router *Router) *BookmarksController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
||||
|
||||
func initLibraryScanningController(router *Router) *LibraryScanningController {
|
||||
panic(wire.Build(allProviders))
|
||||
}
|
Loading…
Reference in New Issue