2021-06-14 01:15:41 +02:00
|
|
|
package nativeapi
|
2020-01-20 01:34:54 +01:00
|
|
|
|
|
|
|
import (
|
2020-01-20 02:40:18 +01:00
|
|
|
"context"
|
2020-01-20 01:34:54 +01:00
|
|
|
"net/http"
|
2020-01-20 02:40:18 +01:00
|
|
|
"net/url"
|
|
|
|
"strings"
|
2020-01-20 01:34:54 +01:00
|
|
|
|
2020-01-20 02:40:18 +01:00
|
|
|
"github.com/deluan/rest"
|
2021-05-11 23:21:18 +02:00
|
|
|
"github.com/go-chi/chi/v5"
|
2020-04-28 03:23:15 +02:00
|
|
|
"github.com/navidrome/navidrome/conf"
|
2021-06-08 21:44:30 +02:00
|
|
|
"github.com/navidrome/navidrome/core"
|
2020-01-24 01:44:08 +01:00
|
|
|
"github.com/navidrome/navidrome/model"
|
2021-06-13 18:46:36 +02:00
|
|
|
"github.com/navidrome/navidrome/server"
|
2020-11-08 06:06:48 +01:00
|
|
|
"github.com/navidrome/navidrome/server/events"
|
2020-01-20 01:34:54 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type Router struct {
|
2021-06-13 18:46:36 +02:00
|
|
|
http.Handler
|
2020-11-08 06:06:48 +01:00
|
|
|
ds model.DataStore
|
|
|
|
broker events.Broker
|
2021-06-08 21:44:30 +02:00
|
|
|
share core.Share
|
2020-01-20 01:34:54 +01:00
|
|
|
}
|
|
|
|
|
2021-06-08 21:44:30 +02:00
|
|
|
func New(ds model.DataStore, broker events.Broker, share core.Share) *Router {
|
2021-06-13 18:46:36 +02:00
|
|
|
r := &Router{ds: ds, broker: broker, share: share}
|
|
|
|
r.Handler = r.routes()
|
|
|
|
return r
|
2020-01-20 01:34:54 +01:00
|
|
|
}
|
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
func (n *Router) routes() http.Handler {
|
2020-01-20 01:34:54 +01:00
|
|
|
r := chi.NewRouter()
|
2020-01-20 02:40:18 +01:00
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
r.Use(server.Authenticator(n.ds))
|
2021-06-13 18:46:36 +02:00
|
|
|
r.Use(server.JWTRefresher)
|
2021-06-14 01:15:41 +02:00
|
|
|
n.R(r, "/user", model.User{}, true)
|
|
|
|
n.R(r, "/song", model.MediaFile{}, true)
|
|
|
|
n.R(r, "/album", model.Album{}, true)
|
|
|
|
n.R(r, "/artist", model.Artist{}, true)
|
2021-07-17 01:41:49 +02:00
|
|
|
n.R(r, "/genre", model.Genre{}, true)
|
2021-06-14 01:15:41 +02:00
|
|
|
n.R(r, "/player", model.Player{}, true)
|
|
|
|
n.R(r, "/playlist", model.Playlist{}, true)
|
|
|
|
n.R(r, "/transcoding", model.Transcoding{}, conf.Server.EnableTranscodingConfig)
|
|
|
|
n.RX(r, "/share", n.share.NewRepository, true)
|
|
|
|
n.RX(r, "/translation", newTranslationRepository, false)
|
2021-06-13 18:46:36 +02:00
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
n.addPlaylistTrackRoute(r)
|
2021-06-13 18:46:36 +02:00
|
|
|
|
|
|
|
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
|
|
|
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
_, _ = w.Write([]byte(`{"response":"ok", "id":"keepalive"}`))
|
2020-01-20 02:40:18 +01:00
|
|
|
})
|
2020-01-23 00:35:44 +01:00
|
|
|
|
2021-06-13 18:46:36 +02:00
|
|
|
if conf.Server.DevActivityPanel {
|
2021-06-14 01:15:41 +02:00
|
|
|
r.Handle("/events", n.broker)
|
2021-06-13 18:46:36 +02:00
|
|
|
}
|
2020-01-23 00:35:44 +01:00
|
|
|
|
2020-01-20 01:34:54 +01:00
|
|
|
return r
|
|
|
|
}
|
2020-01-20 02:40:18 +01:00
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
func (n *Router) R(r chi.Router, pathPrefix string, model interface{}, persistable bool) {
|
2020-01-22 18:32:31 +01:00
|
|
|
constructor := func(ctx context.Context) rest.Repository {
|
2021-06-14 01:15:41 +02:00
|
|
|
return n.ds.Resource(ctx, model)
|
2020-01-22 18:32:31 +01:00
|
|
|
}
|
2021-06-14 01:15:41 +02:00
|
|
|
n.RX(r, pathPrefix, constructor, persistable)
|
2020-05-02 00:29:50 +02:00
|
|
|
}
|
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
func (n *Router) RX(r chi.Router, pathPrefix string, constructor rest.RepositoryConstructor, persistable bool) {
|
2020-01-20 02:40:18 +01:00
|
|
|
r.Route(pathPrefix, func(r chi.Router) {
|
2020-01-22 18:32:31 +01:00
|
|
|
r.Get("/", rest.GetAll(constructor))
|
2020-04-28 03:23:15 +02:00
|
|
|
if persistable {
|
|
|
|
r.Post("/", rest.Post(constructor))
|
|
|
|
}
|
2020-05-02 00:29:50 +02:00
|
|
|
r.Route("/{id}", func(r chi.Router) {
|
2021-05-02 21:23:51 +02:00
|
|
|
r.Use(urlParams)
|
2020-01-22 18:32:31 +01:00
|
|
|
r.Get("/", rest.Get(constructor))
|
2020-04-28 03:23:15 +02:00
|
|
|
if persistable {
|
|
|
|
r.Put("/", rest.Put(constructor))
|
|
|
|
r.Delete("/", rest.Delete(constructor))
|
|
|
|
}
|
2020-01-20 02:40:18 +01:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-06-14 01:15:41 +02:00
|
|
|
func (n *Router) addPlaylistTrackRoute(r chi.Router) {
|
2020-05-09 05:48:06 +02:00
|
|
|
r.Route("/playlist/{playlistId}/tracks", func(r chi.Router) {
|
2020-08-22 18:15:26 +02:00
|
|
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
2021-06-14 01:15:41 +02:00
|
|
|
getPlaylist(n.ds)(w, r)
|
2020-08-22 18:15:26 +02:00
|
|
|
})
|
2020-05-09 05:48:06 +02:00
|
|
|
r.Route("/{id}", func(r chi.Router) {
|
2021-05-02 21:23:51 +02:00
|
|
|
r.Use(urlParams)
|
2020-06-05 01:05:41 +02:00
|
|
|
r.Put("/", func(w http.ResponseWriter, r *http.Request) {
|
2021-06-14 01:15:41 +02:00
|
|
|
reorderItem(n.ds)(w, r)
|
2020-06-05 01:05:41 +02:00
|
|
|
})
|
2020-05-17 00:10:08 +02:00
|
|
|
r.Delete("/", func(w http.ResponseWriter, r *http.Request) {
|
2021-06-14 01:15:41 +02:00
|
|
|
deleteFromPlaylist(n.ds)(w, r)
|
2020-05-17 00:10:08 +02:00
|
|
|
})
|
2020-05-09 05:48:06 +02:00
|
|
|
})
|
2021-05-02 21:23:51 +02:00
|
|
|
r.With(urlParams).Post("/", func(w http.ResponseWriter, r *http.Request) {
|
2021-06-14 01:15:41 +02:00
|
|
|
addToPlaylist(n.ds)(w, r)
|
2020-05-16 02:47:15 +02:00
|
|
|
})
|
2020-05-09 05:48:06 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-01-20 02:40:18 +01:00
|
|
|
// Middleware to convert Chi URL params (from Context) to query params, as expected by our REST package
|
2021-05-02 21:23:51 +02:00
|
|
|
func urlParams(next http.Handler) http.Handler {
|
2020-01-20 02:40:18 +01:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := chi.RouteContext(r.Context())
|
|
|
|
parts := make([]string, 0)
|
|
|
|
for i, key := range ctx.URLParams.Keys {
|
|
|
|
value := ctx.URLParams.Values[i]
|
|
|
|
if key == "*" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
parts = append(parts, url.QueryEscape(":"+key)+"="+url.QueryEscape(value))
|
|
|
|
}
|
|
|
|
q := strings.Join(parts, "&")
|
|
|
|
if r.URL.RawQuery == "" {
|
|
|
|
r.URL.RawQuery = q
|
|
|
|
} else {
|
|
|
|
r.URL.RawQuery += "&" + q
|
|
|
|
}
|
|
|
|
|
|
|
|
next.ServeHTTP(w, r)
|
|
|
|
})
|
|
|
|
}
|