Improve Genius artist search for manual matching (#233)
The manual match modal for Genius only returned 0 or 1 artist result because search_artist() searched songs (per_page=5), extracted the primary artist, and returned the first match or None. Added search_artists() that returns multiple unique artists extracted from song results with broader search (per_page=20). The manual match endpoint now shows up to 8 artist candidates and multiple track results instead of one-or-nothing. Also shows the Genius URL as extra info.
This commit is contained in:
parent
982ca77501
commit
778e68a844
2 changed files with 47 additions and 17 deletions
|
|
@ -212,24 +212,47 @@ class GeniusClient:
|
||||||
Returns:
|
Returns:
|
||||||
Artist dict with: id, name, url, image_url
|
Artist dict with: id, name, url, image_url
|
||||||
"""
|
"""
|
||||||
hits = self.search(artist_name, per_page=5)
|
artists = self.search_artists(artist_name, limit=10)
|
||||||
if not hits:
|
if not artists:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
artist_lower = artist_name.lower().strip()
|
artist_lower = artist_name.lower().strip()
|
||||||
|
|
||||||
for hit in hits:
|
for a in artists:
|
||||||
result = hit.get('result', {})
|
a_name = (a.get('name') or '').lower()
|
||||||
primary = result.get('primary_artist', {})
|
if artist_lower in a_name or a_name in artist_lower:
|
||||||
primary_name = (primary.get('name') or '').lower()
|
logger.debug(f"Found artist: {a.get('name')}")
|
||||||
if primary and (artist_lower in primary_name or primary_name in artist_lower):
|
return a
|
||||||
logger.debug(f"Found artist: {primary.get('name')}")
|
|
||||||
return primary
|
|
||||||
|
|
||||||
# No confident match — let the worker mark as not_found and retry later
|
# No confident match — let the worker mark as not_found and retry later
|
||||||
logger.debug(f"No artist match found in search results for: {artist_name}")
|
logger.debug(f"No artist match found in search results for: {artist_name}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@rate_limited
|
||||||
|
def search_artists(self, query: str, limit: int = 10) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
Search for artists by name. Extracts unique artists from song results.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of artist dicts with: id, name, url, image_url
|
||||||
|
"""
|
||||||
|
hits = self.search(query, per_page=min(limit * 2, 20))
|
||||||
|
if not hits:
|
||||||
|
return []
|
||||||
|
|
||||||
|
seen_ids = set()
|
||||||
|
artists = []
|
||||||
|
for hit in hits:
|
||||||
|
result = hit.get('result', {})
|
||||||
|
primary = result.get('primary_artist', {})
|
||||||
|
if primary and primary.get('id') and primary['id'] not in seen_ids:
|
||||||
|
seen_ids.add(primary['id'])
|
||||||
|
artists.append(primary)
|
||||||
|
if len(artists) >= limit:
|
||||||
|
break
|
||||||
|
|
||||||
|
return artists
|
||||||
|
|
||||||
@rate_limited
|
@rate_limited
|
||||||
def get_artist(self, artist_id: int) -> Optional[Dict[str, Any]]:
|
def get_artist(self, artist_id: int) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -12614,15 +12614,22 @@ def _search_service(service, entity_type, query):
|
||||||
raise ValueError("Genius worker not initialized")
|
raise ValueError("Genius worker not initialized")
|
||||||
client = genius_worker.client
|
client = genius_worker.client
|
||||||
if entity_type == 'artist':
|
if entity_type == 'artist':
|
||||||
result = client.search_artist(query)
|
artists = client.search_artists(query, limit=8)
|
||||||
if result:
|
return [{'id': str(a.get('id', '')), 'name': a.get('name', ''),
|
||||||
return [{'id': str(result.get('id', '')), 'name': result.get('name', ''),
|
'image': a.get('image_url'), 'extra': a.get('url', '')} for a in artists]
|
||||||
'image': result.get('image_url'), 'extra': ''}]
|
|
||||||
elif entity_type == 'track':
|
elif entity_type == 'track':
|
||||||
result = client.search_song(query, '')
|
# Search with broader results for manual matching
|
||||||
if result:
|
hits = client.search(f"{query}", per_page=10)
|
||||||
return [{'id': str(result.get('id', '')), 'name': result.get('title', ''),
|
results = []
|
||||||
'image': result.get('song_art_image_url'), 'extra': result.get('artist_names', '')}]
|
seen_ids = set()
|
||||||
|
for hit in hits:
|
||||||
|
r = hit.get('result', {})
|
||||||
|
rid = r.get('id')
|
||||||
|
if rid and rid not in seen_ids:
|
||||||
|
seen_ids.add(rid)
|
||||||
|
results.append({'id': str(rid), 'name': r.get('title', ''),
|
||||||
|
'image': r.get('song_art_image_url'), 'extra': r.get('artist_names', '')})
|
||||||
|
return results
|
||||||
return []
|
return []
|
||||||
|
|
||||||
elif service == 'tidal':
|
elif service == 'tidal':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue