Files
Lyra/worker/lyra_worker/registry.py
T
Jonathan a15f4ae8bb feat(discovery): build_similarity_sources + worker sweep/trigger wiring
Adds registry.build_similarity_sources() (always constructs
ListenBrainzSource; reachability is a per-run health() concern, not a
startup gate) and wires discovery into the worker's main loop: a
scheduled sweep gated on discover.enabled + DISCOVER_TICK_SECONDS, and
a one-shot discover.requested trigger mirroring the existing
scan.requested pattern.

Also hardens run_discovery's health-check pass: a source whose
health() raises is now logged and skipped instead of aborting the
whole sweep (accepted finding from the Task-3 review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-12 00:22:34 +02:00

58 lines
2.2 KiB
Python

from lyra_worker._mbbrowser import MusicBrainzBrowser
from lyra_worker._musicbrainz import MusicBrainzResolver
from lyra_worker._mutagen import MutagenTagger
from lyra_worker._probe import MutagenProbe
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
from lyra_worker.browser import MbBrowser
from lyra_worker.probe import AudioProbe
from lyra_worker.resolver import MbResolver
from lyra_worker.similarity._listenbrainz import ListenBrainzSource
from lyra_worker.similarity.base import SimilaritySource
from lyra_worker.tagger import Tagger
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 (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()]
def build_resolver() -> MbResolver:
"""The MusicBrainz resolver used to canonicalize requests in intake."""
return MusicBrainzResolver()
def build_tagger() -> Tagger:
"""The tagger that writes canonical metadata onto downloaded files."""
return MutagenTagger()
def build_browser() -> MbBrowser:
"""The MusicBrainz browser used by the background monitor."""
return MusicBrainzBrowser()
def build_probe() -> AudioProbe:
"""The audio probe used by the library scan."""
return MutagenProbe()
def build_similarity_sources(config: dict) -> list[SimilaritySource]:
"""Similarity sources for discovery. ListenBrainz needs no credentials, so it is
always constructed; per-run reachability is checked via each source's health()."""
return [ListenBrainzSource(base_url=config.get("discover.listenBrainzUrl") or "")]