- 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
176 lines
7.8 KiB
Python
176 lines
7.8 KiB
Python
"""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"]
|