889e33355f
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
110 lines
3.2 KiB
Python
110 lines
3.2 KiB
Python
from typing import Callable
|
|
|
|
from lyra_worker.browser import ArtistHit, ReleaseGroupInfo
|
|
from lyra_worker.probe import ProbeResult
|
|
from lyra_worker.similarity.base import SimilarArtist
|
|
from lyra_worker.types import Candidate, DownloadResult, MBTarget, Quality
|
|
|
|
_QUALITIES = {
|
|
"qobuz": Quality(fmt="FLAC", lossless=True, bit_depth=24, sample_rate=96000),
|
|
"soulseek": Quality(fmt="FLAC", lossless=True, bit_depth=16, sample_rate=44100),
|
|
"youtube": Quality(fmt="OPUS", lossless=False, bitrate_kbps=160),
|
|
}
|
|
|
|
|
|
class _BaseFake:
|
|
name = "fake"
|
|
tier = 99
|
|
|
|
def __init__(self, matches: bool = True):
|
|
self._matches = matches
|
|
|
|
def health(self) -> bool:
|
|
return True
|
|
|
|
def search(self, target: MBTarget) -> list[Candidate]:
|
|
if not self._matches:
|
|
return []
|
|
tracks = target.track_count or 10
|
|
return [
|
|
Candidate(
|
|
source=self.name,
|
|
source_ref=f"{self.name}:{target.artist}:{target.album}",
|
|
matched_artist=target.artist,
|
|
matched_album=target.album,
|
|
quality=_QUALITIES.get(self.name, _QUALITIES["youtube"]),
|
|
track_count=tracks,
|
|
source_tier=self.tier,
|
|
)
|
|
]
|
|
|
|
def download(
|
|
self, candidate: Candidate, dest: str, on_progress: Callable[[float], None]
|
|
) -> DownloadResult:
|
|
for pct in (0.25, 0.5, 0.75, 1.0):
|
|
on_progress(pct)
|
|
return DownloadResult(ok=True, path=dest, track_count=candidate.track_count)
|
|
|
|
|
|
class FakeQobuz(_BaseFake):
|
|
name = "qobuz"
|
|
tier = 0
|
|
|
|
|
|
class FakeSoulseek(_BaseFake):
|
|
name = "soulseek"
|
|
tier = 1
|
|
|
|
|
|
class FakeYouTube(_BaseFake):
|
|
name = "youtube"
|
|
tier = 2
|
|
|
|
|
|
class FailingAdapter(_BaseFake):
|
|
name = "qobuz" # pretends to be a real source that then fails to download
|
|
tier = 0
|
|
|
|
def download(
|
|
self, candidate: Candidate, dest: str, on_progress: Callable[[float], None]
|
|
) -> DownloadResult:
|
|
return DownloadResult(ok=False, error="simulated download failure")
|
|
|
|
|
|
class FakeMbBrowser:
|
|
"""In-memory MbBrowser for tests. `releases` maps artist mbid -> [ReleaseGroupInfo]."""
|
|
|
|
def __init__(self, artists=None, releases=None):
|
|
self._artists = list(artists or [])
|
|
self._releases = dict(releases or {})
|
|
|
|
def search_artist(self, name: str) -> list[ArtistHit]:
|
|
return list(self._artists)
|
|
|
|
def browse_release_groups(self, artist_mbid: str) -> list[ReleaseGroupInfo]:
|
|
return list(self._releases.get(artist_mbid, []))
|
|
|
|
|
|
class FakeAudioProbe:
|
|
"""In-memory AudioProbe for tests."""
|
|
def __init__(self, artist="", album="", fmt="FLAC", quality_class=3):
|
|
self._r = ProbeResult(artist=artist, album=album, fmt=fmt, quality_class=quality_class)
|
|
def probe(self, path: str) -> ProbeResult:
|
|
return self._r
|
|
|
|
|
|
class FakeSimilaritySource:
|
|
"""In-memory SimilaritySource for tests. `similar` maps seed mbid -> [SimilarArtist]."""
|
|
|
|
name = "fake"
|
|
|
|
def __init__(self, similar=None, healthy=True):
|
|
self._similar = dict(similar or {})
|
|
self._healthy = healthy
|
|
|
|
def health(self) -> bool:
|
|
return self._healthy
|
|
|
|
def similar_artists(self, mbid: str) -> list[SimilarArtist]:
|
|
return list(self._similar.get(mbid, []))
|