This commit is contained in:
shiokoala 2024-04-25 22:44:20 -04:00 committed by GitHub
commit 83ffaea4e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 43 additions and 18 deletions

View File

@ -145,7 +145,7 @@ func (a *Agents) GetSimilarArtists(ctx context.Context, id, name, mbid string, l
return nil, ErrNotFound
}
func (a *Agents) GetArtistImages(ctx context.Context, id, name, mbid string) ([]ExternalImage, error) {
func (a *Agents) GetArtistImages(ctx context.Context, id, name, sortName, mbid string) ([]ExternalImage, error) {
switch id {
case consts.UnknownArtistID:
return nil, ErrNotFound
@ -161,7 +161,7 @@ func (a *Agents) GetArtistImages(ctx context.Context, id, name, mbid string) ([]
if !ok {
continue
}
images, err := agent.GetArtistImages(ctx, id, name, mbid)
images, err := agent.GetArtistImages(ctx, id, name, sortName, mbid)
if len(images) > 0 && err == nil {
log.Debug(ctx, "Got Images", "agent", ag.AgentName(), "artist", name, "images", images, "elapsed", time.Since(start))
return images, nil

View File

@ -152,21 +152,21 @@ var _ = Describe("Agents", func() {
Describe("GetArtistImages", func() {
It("returns on first match", func() {
Expect(ag.GetArtistImages(ctx, "123", "test", "mb123")).To(Equal([]ExternalImage{{
Expect(ag.GetArtistImages(ctx, "123", "test", "test", "mb123")).To(Equal([]ExternalImage{{
URL: "imageUrl",
Size: 100,
}}))
Expect(mock.Args).To(ConsistOf("123", "test", "mb123"))
Expect(mock.Args).To(ConsistOf("123", "test", "test", "mb123"))
})
It("skips the agent if it returns an error", func() {
mock.Err = errors.New("error")
_, err := ag.GetArtistImages(ctx, "123", "test", "mb123")
_, err := ag.GetArtistImages(ctx, "123", "test", "test", "mb123")
Expect(err).To(MatchError("not found"))
Expect(mock.Args).To(ConsistOf("123", "test", "mb123"))
Expect(mock.Args).To(ConsistOf("123", "test", "test", "mb123"))
})
It("interrupts if the context is canceled", func() {
cancel()
_, err := ag.GetArtistImages(ctx, "123", "test", "mb123")
_, err := ag.GetArtistImages(ctx, "123", "test", "test", "mb123")
Expect(err).To(MatchError(ErrNotFound))
Expect(mock.Args).To(BeEmpty())
})
@ -287,8 +287,8 @@ func (a *mockAgent) GetArtistBiography(_ context.Context, id, name, mbid string)
return "bio", nil
}
func (a *mockAgent) GetArtistImages(_ context.Context, id, name, mbid string) ([]ExternalImage, error) {
a.Args = []interface{}{id, name, mbid}
func (a *mockAgent) GetArtistImages(_ context.Context, id, name, sortName, mbid string) ([]ExternalImage, error) {
a.Args = []interface{}{id, name, sortName, mbid}
if a.Err != nil {
return nil, a.Err
}

View File

@ -62,7 +62,7 @@ type ArtistSimilarRetriever interface {
}
type ArtistImageRetriever interface {
GetArtistImages(ctx context.Context, id, name, mbid string) ([]ExternalImage, error)
GetArtistImages(ctx context.Context, id, name, sortName, mbid string) ([]ExternalImage, error)
}
type ArtistTopSongsRetriever interface {

View File

@ -44,8 +44,8 @@ func (s *spotifyAgent) AgentName() string {
return spotifyAgentName
}
func (s *spotifyAgent) GetArtistImages(ctx context.Context, id, name, mbid string) ([]agents.ExternalImage, error) {
a, err := s.searchArtist(ctx, name)
func (s *spotifyAgent) GetArtistImages(ctx context.Context, id, name, sortName, mbid string) ([]agents.ExternalImage, error) {
a, err := s.searchArtist(ctx, name, sortName)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
log.Warn(ctx, "Artist not found in Spotify", "artist", name)
@ -65,7 +65,7 @@ func (s *spotifyAgent) GetArtistImages(ctx context.Context, id, name, mbid strin
return res, nil
}
func (s *spotifyAgent) searchArtist(ctx context.Context, name string) (*Artist, error) {
func (s *spotifyAgent) searchArtist(ctx context.Context, name string, sortName string) (*Artist, error) {
artists, err := s.client.searchArtists(ctx, name, 40)
if err != nil || len(artists) == 0 {
return nil, model.ErrNotFound
@ -79,11 +79,36 @@ func (s *spotifyAgent) searchArtist(ctx context.Context, name string) (*Artist,
return ai < aj
})
// If the first one has the same name, that's the one
if strings.ToLower(artists[0].Name) != name {
return nil, model.ErrNotFound
// If the first result sorted by name matches the name, return that artist (should cover most use cases with English names)
if strings.ToLower(artists[0].Name) == name {
return &artists[0], err
}
return &artists[0], err
// If matching by name doesn't work(non-Latin alphabet names), match by sortName
sortName = strings.ToLower(sortName)
sort.Slice(artists, func(i, j int) bool {
ai := fmt.Sprintf("%-5t-%03d-%04d", len(artists[i].Images) == 0, customMetric(strings.ToLower(artists[i].Name), sortName), 1000-artists[i].Popularity)
aj := fmt.Sprintf("%-5t-%03d-%04d", len(artists[j].Images) == 0, customMetric(strings.ToLower(artists[j].Name), sortName), 1000-artists[j].Popularity)
return ai < aj
})
// If the first one has a similar name to sortName, that is the one
if customMetric(strings.ToLower(artists[0].Name), sortName) < 1 {
return &artists[0], err
}
return nil, model.ErrNotFound
}
func customMetric(name string, sortName string) int {
// Because sortNames often have commas and have different word orders(e.g. "John Williams" -> "Williams, John", "The Beatles"->"Beatles, The"),
// this custom metric returns the number of letters that are different from "name" and "sortName" but irrespective of the word order
name = strings.ReplaceAll(name, " ", "")
sortName = strings.ReplaceAll(sortName, " ", "")
substrings := strings.Split(sortName, ",")
for _, ss := range substrings {
name = strings.Replace(name, ss, "", 1)
}
return len(name)
}
func init() {

View File

@ -444,7 +444,7 @@ func (e *externalMetadata) callGetBiography(ctx context.Context, agent agents.Ar
}
func (e *externalMetadata) callGetImage(ctx context.Context, agent agents.ArtistImageRetriever, artist *auxArtist) {
images, err := agent.GetArtistImages(ctx, artist.ID, artist.Name, artist.MbzArtistID)
images, err := agent.GetArtistImages(ctx, artist.ID, artist.Name, artist.SortArtistName, artist.MbzArtistID)
if err != nil {
return
}