mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-12 12:27:09 +02:00
feat(subsonic): Implement OpenSubsonic topSongsByArtistId extension (#5853)
* implement topSongsByArtistId extension * do not look up by artist name if empty --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
This commit is contained in:
parent
810b14ed57
commit
b40b41584a
8 changed files with 143 additions and 59 deletions
|
|
@ -381,13 +381,14 @@ func (api *Router) GetSimilarSongs2(r *http.Request) (*responses.Subsonic, error
|
|||
func (api *Router) GetTopSongs(r *http.Request) (*responses.Subsonic, error) {
|
||||
ctx := r.Context()
|
||||
p := req.Params(r)
|
||||
id, idErr := p.String("id")
|
||||
artist, err := p.String("artist")
|
||||
if err != nil {
|
||||
if err != nil && idErr != nil {
|
||||
return nil, err
|
||||
}
|
||||
count := p.IntOr("count", 50)
|
||||
|
||||
songs, err := api.provider.TopSongs(ctx, artist, count)
|
||||
songs, err := api.provider.TopSongs(ctx, artist, id, count)
|
||||
if err != nil && !errors.Is(err, model.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ func (n noopProvider) SimilarSongs(context.Context, string, int) (model.MediaFil
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func (n noopProvider) TopSongs(context.Context, string, int) (model.MediaFiles, error) {
|
||||
func (n noopProvider) TopSongs(context.Context, string, string, int) (model.MediaFiles, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,15 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
setupTestDB()
|
||||
})
|
||||
|
||||
getBeatlesId := func() string {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
return artists[0].ID
|
||||
}
|
||||
|
||||
Describe("getMusicFolders", func() {
|
||||
It("returns the configured music library", func() {
|
||||
resp := doReq("getMusicFolders")
|
||||
|
|
@ -85,12 +94,7 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
|
||||
Describe("getMusicDirectory", func() {
|
||||
It("returns an artist directory with its albums as children", func() {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
beatlesID := artists[0].ID
|
||||
beatlesID := getBeatlesId()
|
||||
|
||||
resp := doReq("getMusicDirectory", "id", beatlesID)
|
||||
|
||||
|
|
@ -125,12 +129,7 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
|
||||
Describe("getArtist", func() {
|
||||
It("returns artist with albums in ID3 format", func() {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
beatlesID := artists[0].ID
|
||||
beatlesID := getBeatlesId()
|
||||
|
||||
resp := doReq("getArtist", "id", beatlesID)
|
||||
|
||||
|
|
@ -141,12 +140,7 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
})
|
||||
|
||||
It("returns album names for the artist", func() {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
beatlesID := artists[0].ID
|
||||
beatlesID := getBeatlesId()
|
||||
|
||||
resp := doReq("getArtist", "id", beatlesID)
|
||||
|
||||
|
|
@ -381,13 +375,7 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
|
||||
Describe("getArtistInfo", func() {
|
||||
It("returns artist info for a valid artist", func() {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
beatlesID := artists[0].ID
|
||||
|
||||
beatlesID := getBeatlesId()
|
||||
resp := doReq("getArtistInfo", "id", beatlesID)
|
||||
|
||||
Expect(resp.Status).To(Equal(responses.StatusOK))
|
||||
|
|
@ -397,13 +385,7 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
|
||||
Describe("getArtistInfo2", func() {
|
||||
It("returns artist info2 for a valid artist", func() {
|
||||
artists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "The Beatles"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(artists).ToNot(BeEmpty())
|
||||
beatlesID := artists[0].ID
|
||||
|
||||
beatlesID := getBeatlesId()
|
||||
resp := doReq("getArtistInfo2", "id", beatlesID)
|
||||
|
||||
Expect(resp.Status).To(Equal(responses.StatusOK))
|
||||
|
|
@ -426,6 +408,28 @@ var _ = Describe("Browsing Endpoints", func() {
|
|||
Expect(resp.TopSongs).ToNot(BeNil())
|
||||
Expect(resp.TopSongs.Song).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("returns an error if no arguments are specified", func() {
|
||||
resp := doReq("getTopSongs")
|
||||
Expect(resp.Status).To(Equal(responses.StatusFailed))
|
||||
Expect(resp.TopSongs).To(BeNil())
|
||||
})
|
||||
|
||||
It("returns a response only by id", func() {
|
||||
beatlesID := getBeatlesId()
|
||||
resp := doReq("getTopSongs", "id", beatlesID)
|
||||
|
||||
Expect(resp.Status).To(Equal(responses.StatusOK))
|
||||
Expect(resp.TopSongs).ToNot(BeNil())
|
||||
})
|
||||
|
||||
It("returns a response when both id and name are included", func() {
|
||||
beatlesID := getBeatlesId()
|
||||
resp := doReq("getTopSongs", "id", beatlesID, "artist", "The Beatles")
|
||||
|
||||
Expect(resp.Status).To(Equal(responses.StatusOK))
|
||||
Expect(resp.TopSongs).ToNot(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("getSimilarSongs", func() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ func (api *Router) GetOpenSubsonicExtensions(_ *http.Request) (*responses.Subson
|
|||
{Name: "indexBasedQueue", Versions: []int32{1}},
|
||||
{Name: "transcoding", Versions: []int32{1}},
|
||||
{Name: "playbackReport", Versions: []int32{1}},
|
||||
{Name: "topSongsByArtistId", Versions: []int32{1}},
|
||||
}
|
||||
if api.sonic != nil && api.sonic.HasProvider() {
|
||||
extensions = append(extensions, responses.OpenSubsonicExtension{
|
||||
|
|
|
|||
|
|
@ -55,13 +55,14 @@ var _ = Describe("GetOpenSubsonicExtensions", func() {
|
|||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(*response.Subsonic.OpenSubsonicExtensions).To(SatisfyAll(
|
||||
HaveLen(6),
|
||||
HaveLen(7),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "transcodeOffset", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "formPost", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "songLyrics", Versions: []int32{1, 2}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "indexBasedQueue", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "transcoding", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "playbackReport", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "topSongsByArtistId", Versions: []int32{1}}),
|
||||
))
|
||||
Expect(*response.Subsonic.OpenSubsonicExtensions).NotTo(
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "sonicSimilarity", Versions: []int32{1}}),
|
||||
|
|
@ -85,7 +86,7 @@ var _ = Describe("GetOpenSubsonicExtensions", func() {
|
|||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(*response.Subsonic.OpenSubsonicExtensions).To(SatisfyAll(
|
||||
HaveLen(7),
|
||||
HaveLen(8),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "transcodeOffset", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "formPost", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "songLyrics", Versions: []int32{1, 2}}),
|
||||
|
|
@ -93,6 +94,7 @@ var _ = Describe("GetOpenSubsonicExtensions", func() {
|
|||
ContainElement(responses.OpenSubsonicExtension{Name: "transcoding", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "playbackReport", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "sonicSimilarity", Versions: []int32{1}}),
|
||||
ContainElement(responses.OpenSubsonicExtension{Name: "topSongsByArtistId", Versions: []int32{1}}),
|
||||
))
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue