Add dedicated SimilarArtists call

This commit is contained in:
Deluan
2020-10-20 13:38:44 -04:00
committed by Deluan Quintão
parent 29d8950e5b
commit e9e09a7480
22 changed files with 317 additions and 91 deletions
+2
View File
@@ -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
View File
@@ -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()
-21
View File
@@ -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
}
@@ -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}]}}
@@ -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>
@@ -0,0 +1 @@
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs":{}}
@@ -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>
@@ -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}]}}
@@ -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>
@@ -0,0 +1 @@
{"status":"ok","version":"1.8.0","type":"navidrome","serverVersion":"v0.0.0","similarSongs2":{}}
@@ -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>
+13 -3
View File
@@ -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{}
+1 -1
View File
@@ -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
}