mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-01 19:47:37 +03:00
fix(subsonic): fix albumCount in artists (#3827)
* only do subsonic instead * make sure to actually populate response first * navidrome artist filtering * address discord feedback * perPage min 36 * various artist artist_id -> albumartist_id * artist_id, role_id separate * remove all ui changes I guess * Revert role filters Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org> Co-authored-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
98808e4b6d
commit
ed1109ddb2
8 changed files with 78 additions and 28 deletions
|
@ -270,30 +270,43 @@ func (api *Router) GetGenres(r *http.Request) (*responses.Subsonic, error) {
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) {
|
||||
func (api *Router) getArtistInfo(r *http.Request) (*responses.ArtistInfoBase, *model.Artists, error) {
|
||||
ctx := r.Context()
|
||||
p := req.Params(r)
|
||||
id, err := p.String("id")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
count := p.IntOr("count", 20)
|
||||
includeNotPresent := p.BoolOr("includeNotPresent", false)
|
||||
|
||||
artist, err := api.externalMetadata.UpdateArtistInfo(ctx, id, count, includeNotPresent)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
base := responses.ArtistInfoBase{}
|
||||
base.Biography = artist.Biography
|
||||
base.SmallImageUrl = public.ImageURL(r, artist.CoverArtID(), 300)
|
||||
base.MediumImageUrl = public.ImageURL(r, artist.CoverArtID(), 600)
|
||||
base.LargeImageUrl = public.ImageURL(r, artist.CoverArtID(), 1200)
|
||||
base.LastFmUrl = artist.ExternalUrl
|
||||
base.MusicBrainzID = artist.MbzArtistID
|
||||
|
||||
return &base, &artist.SimilarArtists, nil
|
||||
}
|
||||
|
||||
func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) {
|
||||
base, similarArtists, err := api.getArtistInfo(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.ArtistInfo = &responses.ArtistInfo{}
|
||||
response.ArtistInfo.Biography = artist.Biography
|
||||
response.ArtistInfo.SmallImageUrl = public.ImageURL(r, artist.CoverArtID(), 300)
|
||||
response.ArtistInfo.MediumImageUrl = public.ImageURL(r, artist.CoverArtID(), 600)
|
||||
response.ArtistInfo.LargeImageUrl = public.ImageURL(r, artist.CoverArtID(), 1200)
|
||||
response.ArtistInfo.LastFmUrl = artist.ExternalUrl
|
||||
response.ArtistInfo.MusicBrainzID = artist.MbzArtistID
|
||||
for _, s := range artist.SimilarArtists {
|
||||
response.ArtistInfo.ArtistInfoBase = *base
|
||||
|
||||
for _, s := range *similarArtists {
|
||||
similar := toArtist(r, s)
|
||||
if s.ID == "" {
|
||||
similar.Id = "-1"
|
||||
|
@ -304,23 +317,20 @@ func (api *Router) GetArtistInfo(r *http.Request) (*responses.Subsonic, error) {
|
|||
}
|
||||
|
||||
func (api *Router) GetArtistInfo2(r *http.Request) (*responses.Subsonic, error) {
|
||||
info, err := api.GetArtistInfo(r)
|
||||
base, similarArtists, err := api.getArtistInfo(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := newResponse()
|
||||
response.ArtistInfo2 = &responses.ArtistInfo2{}
|
||||
response.ArtistInfo2.ArtistInfoBase = info.ArtistInfo.ArtistInfoBase
|
||||
for _, s := range info.ArtistInfo.SimilarArtist {
|
||||
similar := responses.ArtistID3{}
|
||||
similar.Id = s.Id
|
||||
similar.Name = s.Name
|
||||
similar.AlbumCount = s.AlbumCount
|
||||
similar.Starred = s.Starred
|
||||
similar.UserRating = s.UserRating
|
||||
similar.CoverArt = s.CoverArt
|
||||
similar.ArtistImageUrl = s.ArtistImageUrl
|
||||
response.ArtistInfo2.ArtistInfoBase = *base
|
||||
|
||||
for _, s := range *similarArtists {
|
||||
similar := toArtistID3(r, s)
|
||||
if s.ID == "" {
|
||||
similar.Id = "-1"
|
||||
}
|
||||
response.ArtistInfo2.SimilarArtist = append(response.ArtistInfo2.SimilarArtist, similar)
|
||||
}
|
||||
return response, nil
|
||||
|
|
|
@ -77,11 +77,26 @@ func sortName(sortName, orderName string) string {
|
|||
return orderName
|
||||
}
|
||||
|
||||
func getArtistAlbumCount(a model.Artist) int32 {
|
||||
albumStats := a.Stats[model.RoleAlbumArtist]
|
||||
|
||||
// If ArtistParticipations are set, then `getArtist` will return albums
|
||||
// where the artist is an album artist OR artist. While it may be an underestimate,
|
||||
// guess the count by taking a max of the album artist and artist count. This is
|
||||
// guaranteed to be <= the actual count.
|
||||
// Otherwise, return just the roles as album artist (precise)
|
||||
if conf.Server.Subsonic.ArtistParticipations {
|
||||
artistStats := a.Stats[model.RoleArtist]
|
||||
return int32(max(artistStats.AlbumCount, albumStats.AlbumCount))
|
||||
} else {
|
||||
return int32(albumStats.AlbumCount)
|
||||
}
|
||||
}
|
||||
|
||||
func toArtist(r *http.Request, a model.Artist) responses.Artist {
|
||||
artist := responses.Artist{
|
||||
Id: a.ID,
|
||||
Name: a.Name,
|
||||
AlbumCount: int32(a.AlbumCount),
|
||||
UserRating: int32(a.Rating),
|
||||
CoverArt: a.CoverArtID().String(),
|
||||
ArtistImageUrl: public.ImageURL(r, a.CoverArtID(), 600),
|
||||
|
@ -96,7 +111,7 @@ func toArtistID3(r *http.Request, a model.Artist) responses.ArtistID3 {
|
|||
artist := responses.ArtistID3{
|
||||
Id: a.ID,
|
||||
Name: a.Name,
|
||||
AlbumCount: int32(a.AlbumCount),
|
||||
AlbumCount: getArtistAlbumCount(a),
|
||||
CoverArt: a.CoverArtID().String(),
|
||||
ArtistImageUrl: public.ImageURL(r, a.CoverArtID(), 600),
|
||||
UserRating: int32(a.Rating),
|
||||
|
|
|
@ -10,6 +10,10 @@ import (
|
|||
)
|
||||
|
||||
var _ = Describe("helpers", func() {
|
||||
BeforeEach(func() {
|
||||
DeferCleanup(configtest.SetupConfig())
|
||||
})
|
||||
|
||||
Describe("fakePath", func() {
|
||||
var mf model.MediaFile
|
||||
BeforeEach(func() {
|
||||
|
@ -134,4 +138,29 @@ var _ = Describe("helpers", func() {
|
|||
Entry("returns \"explicit\" when the db value is \"e\"", "e", "explicit"),
|
||||
Entry("returns an empty string when the db value is \"\"", "", ""),
|
||||
Entry("returns an empty string when there are unexpected values on the db", "abc", ""))
|
||||
|
||||
Describe("getArtistAlbumCount", func() {
|
||||
artist := model.Artist{
|
||||
Stats: map[model.Role]model.ArtistStats{
|
||||
model.RoleAlbumArtist: {
|
||||
AlbumCount: 3,
|
||||
},
|
||||
model.RoleArtist: {
|
||||
AlbumCount: 4,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
It("Handles album count without artist participations", func() {
|
||||
conf.Server.Subsonic.ArtistParticipations = false
|
||||
result := getArtistAlbumCount(artist)
|
||||
Expect(result).To(Equal(int32(3)))
|
||||
})
|
||||
|
||||
It("Handles album count without with participations", func() {
|
||||
conf.Server.Subsonic.ArtistParticipations = true
|
||||
result := getArtistAlbumCount(artist)
|
||||
Expect(result).To(Equal(int32(4)))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
{
|
||||
"id": "111",
|
||||
"name": "aaa",
|
||||
"albumCount": 2,
|
||||
"starred": "2016-03-02T20:30:00Z",
|
||||
"userRating": 3,
|
||||
"artistImageUrl": "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<subsonic-response xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0" type="navidrome" serverVersion="v0.0.0" openSubsonic="true">
|
||||
<indexes lastModified="1" ignoredArticles="A">
|
||||
<index name="A">
|
||||
<artist id="111" name="aaa" albumCount="2" starred="2016-03-02T20:30:00Z" userRating="3" artistImageUrl="https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png"></artist>
|
||||
<artist id="111" name="aaa" starred="2016-03-02T20:30:00Z" userRating="3" artistImageUrl="https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png"></artist>
|
||||
</index>
|
||||
</indexes>
|
||||
</subsonic-response>
|
||||
|
|
|
@ -92,7 +92,6 @@ type MusicFolders struct {
|
|||
type Artist struct {
|
||||
Id string `xml:"id,attr" json:"id"`
|
||||
Name string `xml:"name,attr" json:"name"`
|
||||
AlbumCount int32 `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"`
|
||||
Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"`
|
||||
UserRating int32 `xml:"userRating,attr,omitempty" json:"userRating,omitempty"`
|
||||
CoverArt string `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
|
||||
|
@ -233,7 +232,7 @@ type ArtistID3 struct {
|
|||
Id string `xml:"id,attr" json:"id"`
|
||||
Name string `xml:"name,attr" json:"name"`
|
||||
CoverArt string `xml:"coverArt,attr,omitempty" json:"coverArt,omitempty"`
|
||||
AlbumCount int32 `xml:"albumCount,attr,omitempty" json:"albumCount,omitempty"`
|
||||
AlbumCount int32 `xml:"albumCount,attr" json:"albumCount"`
|
||||
Starred *time.Time `xml:"starred,attr,omitempty" json:"starred,omitempty"`
|
||||
UserRating int32 `xml:"userRating,attr,omitempty" json:"userRating,omitempty"`
|
||||
ArtistImageUrl string `xml:"artistImageUrl,attr,omitempty" json:"artistImageUrl,omitempty"`
|
||||
|
|
|
@ -103,7 +103,6 @@ var _ = Describe("Responses", func() {
|
|||
Name: "aaa",
|
||||
Starred: &t,
|
||||
UserRating: 3,
|
||||
AlbumCount: 2,
|
||||
ArtistImageUrl: "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png",
|
||||
}
|
||||
index := make([]Index, 1)
|
||||
|
|
|
@ -94,7 +94,6 @@ func (api *Router) Search2(r *http.Request) (*responses.Subsonic, error) {
|
|||
a := responses.Artist{
|
||||
Id: artist.ID,
|
||||
Name: artist.Name,
|
||||
AlbumCount: int32(artist.AlbumCount),
|
||||
UserRating: int32(artist.Rating),
|
||||
CoverArt: artist.CoverArtID().String(),
|
||||
ArtistImageUrl: public.ImageURL(r, artist.CoverArtID(), 600),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue