diff --git a/deezspot/easy_spoty.py b/deezspot/easy_spoty.py index e52dd21..62e0f3e 100644 --- a/deezspot/easy_spoty.py +++ b/deezspot/easy_spoty.py @@ -1,13 +1,12 @@ #!/usr/bin/python3 -from librespot.core import Session, SearchManager +from librespot.core import Session from librespot.metadata import TrackId, AlbumId, ArtistId, EpisodeId, ShowId, PlaylistId from deezspot.exceptions import InvalidLink from typing import Any, Dict, List, Optional -# Note: We intentionally avoid importing spotipy. This module is now a -# thin shim over librespot's internal API, returning Web-API-shaped dicts -# consumed by spotloader's converters. +# Note: Search is handled via spotipy (Web API). Other metadata (tracks/albums/...) +# still use librespot via LibrespotClient. from deezspot.libutils import LibrespotClient @@ -481,36 +480,22 @@ class Spo: @classmethod def search(cls, query, search_type='track', limit=10, country: Optional[str] = None, locale: Optional[str] = None, catalogue: Optional[str] = None, image_size: Optional[str] = None, client_id=None, client_secret=None): - cls.__check_initialized() - # Preferred path: use LibrespotClient for consistent defaults and options - if cls.__client is not None: - res = cls.__client.search( - query=query, - limit=limit, - country=country or cls.__get_session_country_code(), - locale=locale, - catalogue=catalogue, - image_size=image_size, - ) - # Optionally filter by type if requested (best-effort; librespot returns mixed) - if search_type and isinstance(res, dict) and search_type in res: - return {search_type: res.get(search_type)} + # Reverted: use spotipy Web API search; librespot search is not supported here. + try: + import spotipy # type: ignore + from spotipy.oauth2 import SpotifyClientCredentials # type: ignore + except Exception as e: + raise RuntimeError("spotipy is required for search; please install spotipy") from e + try: + if client_id or client_secret: + auth_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret) + else: + auth_manager = SpotifyClientCredentials() + sp = spotipy.Spotify(auth_manager=auth_manager) + type_param = ','.join([t.strip() for t in str(search_type or 'track').split(',') if t.strip()]) or 'track' + market = country or None + res = sp.search(q=query, type=type_param, market=market, limit=int(limit) if limit is not None else 10) return res - # Fallback: direct SearchManager - req = SearchManager.SearchRequest(query).set_limit(limit) - if country: - req.set_country(country) - else: - cc = cls.__get_session_country_code() - if cc: - req.set_country(cc) - if locale: - req.set_locale(locale) - if catalogue: - req.set_catalogue(catalogue) - if image_size: - req.set_image_size(image_size) - res = cls.__session.search().request(req) # type: ignore[union-attr] - if search_type and isinstance(res, dict) and search_type in res: - return {search_type: res.get(search_type)} - return res + except Exception as e: + # Surface a concise error to callers + raise RuntimeError(f"Spotify search failed: {e}") diff --git a/pyproject.toml b/pyproject.toml index 49322d4..13a406f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,8 @@ dependencies = [ "fastapi==0.116.1", "uvicorn[standard]==0.35.0", "librespot-spotizerr==0.3.0", - "rapidfuzz==3.13.0" + "rapidfuzz==3.13.0", + "spotipy==2.25.1" ] [project.urls] diff --git a/setup.py b/setup.py index 903e517..c329289 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ setup( "fastapi==0.116.1", "uvicorn[standard]==0.35.0", "librespot-spotizerr==0.3.0", - "rapidfuzz" + "rapidfuzz==3.13.0", + "spotipy==2.25.1" ], )