feat: top releases sorted by popularity with library-style album cards
Replaced the date-sorted release group approach with a dedicated TopReleaseGroupsForArtist LB API call that returns releases ranked by total listen count (popularity). Added LBTopReleaseGroup type and Wails bindings. Restyled the top-releases cards to match the library album view: square cover art on top with title and type below, centered text, auto-filling the available width with even spacing.
This commit is contained in:
@@ -184,6 +184,11 @@ func (e *Service) TopRecordingsForArtist(artistMBID string) ([]LBTopRecording, e
|
||||
return e.lb.TopRecordingsForArtist(e.ctx, artistMBID)
|
||||
}
|
||||
|
||||
// TopReleaseGroupsForArtist returns the most-listened release groups for an artist.
|
||||
func (e *Service) TopReleaseGroupsForArtist(artistMBID string) ([]LBTopReleaseGroup, error) {
|
||||
return e.lb.TopReleaseGroupsForArtist(e.ctx, artistMBID)
|
||||
}
|
||||
|
||||
// SimilarArtists returns artists similar to the given artist MBID.
|
||||
func (e *Service) SimilarArtists(artistMBID string) ([]LBSimilarArtist, error) {
|
||||
return e.lb.SimilarArtists(e.ctx, artistMBID)
|
||||
|
||||
@@ -97,6 +97,52 @@ func (c *ListenBrainzClient) TopRecordingsForArtist(
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TopReleaseGroupsForArtist returns the most-listened release groups
|
||||
// for the artist identified by artistMBID.
|
||||
func (c *ListenBrainzClient) TopReleaseGroupsForArtist(
|
||||
ctx context.Context, artistMBID string,
|
||||
) ([]LBTopReleaseGroup, error) {
|
||||
url := fmt.Sprintf(
|
||||
"%s/1/popularity/top-release-groups-for-artist/%s",
|
||||
listenBrainzBaseURL,
|
||||
artistMBID,
|
||||
)
|
||||
cacheKey := "lb:top-release-groups:" + artistMBID
|
||||
|
||||
if data, ok := c.cache.Get(cacheKey); ok {
|
||||
var out []LBTopReleaseGroup
|
||||
if err := json.Unmarshal(data, &out); err == nil {
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
|
||||
body, err := c.doGet(ctx, url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("listenbrainz top release groups: %w", err)
|
||||
}
|
||||
|
||||
var wire []lbTopReleaseGroupWire
|
||||
if err := json.Unmarshal(body, &wire); err != nil {
|
||||
return nil, fmt.Errorf("listenbrainz top release groups unmarshal: %w", err)
|
||||
}
|
||||
|
||||
const maxTopReleaseGroups = 10
|
||||
|
||||
limit := len(wire)
|
||||
if limit > maxTopReleaseGroups {
|
||||
limit = maxTopReleaseGroups
|
||||
}
|
||||
|
||||
out := make([]LBTopReleaseGroup, limit)
|
||||
for i := range limit {
|
||||
out[i] = wire[i].toPublic()
|
||||
}
|
||||
|
||||
c.cacheJSON(cacheKey, out, cacheTTLSearch, artistMBID, "artist")
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// SimilarArtists returns artists similar to the one identified by
|
||||
// artistMBID, using the ListenBrainz labs API. Returns nil, nil
|
||||
// if the endpoint is unavailable (labs API may be unstable).
|
||||
|
||||
@@ -106,3 +106,45 @@ type LBSimilarArtist struct {
|
||||
Name string `json:"name"`
|
||||
Score float64 `json:"score"`
|
||||
}
|
||||
|
||||
// LBTopReleaseGroup represents a popular release group from the
|
||||
// ListenBrainz popularity API.
|
||||
type LBTopReleaseGroup struct {
|
||||
ReleaseGroupMBID string `json:"releaseGroupMbid"`
|
||||
Title string `json:"title"`
|
||||
ArtistName string `json:"artistName"`
|
||||
Type string `json:"type"`
|
||||
TotalListenCount int `json:"totalListenCount"`
|
||||
}
|
||||
|
||||
// lbTopReleaseGroupWire matches the ListenBrainz API's snake_case
|
||||
// JSON response for the popularity/top-release-groups-for-artist
|
||||
// endpoint.
|
||||
type lbTopReleaseGroupWire struct {
|
||||
ReleaseGroupMBID string `json:"release_group_mbid"`
|
||||
TotalListenCount int `json:"total_listen_count"`
|
||||
ReleaseGroup struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
} `json:"release_group"`
|
||||
Artist struct {
|
||||
Artists []struct {
|
||||
Name string `json:"name"`
|
||||
} `json:"artists"`
|
||||
} `json:"artist"`
|
||||
}
|
||||
|
||||
func (w lbTopReleaseGroupWire) toPublic() LBTopReleaseGroup {
|
||||
artistName := ""
|
||||
if len(w.Artist.Artists) > 0 {
|
||||
artistName = w.Artist.Artists[0].Name
|
||||
}
|
||||
|
||||
return LBTopReleaseGroup{
|
||||
ReleaseGroupMBID: w.ReleaseGroupMBID,
|
||||
Title: w.ReleaseGroup.Name,
|
||||
ArtistName: artistName,
|
||||
Type: w.ReleaseGroup.Type,
|
||||
TotalListenCount: w.TotalListenCount,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user