Skip to content

Commit

Permalink
Fix buggy Last.FM by falling back to artist search
Browse files Browse the repository at this point in the history
  • Loading branch information
dewey committed Oct 24, 2024
1 parent 9ff97e8 commit 8e0360e
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
14 changes: 12 additions & 2 deletions api/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package api

import (
"errors"
"fmt"
"time"

"github.com/go-kit/kit/log"
Expand Down Expand Up @@ -138,22 +139,31 @@ func (s *service) GenerateTaste(username string, period string, limit int) ([]la
if err != nil {
// If we don't have it in our store we get the unique top tag for the first 4 artists
start = time.Now()
tt, err := s.client.GetTopTags(ta.Mbid)

// We try to get the top tags by mbid, but if this doesn't work because of the Last.FM bug we fallback to the artist name:
// https://www.reddit.com/r/lastfm/comments/1g9suo3/api_problem/
tt, err := s.client.GetTopTags(ta.Mbid, ta.Name)
fetchDurationHistogram.WithLabelValues(period, "get_top_tags").Observe(time.Since(start).Seconds())
cacheMissTotalCounter.Add(1)
if err != nil {
s.l.Log("err", err)
continue
}
// If we don't get any top tags, we just append the artist without tags
if len(tt) > 1 {
ta.Genre = tt[0]
if _, ok := m[ta.Genre]; !ok {
al = append(al, ta)
m[ta.Genre] = struct{}{}
}
// We store the newly fetched information in our storage backend so we don't have to fetch it again for the next user
s.storageRepository.Save(ta.Mbid, tt[0])
if err := s.storageRepository.Save(ta.Mbid, tt[0]); err != nil {
s.l.Log("msg", fmt.Sprintf("failed to save artist key: %s,", err), "backend", s.cfg.StorageBackend)
}
} else {
al = append(al, ta)
}

continue
}
cacheHitTotalCounter.Add(1)
Expand Down
30 changes: 26 additions & 4 deletions client/lastfm/lastfm.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
)

// Client contains everything needed for a Last.FM client
Expand Down Expand Up @@ -76,7 +77,8 @@ type TopArtist struct {

// GetTopArtists gets the top artist of a user from Last.FM
func (c *Client) GetTopArtists(username string, period string, limit int) ([]TopArtist, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=%s&api_key=%s&format=json&period=%s&limit=%d", username, c.APIKey, period, limit), nil)
call := fmt.Sprintf("http://ws.audioscrobbler.com/2.0/?method=user.gettopartists&user=%s&api_key=%s&format=json&period=%s&limit=%d", username, c.APIKey, period, limit)
req, err := http.NewRequest("GET", call, nil)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -146,9 +148,29 @@ func (c *Client) GetWeeklyArtistChart(username string, from, to int64, limit int
return tal, nil
}

// GetTopTags gets the top tags for an artist from the Last.FM API
func (c *Client) GetTopTags(mbid string) ([]string, error) {
req, err := http.NewRequest("GET", fmt.Sprintf("http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags&mbid=%s&api_key=%s&format=json", mbid, c.APIKey), nil)
// GetTopTags gets the top tags for an artist from the Last.FM API by mbid, or artist as a fallback
func (c *Client) GetTopTags(mbid string, artist string) ([]string, error) {
if mbid == "" {
return c.getTopTags("artist", artist)
}
return c.getTopTags("mbid", mbid)
}

func (c *Client) getTopTags(by string, value string) ([]string, error) {
call := fmt.Sprintf("http://ws.audioscrobbler.com/2.0/?method=artist.gettoptags&api_key=%s&format=json", c.APIKey)
u, err := url.Parse(call)
if err != nil {
return nil, err
}
q := u.Query()
switch by {
case "mbid":
q.Add("mbid", value)
default:
q.Add("artist", value)
}
u.RawQuery = q.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 8e0360e

Please sign in to comment.