diff --git a/worker/lyra_worker/registry.py b/worker/lyra_worker/registry.py index 89cd8be..efc2c50 100644 --- a/worker/lyra_worker/registry.py +++ b/worker/lyra_worker/registry.py @@ -1,18 +1,21 @@ +from lyra_worker.adapters._slskd import SlskdClient from lyra_worker.adapters._streamrip import StreamripClient from lyra_worker.adapters._ytdlp import YtDlpClient from lyra_worker.adapters.base import SourceAdapter from lyra_worker.adapters.qobuz import QobuzAdapter +from lyra_worker.adapters.soulseek import SoulseekAdapter from lyra_worker.adapters.youtube import YouTubeAdapter def build_adapters(config: dict) -> list[SourceAdapter]: """Real source adapters, best-tier first, filtered to those that are configured. - An adapter is included only if its health() is true (e.g. Qobuz requires - credentials in config). Plan 3d adds Soulseek (slskd) the same way. + An adapter is included only if its health() is true (Qobuz needs credentials, + Soulseek needs an slskd URL + API key). YouTube needs no config. """ candidates: list[SourceAdapter] = [ QobuzAdapter(StreamripClient(config)), + SoulseekAdapter(SlskdClient(config)), YouTubeAdapter(YtDlpClient()), ] return [a for a in candidates if a.health()] diff --git a/worker/tests/test_registry.py b/worker/tests/test_registry.py index a84f635..b0592bb 100644 --- a/worker/tests/test_registry.py +++ b/worker/tests/test_registry.py @@ -1,30 +1,29 @@ from lyra_worker.adapters.qobuz import QobuzAdapter +from lyra_worker.adapters.soulseek import SoulseekAdapter from lyra_worker.adapters.youtube import YouTubeAdapter from lyra_worker.registry import build_adapters QOBUZ_CFG = {"qobuz.email": "me@example.com", "qobuz.password": "secret"} +SLSKD_CFG = {"slskd.url": "http://slskd:5030", "slskd.api_key": "key"} -def test_youtube_always_present_qobuz_skipped_without_config(): - adapters = build_adapters({}) +def test_only_youtube_without_any_config(): + names = [a.name for a in build_adapters({})] + assert names == ["youtube"] # qobuz + soulseek both gated off + + +def test_soulseek_included_when_configured(): + adapters = build_adapters(SLSKD_CFG) names = [a.name for a in adapters] - assert "youtube" in names - assert "qobuz" not in names # no creds -> health() false -> excluded + assert "soulseek" in names and "youtube" in names + assert "qobuz" not in names + assert isinstance(next(a for a in adapters if a.name == "soulseek"), SoulseekAdapter) -def test_qobuz_included_when_configured(): - adapters = build_adapters(QOBUZ_CFG) - names = [a.name for a in adapters] - assert "qobuz" in names - assert "youtube" in names - qz = next(a for a in adapters if a.name == "qobuz") - yt = next(a for a in adapters if a.name == "youtube") - assert isinstance(qz, QobuzAdapter) - assert isinstance(yt, YouTubeAdapter) - - -def test_adapter_names_unique_and_qobuz_first(): - adapters = build_adapters(QOBUZ_CFG) +def test_all_three_configured_ordered_by_tier(): + adapters = build_adapters({**QOBUZ_CFG, **SLSKD_CFG}) names = [a.name for a in adapters] + assert names == ["qobuz", "soulseek", "youtube"] # tiers 0,1,2 assert len(names) == len(set(names)) - assert names[0] == "qobuz" # tier 0 listed first + assert isinstance(next(a for a in adapters if a.name == "qobuz"), QobuzAdapter) + assert isinstance(next(a for a in adapters if a.name == "youtube"), YouTubeAdapter)