diff --git a/core/spotify_client.py b/core/spotify_client.py index 2085e55..77570ed 100644 --- a/core/spotify_client.py +++ b/core/spotify_client.py @@ -255,3 +255,28 @@ def resolve_spotify_track_no_auth(url: str) -> tuple[str, str, list[dict]]: track = {"name": name, "artist": artist} return "Brano", name, [track] + + +def search_track(token: str, query: str): + """Cerca un brano su Spotify e ritorna il primo match. + + Ritorna un dict con {id, url, name, artists} oppure None se nessun match. + Solleva requests.HTTPError su errori server / auth. + """ + resp = requests.get( + "https://api.spotify.com/v1/search", + headers={"Authorization": f"Bearer {token}"}, + params={"q": query, "type": "track", "limit": 1}, + timeout=15, + ) + resp.raise_for_status() + items = resp.json().get("tracks", {}).get("items", []) + if not items: + return None + t = items[0] + return { + "id": t.get("id"), + "url": t.get("external_urls", {}).get("spotify", ""), + "name": t.get("name", ""), + "artists": ", ".join(a.get("name", "") for a in t.get("artists", [])), + } diff --git a/tests/test_spotify_client.py b/tests/test_spotify_client.py new file mode 100644 index 0000000..0590c3e --- /dev/null +++ b/tests/test_spotify_client.py @@ -0,0 +1,70 @@ +"""Test per core.spotify_client.search_track().""" + +from __future__ import annotations + +import pytest +import responses + +from core import spotify_client + + +class TestSearchTrack: + @responses.activate + def test_returns_track_dict_when_found(self): + responses.add( + responses.GET, + "https://api.spotify.com/v1/search", + json={ + "tracks": { + "items": [ + { + "id": "abc123", + "name": "Hot Sauce", + "artists": [{"name": "Kapuchon"}], + "external_urls": {"spotify": "https://open.spotify.com/track/abc123"}, + } + ] + } + }, + status=200, + ) + result = spotify_client.search_track("fake-token", "Kapuchon Hot Sauce") + assert result is not None + assert result["id"] == "abc123" + assert result["url"] == "https://open.spotify.com/track/abc123" + + @responses.activate + def test_returns_none_when_no_results(self): + responses.add( + responses.GET, + "https://api.spotify.com/v1/search", + json={"tracks": {"items": []}}, + status=200, + ) + result = spotify_client.search_track("fake-token", "no-match") + assert result is None + + @responses.activate + def test_sends_bearer_token(self): + responses.add( + responses.GET, + "https://api.spotify.com/v1/search", + json={"tracks": {"items": []}}, + status=200, + ) + spotify_client.search_track("my-token", "q") + assert responses.calls[0].request.headers["Authorization"] == "Bearer my-token" + + @responses.activate + def test_query_params_correct(self): + responses.add( + responses.GET, + "https://api.spotify.com/v1/search", + json={"tracks": {"items": []}}, + status=200, + ) + spotify_client.search_track("t", "Kapuchon Hot Sauce") + params = responses.calls[0].request.params + assert params["q"] == "Kapuchon Hot Sauce" + assert params["type"] == "track" + assert params["limit"] == "1"