soulsync/core/wishlist/resolution.py
Antti Kettunen 0fa692f935
Make wishlist respect configured providers
- add neutral wishlist payload helpers while keeping legacy Spotify aliases
- route wishlist removal and classification through generic track data
- keep API and service compatibility for existing callers
2026-04-30 07:41:22 +03:00

176 lines
7.8 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Wishlist resolution and removal helpers."""
from __future__ import annotations
from typing import Any, Dict, List
from core.imports.context import (
get_import_original_search,
get_import_search_result,
get_import_source,
get_import_source_ids,
get_import_track_info,
)
from core.wishlist.service import get_wishlist_service
from database.music_database import get_database
from utils.logging_config import get_logger
logger = get_logger("wishlist.resolution")
def _primary_track_artist_name(track_info: Dict[str, Any]) -> str:
artists = (track_info or {}).get("artists", [])
if isinstance(artists, list) and artists:
first = artists[0]
if isinstance(first, dict):
return str(first.get("name", "") or "")
return str(first or "")
if isinstance(artists, str):
return artists
return str((track_info or {}).get("artist", "") or "")
def _all_profile_wishlist_tracks(wishlist_service, database=None) -> List[Dict[str, Any]]:
database = database or get_database()
all_profiles = database.get_all_profiles()
wishlist_tracks: List[Dict[str, Any]] = []
for profile in all_profiles:
wishlist_tracks.extend(wishlist_service.get_wishlist_tracks_for_download(profile_id=profile["id"]))
return wishlist_tracks
def check_and_remove_from_wishlist(context: Dict[str, Any], wishlist_service=None, database=None) -> None:
"""Check whether a successful download should be removed from the wishlist."""
try:
wishlist_service = wishlist_service or get_wishlist_service()
source = get_import_source(context)
source_ids = get_import_source_ids(context)
source_label = {
"spotify": "Spotify",
"itunes": "iTunes",
"deezer": "Deezer",
"discogs": "Discogs",
"hydrabase": "Hydrabase",
}.get(source, "Source")
track_info = get_import_track_info(context) or get_import_search_result(context)
search_result = get_import_original_search(context) or get_import_search_result(context)
track_id = None
track_id = source_ids.get("track_id") or None
if track_id:
logger.info("[Wishlist] Found %s track ID from source_ids: %s", source_label, track_id)
elif "wishlist_id" in track_info:
wishlist_id = track_info["wishlist_id"]
logger.info("[Wishlist] Found wishlist_id in context: %s", wishlist_id)
wishlist_tracks = _all_profile_wishlist_tracks(wishlist_service, database=database)
for wishlist_track in wishlist_tracks:
if wishlist_track.get("wishlist_id") == wishlist_id:
track_id = wishlist_track.get("track_id") or wishlist_track.get("spotify_track_id") or wishlist_track.get("id")
logger.info("[Wishlist] Found track ID from wishlist entry: %s", track_id)
break
if not track_id:
track_name = track_info.get("name") or search_result.get("title", "")
artist_name = _primary_track_artist_name(track_info) or _primary_track_artist_name(search_result)
if track_name and artist_name:
logger.warning(
"[Wishlist] No track ID found, checking for fuzzy match: '%s' by '%s'",
track_name,
artist_name,
)
wishlist_tracks = _all_profile_wishlist_tracks(wishlist_service, database=database)
for wishlist_track in wishlist_tracks:
wl_name = wishlist_track.get("name", "").lower()
wl_artists = wishlist_track.get("artists", [])
wl_artist_name = ""
if wl_artists:
if isinstance(wl_artists[0], dict):
wl_artist_name = wl_artists[0].get("name", "").lower()
else:
wl_artist_name = str(wl_artists[0]).lower()
if wl_name == track_name.lower() and wl_artist_name == artist_name.lower():
track_id = wishlist_track.get("track_id") or wishlist_track.get("spotify_track_id") or wishlist_track.get("id")
logger.info("[Wishlist] Found fuzzy match - track ID: %s", track_id)
break
if track_id:
logger.info("[Wishlist] Attempting to remove track from wishlist: %s", track_id)
removed = wishlist_service.mark_track_download_result(track_id, success=True)
if removed:
logger.info("[Wishlist] Successfully removed track from wishlist: %s", track_id)
else:
logger.warning(" [Wishlist] Track not found in wishlist or already removed: %s", track_id)
else:
logger.warning(" [Wishlist] No track ID found for wishlist removal check")
except Exception as exc:
logger.error("[Wishlist] Error in wishlist removal check: %s", exc)
def check_and_remove_track_from_wishlist_by_metadata(
track_data: Dict[str, Any],
wishlist_service=None,
database=None,
) -> bool:
"""Remove a wishlist track by metadata after a database/library match."""
try:
wishlist_service = wishlist_service or get_wishlist_service()
track_name = track_data.get("name", "")
track_id = track_data.get("id", "")
artists = track_data.get("artists", [])
logger.info("[Analysis] Checking if track should be removed from wishlist: '%s' (ID: %s)", track_name, track_id)
if track_id:
removed = wishlist_service.mark_track_download_result(track_id, success=True)
if removed:
logger.info("[Analysis] Removed track from wishlist via direct ID match: %s", track_id)
return True
if track_name and artists:
primary_artist = _primary_track_artist_name(track_data)
if primary_artist:
logger.warning(
"[Analysis] No direct ID match, trying fuzzy match: '%s' by '%s'",
track_name,
primary_artist,
)
wishlist_tracks = _all_profile_wishlist_tracks(wishlist_service, database=database)
for wishlist_track in wishlist_tracks:
wl_name = wishlist_track.get("name", "").lower()
wl_artists = wishlist_track.get("artists", [])
wl_artist_name = ""
if wl_artists:
if isinstance(wl_artists[0], dict):
wl_artist_name = wl_artists[0].get("name", "").lower()
else:
wl_artist_name = str(wl_artists[0]).lower()
if wl_name == track_name.lower() and wl_artist_name == primary_artist.lower():
spotify_track_id = (
wishlist_track.get("track_id")
or wishlist_track.get("spotify_track_id")
or wishlist_track.get("id")
)
if spotify_track_id:
removed = wishlist_service.mark_track_download_result(spotify_track_id, success=True)
if removed:
logger.info("[Analysis] Removed track from wishlist via fuzzy match: %s", spotify_track_id)
return True
logger.warning(" [Analysis] Track not found in wishlist or already removed: '%s'", track_name)
return False
except Exception as e:
logger.error("[Analysis] Error checking wishlist removal by metadata: %s", e)
import traceback
traceback.print_exc()
return False
__all__ = ["check_and_remove_from_wishlist", "check_and_remove_track_from_wishlist_by_metadata"]