Add dedicated SimilarArtists call
This commit is contained in:
@@ -79,6 +79,8 @@ func (api *Router) routes() http.Handler {
|
||||
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.Group(func(r chi.Router) {
|
||||
c := initAlbumListController(api)
|
||||
|
||||
+37
-18
@@ -109,7 +109,7 @@ func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Re
|
||||
id := utils.ParamString(r, "id")
|
||||
ctx := r.Context()
|
||||
|
||||
entity, err := getEntityByID(ctx, c.ds, id)
|
||||
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
||||
switch {
|
||||
case err == model.ErrNotFound:
|
||||
log.Error(r, "Requested ID not found ", "id", id)
|
||||
@@ -241,26 +241,12 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
|
||||
count := utils.ParamInt(r, "count", 20)
|
||||
includeNotPresent := utils.ParamBool(r, "includeNotPresent", false)
|
||||
|
||||
entity, err := getEntityByID(ctx, c.ds, id)
|
||||
info, err := c.ei.ArtistInfo(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch v := entity.(type) {
|
||||
case *model.MediaFile:
|
||||
id = v.ArtistID
|
||||
case *model.Album:
|
||||
id = v.AlbumArtistID
|
||||
case *model.Artist:
|
||||
id = v.ID
|
||||
default:
|
||||
err = model.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := c.ei.ArtistInfo(ctx, id, includeNotPresent, count)
|
||||
similar, err := c.ei.SimilarArtists(ctx, id, includeNotPresent, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -273,7 +259,7 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
|
||||
response.ArtistInfo.LargeImageUrl = info.LargeImageUrl
|
||||
response.ArtistInfo.LastFmUrl = info.LastFMUrl
|
||||
response.ArtistInfo.MusicBrainzID = info.MBID
|
||||
for _, s := range info.Similar {
|
||||
for _, s := range similar {
|
||||
similar := responses.Artist{}
|
||||
similar.Id = s.ID
|
||||
similar.Name = s.Name
|
||||
@@ -306,6 +292,39 @@ 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) {
|
||||
ctx := r.Context()
|
||||
id, err := requiredParamString(r, "id", "id parameter required")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := utils.ParamInt(r, "count", 20)
|
||||
|
||||
songs, err := c.ei.SimilarSongs(ctx, id, count)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.SimilarSongs = &responses.SimilarSongs{
|
||||
Song: childrenFromMediaFiles(ctx, songs),
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (c *BrowsingController) GetSimilarSongs2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
res, err := c.GetSimilarSongs(w, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.SimilarSongs2 = &responses.SimilarSongs2{
|
||||
Song: res.SimilarSongs2.Song,
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// TODO Integrate with Last.FM
|
||||
func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
||||
response := newResponse()
|
||||
|
||||
@@ -258,24 +258,3 @@ func childrenFromAlbums(ctx context.Context, als model.Albums) []responses.Child
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
// TODO: Should the type be encoded in the ID?
|
||||
func getEntityByID(ctx context.Context, ds model.DataStore, id string) (interface{}, error) {
|
||||
ar, err := ds.Artist(ctx).Get(id)
|
||||
if err == nil {
|
||||
return ar, nil
|
||||
}
|
||||
al, err := ds.Album(ctx).Get(id)
|
||||
if err == nil {
|
||||
return al, nil
|
||||
}
|
||||
pls, err := ds.Playlist(ctx).Get(id)
|
||||
if err == nil {
|
||||
return pls, nil
|
||||
}
|
||||
mf, err := ds.MediaFile(ctx).Get(id)
|
||||
if err == nil {
|
||||
return mf, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs":{"song":[{"id":"1","isDir":false,"title":"title","isVideo":false}]}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0" type="navidrome" serverVersion="v0.0.0"><similarSongs><song id="1" isDir="false" title="title" isVideo="false"></song></similarSongs></subsonic-response>
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs":{}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0" type="navidrome" serverVersion="v0.0.0"><similarSongs></similarSongs></subsonic-response>
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs2":{"song":[{"id":"1","isDir":false,"title":"title","isVideo":false}]}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0" type="navidrome" serverVersion="v0.0.0"><similarSongs2><song id="1" isDir="false" title="title" isVideo="false"></song></similarSongs2></subsonic-response>
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs2":{}}
|
||||
+1
@@ -0,0 +1 @@
|
||||
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0" type="navidrome" serverVersion="v0.0.0"><similarSongs2></similarSongs2></subsonic-response>
|
||||
@@ -36,9 +36,11 @@ type Subsonic struct {
|
||||
ArtistWithAlbumsID3 *ArtistWithAlbumsID3 `xml:"artist,omitempty" json:"artist,omitempty"`
|
||||
AlbumWithSongsID3 *AlbumWithSongsID3 `xml:"album,omitempty" json:"album,omitempty"`
|
||||
|
||||
ArtistInfo *ArtistInfo `xml:"artistInfo,omitempty" json:"artistInfo,omitempty"`
|
||||
ArtistInfo2 *ArtistInfo2 `xml:"artistInfo2,omitempty" json:"artistInfo2,omitempty"`
|
||||
TopSongs *TopSongs `xml:"topSongs,omitempty" json:"topSongs,omitempty"`
|
||||
ArtistInfo *ArtistInfo `xml:"artistInfo,omitempty" json:"artistInfo,omitempty"`
|
||||
ArtistInfo2 *ArtistInfo2 `xml:"artistInfo2,omitempty" json:"artistInfo2,omitempty"`
|
||||
SimilarSongs *SimilarSongs `xml:"similarSongs,omitempty" json:"similarSongs,omitempty"`
|
||||
SimilarSongs2 *SimilarSongs2 `xml:"similarSongs2,omitempty" json:"similarSongs2,omitempty"`
|
||||
TopSongs *TopSongs `xml:"topSongs,omitempty" json:"topSongs,omitempty"`
|
||||
|
||||
PlayQueue *PlayQueue `xml:"playQueue,omitempty" json:"playQueue,omitempty"`
|
||||
Bookmarks *Bookmarks `xml:"bookmarks,omitempty" json:"bookmarks,omitempty"`
|
||||
@@ -298,6 +300,14 @@ type ArtistInfo2 struct {
|
||||
SimilarArtist []ArtistID3 `xml:"similarArtist,omitempty" json:"similarArtist,omitempty"`
|
||||
}
|
||||
|
||||
type SimilarSongs struct {
|
||||
Song []Child `xml:"song,omitempty" json:"song,omitempty"`
|
||||
}
|
||||
|
||||
type SimilarSongs2 struct {
|
||||
Song []Child `xml:"song,omitempty" json:"song,omitempty"`
|
||||
}
|
||||
|
||||
type TopSongs struct {
|
||||
Song []Child `xml:"song,omitempty" json:"song,omitempty"`
|
||||
}
|
||||
|
||||
@@ -361,6 +361,64 @@ var _ = Describe("Responses", func() {
|
||||
})
|
||||
})
|
||||
|
||||
Describe("SimilarSongs", func() {
|
||||
BeforeEach(func() {
|
||||
response.SimilarSongs = &SimilarSongs{}
|
||||
})
|
||||
|
||||
Context("without data", func() {
|
||||
It("should match .XML", func() {
|
||||
Expect(xml.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
It("should match .JSON", func() {
|
||||
Expect(json.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with data", func() {
|
||||
BeforeEach(func() {
|
||||
child := make([]Child, 1)
|
||||
child[0] = Child{Id: "1", Title: "title", IsDir: false}
|
||||
response.SimilarSongs.Song = child
|
||||
})
|
||||
It("should match .XML", func() {
|
||||
Expect(xml.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
It("should match .JSON", func() {
|
||||
Expect(json.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("SimilarSongs2", func() {
|
||||
BeforeEach(func() {
|
||||
response.SimilarSongs2 = &SimilarSongs2{}
|
||||
})
|
||||
|
||||
Context("without data", func() {
|
||||
It("should match .XML", func() {
|
||||
Expect(xml.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
It("should match .JSON", func() {
|
||||
Expect(json.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
})
|
||||
|
||||
Context("with data", func() {
|
||||
BeforeEach(func() {
|
||||
child := make([]Child, 1)
|
||||
child[0] = Child{Id: "1", Title: "title", IsDir: false}
|
||||
response.SimilarSongs2.Song = child
|
||||
})
|
||||
It("should match .XML", func() {
|
||||
Expect(xml.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
It("should match .JSON", func() {
|
||||
Expect(json.Marshal(response)).To(MatchSnapshot())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Describe("PlayQueue", func() {
|
||||
BeforeEach(func() {
|
||||
response.PlayQueue = &PlayQueue{}
|
||||
|
||||
@@ -80,7 +80,7 @@ func (c *StreamController) Download(w http.ResponseWriter, r *http.Request) (*re
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entity, err := getEntityByID(ctx, c.ds, id)
|
||||
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user