mirror of https://github.com/Nezreka/SoulSync.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
75 lines
2.6 KiB
75 lines
2.6 KiB
"""Pure artist-list resolution for tag-write paths.
|
|
|
|
Single source of truth for "what is the canonical multi-value artists
|
|
list for this track?" Different download paths populate `context` with
|
|
different keys — Deezer-direct downloads stamp `original_search.artists`
|
|
as a proper list, but Soulseek matched downloads only carry `artist`
|
|
(singular string) in `original_search_result` while the full list lives
|
|
on `track_info` (the full Spotify track object).
|
|
|
|
Resolution order:
|
|
1. `context.original_search_result.artists` (preferred — already-
|
|
curated by the source path that constructed the context)
|
|
2. `context.track_info.artists` (Spotify/Deezer/Tidal full track
|
|
object — always carries the artists array when matched)
|
|
3. `[artist_dict.name]` as a single-element fallback when neither
|
|
carries a list (primary-artist-only)
|
|
|
|
Each list item may be a dict with a `name` key (Spotify shape), a bare
|
|
string, or any other object — the helper normalizes all three to
|
|
strings and drops empty entries.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
|
|
def _normalize_artists_iterable(items: Any) -> List[str]:
|
|
if not isinstance(items, list):
|
|
return []
|
|
result: List[str] = []
|
|
for item in items:
|
|
if isinstance(item, dict):
|
|
name = item.get("name")
|
|
if isinstance(name, str) and name.strip():
|
|
result.append(name.strip())
|
|
elif isinstance(item, str):
|
|
stripped = item.strip()
|
|
if stripped:
|
|
result.append(stripped)
|
|
elif item is not None:
|
|
text = str(item).strip()
|
|
if text:
|
|
result.append(text)
|
|
return result
|
|
|
|
|
|
def resolve_track_artists(
|
|
original_search: Optional[Dict[str, Any]],
|
|
track_info: Optional[Dict[str, Any]],
|
|
artist_dict: Optional[Dict[str, Any]],
|
|
) -> List[str]:
|
|
"""Return the canonical multi-value artists list for tag-write.
|
|
|
|
Falls through preferred → track_info → primary-artist fallback. Each
|
|
candidate is normalized to a list of stripped non-empty strings.
|
|
Empty list returned only when every candidate is empty/invalid.
|
|
"""
|
|
if isinstance(original_search, dict):
|
|
primary = _normalize_artists_iterable(original_search.get("artists"))
|
|
if primary:
|
|
return primary
|
|
|
|
if isinstance(track_info, dict):
|
|
secondary = _normalize_artists_iterable(track_info.get("artists"))
|
|
if secondary:
|
|
return secondary
|
|
|
|
if isinstance(artist_dict, dict):
|
|
name = artist_dict.get("name")
|
|
if isinstance(name, str) and name.strip():
|
|
return [name.strip()]
|
|
|
|
return []
|