diff --git a/server/nativeapi/native_api.go b/server/nativeapi/native_api.go index ca93957ac..fe41c4cbc 100644 --- a/server/nativeapi/native_api.go +++ b/server/nativeapi/native_api.go @@ -54,6 +54,7 @@ func (n *Router) routes() http.Handler { n.addPlaylistRoute(r) n.addPlaylistTrackRoute(r) n.addDeleteSongRoute(r) + n.addGetBeetsTrackRoute(r) // Keepalive endpoint to be used to keep the session valid (ex: while playing songs) r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) { @@ -148,10 +149,19 @@ func (n *Router) addPlaylistTrackRoute(r chi.Router) { } func (n *Router) addDeleteSongRoute(r chi.Router) { - r.Route("/deleteSong", func(r chi.Router) { + r.Route("/delete", func(r chi.Router) { r.Use(server.URLParamsMiddleware) r.Delete("/", func(w http.ResponseWriter, r *http.Request) { deleteSong(n.ds)(w, r) }) }) } + +func (n *Router) addGetBeetsTrackRoute(r chi.Router) { + r.Route("/getBeetTrack", func(r chi.Router) { + r.Use(server.URLParamsMiddleware) + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + getBeetTrack(n.ds)(w, r) + }) + }) +} \ No newline at end of file diff --git a/server/nativeapi/song.go b/server/nativeapi/song.go index fbfe017ee..ada344660 100644 --- a/server/nativeapi/song.go +++ b/server/nativeapi/song.go @@ -8,6 +8,7 @@ import ( "github.com/navidrome/navidrome/log" "github.com/navidrome/navidrome/model" + "github.com/navidrome/navidrome/utils/req" ) type BeetsItem struct { @@ -70,7 +71,7 @@ type BeetsItem struct { Disctitle string `json:"disctitle"` Lyrics string `json:"lyrics"` Albumstatus string `json:"albumstatus"` - Albumtypes string `json:"albumtypes"` + Albumtypes any `json:"albumtypes"` Releasegroupdisambig string `json:"releasegroupdisambig"` Comments string `json:"comments"` Encoder string `json:"encoder"` @@ -98,6 +99,7 @@ type BeetsItem struct { func deleteSong(ds model.DataStore) http.HandlerFunc { type deleteSongPayload struct { Ids []string `json:"ids"` + User string `json:"user"` } return func(w http.ResponseWriter, r *http.Request) { // todo: tests, use proper url parsing lib @@ -118,19 +120,22 @@ func deleteSong(ds model.DataStore) http.HandlerFunc { println(mf.Title) // todo set this base from env variable //baseUrl := "http://127.0.0.1:8337" - baseUrl := "http://host.docker.internal:8337" + // get docker port + baseUrl := fmt.Sprintf("http://beets%s:8337", payload.User) queryEndPoint := "/item/query/" - queryStr := fmt.Sprintf("artist:%s/title:%s/album:%s", mf.Artist, mf.Title, mf.Album) + queryStr := fmt.Sprintf("artist:%s/title:%s/album:%s/user:%s", mf.Artist, mf.Title, mf.Album, payload.User) url := baseUrl + queryEndPoint + queryStr fmt.Printf("query url: %s\n", url) resp, err := http.Get(url) // nolint if err != nil { log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } body, err := io.ReadAll(resp.Body) if err != nil { log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } sb := string(body) @@ -138,47 +143,99 @@ func deleteSong(ds model.DataStore) http.HandlerFunc { err = json.Unmarshal([]byte(sb), &beetsItem) if err != nil { log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) return } length := len(beetsItem.Results) - if length != 1 { - log.Error("following query string matched n entries", "n", length, "queryStr", queryStr) - return + log.Info("following query string matched ", length, "entries: ", queryStr) + for _, item := range beetsItem.Results { + log.Info("deleting: ", item.Artist, " : ", item.Title, " id: ", item.ID) + + deleteStr := fmt.Sprintf("/item/%d", item.ID) + + deleteFromDiskStr := "?delete" + + del_url := baseUrl + deleteStr + deleteFromDiskStr + // Create request + req, err := http.NewRequest(http.MethodDelete, del_url, nil) + log.Info("delete request: ", req) + if err != nil { + log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + // Fetch Request + client := &http.Client{} + del_resp, del_err := client.Do(req) + if del_err != nil { + log.Error(del_err) + http.Error(w, del_err.Error(), http.StatusInternalServerError) + return + } + defer del_resp.Body.Close() + + // read the response body + del_body, err := io.ReadAll(del_resp.Body) + if err != nil { + log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // print the response body + fmt.Println(string(del_body)) + log.Info("del body: ", del_body) } - item := beetsItem.Results[0] - log.Info("deleting: ", item.Artist, " : ", item.Title, " id: ", item.ID) - - deleteStr := fmt.Sprintf("/item/%d", item.ID) - - deleteFromDiskStr := "?delete" - - del_url := baseUrl + deleteStr + deleteFromDiskStr - // Create request - req, err := http.NewRequest(http.MethodDelete, del_url, nil) - log.Info("delete request: ", req) - if err != nil { - log.Error(err) - return - } - // Fetch Request - client := &http.Client{} - del_resp, del_err := client.Do(req) - if del_err != nil { - log.Error(err) - return - } - defer del_resp.Body.Close() - - // read the response body - del_body, err := io.ReadAll(del_resp.Body) - if err != nil { - log.Error(err) - return - } - - // print the response body - fmt.Println(string(del_body)) - log.Info("del body: ", del_body) } } } + +func getBeetTrack(ds model.DataStore) http.HandlerFunc { + + return func(w http.ResponseWriter, r *http.Request) { + // todo: tests, use proper url parsing lib + p := req.Params(r) + id, _ := p.String("id") + user, _ := p.String("user") + + log.Info("got parameters", "id", id, "user", user) + ctx := r.Context() + mf, err := ds.MediaFile(ctx).Get(id) + if err != nil { + log.Error(err) + } + if mf == nil { + log.Error("no mediafile for id", "id", id) + } + log.Info("mediafile", "mf", mf) + // todo set this base from env variable + //baseUrl := "http://127.0.0.1:8337" + baseUrl := fmt.Sprintf("http://beets%s:8337", user) + queryEndPoint := "/item/query/" + queryStr := fmt.Sprintf("artist:%s/title:%s/user:%s", mf.Artist, mf.Title, user) + url := baseUrl + queryEndPoint + queryStr + fmt.Printf("query url: %s\n", url) + resp, err := http.Get(url) // nolint + if err != nil { + log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + body, err := io.ReadAll(resp.Body) + if err != nil { + log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + sb := string(body) + var beetsItem BeetsItem + err = json.Unmarshal([]byte(sb), &beetsItem) + if err != nil { + log.Error(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + json.NewEncoder(w).Encode(beetsItem) + } +}