mirror of
https://github.com/navidrome/navidrome.git
synced 2025-06-18 16:03:19 +03:00
Handle exporting playlists as m3u files
This commit is contained in:
parent
8fa5544af7
commit
366054e8cc
@ -104,24 +104,12 @@ func (app *Router) RX(r chi.Router, pathPrefix string, constructor rest.Reposito
|
|||||||
type restHandler = func(rest.RepositoryConstructor, ...rest.Logger) http.HandlerFunc
|
type restHandler = func(rest.RepositoryConstructor, ...rest.Logger) http.HandlerFunc
|
||||||
|
|
||||||
func (app *Router) addPlaylistTrackRoute(r chi.Router) {
|
func (app *Router) addPlaylistTrackRoute(r chi.Router) {
|
||||||
// Add a middleware to capture the playlistId
|
|
||||||
wrapper := func(f restHandler) http.HandlerFunc {
|
|
||||||
return func(res http.ResponseWriter, req *http.Request) {
|
|
||||||
c := func(ctx context.Context) rest.Repository {
|
|
||||||
plsRepo := app.ds.Resource(ctx, model.Playlist{})
|
|
||||||
plsId := chi.URLParam(req, "playlistId")
|
|
||||||
return plsRepo.(model.PlaylistRepository).Tracks(plsId)
|
|
||||||
}
|
|
||||||
|
|
||||||
f(c).ServeHTTP(res, req)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Route("/playlist/{playlistId}/tracks", func(r chi.Router) {
|
r.Route("/playlist/{playlistId}/tracks", func(r chi.Router) {
|
||||||
r.Get("/", wrapper(rest.GetAll))
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
getPlaylist(app.ds)(w, r)
|
||||||
|
})
|
||||||
r.Route("/{id}", func(r chi.Router) {
|
r.Route("/{id}", func(r chi.Router) {
|
||||||
r.Use(UrlParams)
|
r.Use(UrlParams)
|
||||||
r.Get("/", wrapper(rest.Get))
|
|
||||||
r.Put("/", func(w http.ResponseWriter, r *http.Request) {
|
r.Put("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
reorderItem(app.ds)(w, r)
|
reorderItem(app.ds)(w, r)
|
||||||
})
|
})
|
||||||
|
@ -1,16 +1,76 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/deluan/navidrome/log"
|
"github.com/deluan/navidrome/log"
|
||||||
"github.com/deluan/navidrome/model"
|
"github.com/deluan/navidrome/model"
|
||||||
"github.com/deluan/navidrome/utils"
|
"github.com/deluan/navidrome/utils"
|
||||||
|
"github.com/deluan/rest"
|
||||||
|
"github.com/go-chi/chi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getPlaylist(ds model.DataStore) http.HandlerFunc {
|
||||||
|
// Add a middleware to capture the playlistId
|
||||||
|
wrapper := func(handler restHandler) http.HandlerFunc {
|
||||||
|
return func(res http.ResponseWriter, req *http.Request) {
|
||||||
|
constructor := func(ctx context.Context) rest.Repository {
|
||||||
|
plsRepo := ds.Playlist(ctx)
|
||||||
|
plsId := chi.URLParam(req, "playlistId")
|
||||||
|
return plsRepo.(model.PlaylistRepository).Tracks(plsId)
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(constructor).ServeHTTP(res, req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
accept := r.Header.Get("accept")
|
||||||
|
if strings.ToLower(accept) == "audio/x-mpegurl" {
|
||||||
|
handleExportPlaylist(ds)(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
wrapper(rest.GetAll)(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleExportPlaylist(ds model.DataStore) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ctx := r.Context()
|
||||||
|
plsRepo := ds.Playlist(ctx)
|
||||||
|
plsId := chi.URLParam(r, "playlistId")
|
||||||
|
pls, err := plsRepo.Get(plsId)
|
||||||
|
if err == model.ErrNotFound {
|
||||||
|
log.Warn("Playlist not found", "playlistId", plsId)
|
||||||
|
http.Error(w, "not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Error retrieving the playlist", "playlistId", plsId, err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "audio/x-mpegurl")
|
||||||
|
|
||||||
|
// TODO: Move this and the import playlist logic to `core`
|
||||||
|
w.Write([]byte("#EXTM3U\n"))
|
||||||
|
for _, t := range pls.Tracks {
|
||||||
|
header := fmt.Sprintf("#EXTINF:%.f,%s - %s\n", t.Duration, t.Artist, t.Title)
|
||||||
|
line := t.Path + "\n"
|
||||||
|
_, err := w.Write([]byte(header + line))
|
||||||
|
if err != nil {
|
||||||
|
log.Error(ctx, "Error sending playlist", "name", pls.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func deleteFromPlaylist(ds model.DataStore) http.HandlerFunc {
|
func deleteFromPlaylist(ds model.DataStore) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
playlistId := utils.ParamString(r, ":playlistId")
|
playlistId := utils.ParamString(r, ":playlistId")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user