import server.mf # noqa: F401 — loads musicfetch, registers musicfetch_core import musicfetch_core as mf class _FakeResp: def __init__(self, status, payload): self.status_code = status self._payload = payload def json(self): return self._payload FULL = { "entityUniqueId": "SPOTIFY_SONG::abc", "entitiesByUniqueId": { "SPOTIFY_SONG::abc": { "title": "Bloom", "artistName": "ODESZA", "thumbnailUrl": "https://img/cover.jpg", } }, "linksByPlatform": { "youtubeMusic": {"url": "https://music.youtube.com/watch?v=YYY"}, "youtube": {"url": "https://youtube.com/watch?v=YYY"}, }, } def test_odesli_resolve_full(monkeypatch): monkeypatch.setattr(mf.requests, "get", lambda *a, **k: _FakeResp(200, FULL)) r = mf.odesli_resolve("https://open.spotify.com/track/abc") assert r.title == "Bloom" assert r.artist == "ODESZA" assert r.thumb == "https://img/cover.jpg" assert r.youtube_url == "https://music.youtube.com/watch?v=YYY" def test_odesli_resolve_prefers_ytmusic_then_youtube(monkeypatch): payload = {**FULL, "linksByPlatform": {"youtube": {"url": "https://youtube.com/watch?v=ZZZ"}}} monkeypatch.setattr(mf.requests, "get", lambda *a, **k: _FakeResp(200, payload)) r = mf.odesli_resolve("https://open.spotify.com/track/abc") assert r.youtube_url == "https://youtube.com/watch?v=ZZZ" def test_odesli_resolve_no_youtube_link(monkeypatch): payload = {**FULL, "linksByPlatform": {}} monkeypatch.setattr(mf.requests, "get", lambda *a, **k: _FakeResp(200, payload)) r = mf.odesli_resolve("https://open.spotify.com/track/abc") assert r.youtube_url == "" assert r.title == "Bloom" def test_odesli_resolve_non_200_returns_none(monkeypatch): monkeypatch.setattr(mf.requests, "get", lambda *a, **k: _FakeResp(429, {})) assert mf.odesli_resolve("https://open.spotify.com/track/abc") is None def test_odesli_resolve_malformed_returns_none(monkeypatch): monkeypatch.setattr(mf.requests, "get", lambda *a, **k: _FakeResp(200, {"nope": 1})) assert mf.odesli_resolve("https://open.spotify.com/track/abc") is None def test_odesli_resolve_network_error_returns_none(monkeypatch): def boom(*a, **k): raise mf.RequestException("down") monkeypatch.setattr(mf.requests, "get", boom) assert mf.odesli_resolve("https://open.spotify.com/track/abc") is None def test_is_direct_url_youtube(): assert mf._is_direct_url("https://music.youtube.com/watch?v=abc") assert mf._is_direct_url("https://www.youtube.com/watch?v=abc") assert mf._is_direct_url("https://youtu.be/abc") def test_is_direct_url_soundcloud(): assert mf._is_direct_url("https://soundcloud.com/dj/track") def test_is_direct_url_other_platforms_false(): assert not mf._is_direct_url("https://open.spotify.com/track/abc") assert not mf._is_direct_url("https://music.apple.com/us/album/x/1?i=2") assert not mf._is_direct_url("https://tidal.com/browse/track/123") def test_is_direct_url_youtube_playlist_true(): assert mf._is_direct_url("https://www.youtube.com/playlist?list=PLabc") def test_is_direct_url_lookalike_hosts_false(): # Trailing-substring look-alikes must NOT be treated as direct (label boundary). assert not mf._is_direct_url("https://notyoutube.com/watch?v=abc") assert not mf._is_direct_url("https://myyoutube.com/x") assert not mf._is_direct_url("https://evilyoutu.be/x") assert not mf._is_direct_url("https://youtube.com.evil.com/x") def test_is_direct_url_subdomains_true(): assert mf._is_direct_url("https://m.youtube.com/watch?v=abc") assert mf._is_direct_url("https://on.soundcloud.com/x") assert mf._is_direct_url("https://api.soundcloud.com/tracks/1") def _resolved(yt="https://music.youtube.com/watch?v=YYY"): return mf.Resolved(title="Bloom", artist="ODESZA", thumb="https://img/cover.jpg", youtube_url=yt) def test_resolve_link_hits_builds_query_and_exact_yt(monkeypatch): monkeypatch.setattr(mf, "odesli_resolve", lambda url: _resolved()) lid = mf.Hit(source="lidarr", kind="album", title="A Moment Apart", artist="ODESZA", album="A Moment Apart", year="2017", payload={"album": {"id": 9}}) monkeypatch.setattr(mf, "lidarr_search", lambda q, limit: [lid]) query, hits = mf.resolve_link_hits("https://open.spotify.com/track/abc", 10) assert query == "ODESZA - Bloom" assert hits[0].source == "lidarr" yt = hits[-1] assert yt.source == "youtube" and yt.kind == "track" assert yt.title == "Bloom" and yt.artist == "ODESZA" assert yt.payload["url"] == "https://music.youtube.com/watch?v=YYY" def test_resolve_link_hits_no_yt_link_lidarr_only(monkeypatch): monkeypatch.setattr(mf, "odesli_resolve", lambda url: _resolved(yt="")) lid = mf.Hit(source="lidarr", kind="album", title="X", artist="ODESZA", payload={"album": {"id": 9}}) monkeypatch.setattr(mf, "lidarr_search", lambda q, limit: [lid]) query, hits = mf.resolve_link_hits("https://open.spotify.com/track/abc", 10) assert all(h.source == "lidarr" for h in hits) def test_resolve_link_hits_odesli_miss_raises(monkeypatch): import pytest monkeypatch.setattr(mf, "odesli_resolve", lambda url: None) with pytest.raises(mf.OdesliError): mf.resolve_link_hits("https://open.spotify.com/track/abc", 10) def test_handle_link_miss_prints_and_returns(monkeypatch, capsys): monkeypatch.setattr(mf, "odesli_resolve", lambda url: None) mf.handle_link("https://open.spotify.com/track/abc", "/m", "best", False, True, False, 10) out = capsys.readouterr() assert "Couldn't resolve" in (out.err + out.out) def test_handle_link_dispatches_chosen(monkeypatch): monkeypatch.setattr(mf, "odesli_resolve", lambda url: _resolved()) monkeypatch.setattr(mf, "lidarr_search", lambda q, limit: []) chosen = {} monkeypatch.setattr(mf, "pick", lambda hits, q, ni, yf: hits[0]) monkeypatch.setattr(mf, "_dispatch_chosen", lambda c, hits, root, quality, dry, lo, sa: chosen.update(c=c, root=root)) mf.handle_link("https://open.spotify.com/track/abc", "/m", "best", False, True, False, 10) assert chosen["c"].source == "youtube" assert chosen["root"] == "/m"