Get Similar Artists in parallel

Also don't fail `GetArtistInfo` when Last.FM is not configured
This commit is contained in:
Deluan 2020-10-21 21:43:01 -04:00
parent ed84c5a0a3
commit 1cd2f015c2
3 changed files with 25 additions and 26 deletions

View File

@ -22,8 +22,7 @@ const placeholderArtistImageMediumUrl = "https://lastfm.freetls.fastly.net/i/u/1
const placeholderArtistImageLargeUrl = "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png" const placeholderArtistImageLargeUrl = "https://lastfm.freetls.fastly.net/i/u/300x300/2a96cbd8b46e442fc41c2b86b821562f.png"
type ExternalInfo interface { type ExternalInfo interface {
ArtistInfo(ctx context.Context, id string) (*model.ArtistInfo, error) ArtistInfo(ctx context.Context, id string, count int, includeNotPresent bool) (*model.ArtistInfo, error)
SimilarArtists(ctx context.Context, id string, includeNotPresent bool, count int) (model.Artists, error)
SimilarSongs(ctx context.Context, id string, count int) (model.MediaFiles, error) SimilarSongs(ctx context.Context, id string, count int) (model.MediaFiles, error)
TopSongs(ctx context.Context, artist string, count int) (model.MediaFiles, error) TopSongs(ctx context.Context, artist string, count int) (model.MediaFiles, error)
} }
@ -92,20 +91,6 @@ func (e *externalInfo) SimilarSongs(ctx context.Context, id string, count int) (
}) })
} }
func (e *externalInfo) SimilarArtists(ctx context.Context, id string, includeNotPresent bool, count int) (model.Artists, error) {
if e.lfm == nil {
log.Warn(ctx, "Last.FM client not configured")
return nil, model.ErrNotAvailable
}
artist, err := e.getArtist(ctx, id)
if err != nil {
return nil, err
}
return e.similarArtists(ctx, artist, count, includeNotPresent)
}
func (e *externalInfo) similarArtists(ctx context.Context, artist *model.Artist, count int, includeNotPresent bool) (model.Artists, error) { func (e *externalInfo) similarArtists(ctx context.Context, artist *model.Artist, count int, includeNotPresent bool) (model.Artists, error) {
var result model.Artists var result model.Artists
var notPresent []string var notPresent []string
@ -189,7 +174,7 @@ func (e *externalInfo) findMatchingTrack(ctx context.Context, mbid string, artis
return &mfs[0], nil return &mfs[0], nil
} }
func (e *externalInfo) ArtistInfo(ctx context.Context, id string) (*model.ArtistInfo, error) { func (e *externalInfo) ArtistInfo(ctx context.Context, id string, count int, includeNotPresent bool) (*model.ArtistInfo, error) {
artist, err := e.getArtist(ctx, id) artist, err := e.getArtist(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
@ -202,6 +187,7 @@ func (e *externalInfo) ArtistInfo(ctx context.Context, id string) (*model.Artist
var wg sync.WaitGroup var wg sync.WaitGroup
e.callArtistInfo(ctx, artist, &wg, &info) e.callArtistInfo(ctx, artist, &wg, &info)
e.callArtistImages(ctx, artist, &wg, &info) e.callArtistImages(ctx, artist, &wg, &info)
e.callSimilarArtists(ctx, artist, count, includeNotPresent, &wg, &info)
wg.Wait() wg.Wait()
// Use placeholders if could not get from external sources // Use placeholders if could not get from external sources
@ -215,8 +201,7 @@ func (e *externalInfo) ArtistInfo(ctx context.Context, id string) (*model.Artist
return &info, nil return &info, nil
} }
func (e *externalInfo) callArtistInfo(ctx context.Context, artist *model.Artist, func (e *externalInfo) callArtistInfo(ctx context.Context, artist *model.Artist, wg *sync.WaitGroup, info *model.ArtistInfo) {
wg *sync.WaitGroup, info *model.ArtistInfo) {
if e.lfm != nil { if e.lfm != nil {
log.Debug(ctx, "Calling Last.FM ArtistGetInfo", "artist", artist.Name) log.Debug(ctx, "Calling Last.FM ArtistGetInfo", "artist", artist.Name)
wg.Add(1) wg.Add(1)
@ -257,6 +242,24 @@ func (e *externalInfo) findArtist(ctx context.Context, name string) (*spotify.Ar
return &artists[0], err return &artists[0], err
} }
func (e *externalInfo) callSimilarArtists(ctx context.Context, artist *model.Artist, count int, includeNotPresent bool,
wg *sync.WaitGroup, info *model.ArtistInfo) {
if e.lfm != nil {
wg.Add(1)
go func() {
start := time.Now()
defer wg.Done()
similar, err := e.similarArtists(ctx, artist, count, includeNotPresent)
if err != nil {
log.Error(ctx, "Error calling Last.FM", "artist", artist.Name, err)
return
}
log.Debug(ctx, "Got similar artists from Last.FM", "artist", artist.Name, "info", "elapsed", time.Since(start))
info.SimilarArtists = similar
}()
}
}
func (e *externalInfo) callArtistImages(ctx context.Context, artist *model.Artist, wg *sync.WaitGroup, info *model.ArtistInfo) { func (e *externalInfo) callArtistImages(ctx context.Context, artist *model.Artist, wg *sync.WaitGroup, info *model.ArtistInfo) {
if e.spf != nil { if e.spf != nil {
log.Debug(ctx, "Calling Spotify SearchArtist", "artist", artist.Name) log.Debug(ctx, "Calling Spotify SearchArtist", "artist", artist.Name)

View File

@ -9,4 +9,5 @@ type ArtistInfo struct {
MediumImageUrl string MediumImageUrl string
LargeImageUrl string LargeImageUrl string
LastFMUrl string LastFMUrl string
SimilarArtists Artists
} }

View File

@ -241,12 +241,7 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
count := utils.ParamInt(r, "count", 20) count := utils.ParamInt(r, "count", 20)
includeNotPresent := utils.ParamBool(r, "includeNotPresent", false) includeNotPresent := utils.ParamBool(r, "includeNotPresent", false)
info, err := c.ei.ArtistInfo(ctx, id) info, err := c.ei.ArtistInfo(ctx, id, count, includeNotPresent)
if err != nil {
return nil, err
}
similar, err := c.ei.SimilarArtists(ctx, id, includeNotPresent, count)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -259,7 +254,7 @@ func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Reques
response.ArtistInfo.LargeImageUrl = info.LargeImageUrl response.ArtistInfo.LargeImageUrl = info.LargeImageUrl
response.ArtistInfo.LastFmUrl = info.LastFMUrl response.ArtistInfo.LastFmUrl = info.LastFMUrl
response.ArtistInfo.MusicBrainzID = info.MBID response.ArtistInfo.MusicBrainzID = info.MBID
for _, s := range similar { for _, s := range info.SimilarArtists {
similar := responses.Artist{} similar := responses.Artist{}
similar.Id = s.ID similar.Id = s.ID
similar.Name = s.Name similar.Name = s.Name