diff --git a/core/agents/agents.go b/core/agents/agents.go index 0a11297c..bb6a8c9b 100644 --- a/core/agents/agents.go +++ b/core/agents/agents.go @@ -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 diff --git a/core/agents/agents_test.go b/core/agents/agents_test.go index 33687048..ffa3b181 100644 --- a/core/agents/agents_test.go +++ b/core/agents/agents_test.go @@ -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 } diff --git a/core/agents/interfaces.go b/core/agents/interfaces.go index 00f75627..9adbc168 100644 --- a/core/agents/interfaces.go +++ b/core/agents/interfaces.go @@ -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 { diff --git a/core/agents/spotify/spotify.go b/core/agents/spotify/spotify.go index b0b3f39b..dd29e0b0 100644 --- a/core/agents/spotify/spotify.go +++ b/core/agents/spotify/spotify.go @@ -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() { diff --git a/core/external_metadata.go b/core/external_metadata.go index 33206bde..91487ddc 100644 --- a/core/external_metadata.go +++ b/core/external_metadata.go @@ -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 }