You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SoulSync/tests/test_unknown_artist_fixer.py

242 lines
7.6 KiB

import sys
import types
from types import SimpleNamespace
if "spotipy" not in sys.modules:
spotipy = types.ModuleType("spotipy")
class _DummySpotify:
def __init__(self, *args, **kwargs):
pass
oauth2 = types.ModuleType("spotipy.oauth2")
class _DummyOAuth:
def __init__(self, *args, **kwargs):
pass
spotipy.Spotify = _DummySpotify
oauth2.SpotifyOAuth = _DummyOAuth
oauth2.SpotifyClientCredentials = _DummyOAuth
spotipy.oauth2 = oauth2
sys.modules["spotipy"] = spotipy
sys.modules["spotipy.oauth2"] = oauth2
if "config.settings" not in sys.modules:
config_pkg = types.ModuleType("config")
settings_mod = types.ModuleType("config.settings")
class _DummyConfigManager:
def get(self, key, default=None):
return default
def get_active_media_server(self):
return "plex"
settings_mod.config_manager = _DummyConfigManager()
config_pkg.settings = settings_mod
sys.modules["config"] = config_pkg
sys.modules["config.settings"] = settings_mod
from core.repair_jobs.unknown_artist_fixer import UnknownArtistFixerJob
import core.repair_jobs.unknown_artist_fixer as unknown_artist_fixer_module
class _FakeClient:
def __init__(self, track_details=None, search_results=None):
self.track_details = track_details or {}
self.search_results = search_results or {}
self.get_calls = []
self.search_calls = []
def get_track_details(self, track_id):
self.get_calls.append(track_id)
return self.track_details.get(track_id)
def search_tracks(self, query, limit=5):
self.search_calls.append((query, limit))
return self.search_results.get(query, [])
def _install_tag_reader(monkeypatch, tags=None):
fake_module = types.ModuleType("core.tag_writer")
fake_module.read_file_tags = lambda path: tags or {}
monkeypatch.setitem(sys.modules, "core.tag_writer", fake_module)
def test_unknown_artist_fixer_uses_primary_source_track_id_first(monkeypatch):
job = UnknownArtistFixerJob()
_install_tag_reader(monkeypatch)
deezer_client = _FakeClient(
track_details={
"dz-1": {
"primary_artist": "Deezer Artist",
"album": {
"name": "Deezer Album",
"release_date": "2024-02-01",
"images": [{"url": "https://img/deezer"}],
},
"name": "Deezer Song",
"track_number": 7,
"disc_number": 1,
}
}
)
spotify_client = _FakeClient(
track_details={
"sp-1": {
"primary_artist": "Spotify Artist",
"album": {
"name": "Spotify Album",
"release_date": "2023-01-01",
"images": [{"url": "https://img/spotify"}],
},
"name": "Spotify Song",
"track_number": 1,
"disc_number": 1,
}
}
)
monkeypatch.setattr(unknown_artist_fixer_module, "get_primary_source", lambda: "deezer")
monkeypatch.setattr(
unknown_artist_fixer_module,
"get_client_for_source",
lambda source: {"deezer": deezer_client, "spotify": spotify_client}.get(source),
)
track = {
"title": "Unknown Title",
"album_title": "Unknown Album",
"spotify_track_id": "sp-1",
"deezer_id": "dz-1",
"itunes_track_id": "",
}
result = job._resolve_metadata(SimpleNamespace(), track, "/tmp/track.flac")
assert result["artist"] == "Deezer Artist"
assert result["album"] == "Deezer Album"
assert result["source"] == "deezer_track_id_lookup"
assert deezer_client.get_calls == ["dz-1"]
assert spotify_client.get_calls == []
def test_unknown_artist_fixer_searches_primary_source_first(monkeypatch):
job = UnknownArtistFixerJob()
_install_tag_reader(monkeypatch)
candidate = SimpleNamespace(
id="dz-song-1",
name="Matching Title",
album="Matching Album",
artists=["Deezer Artist"],
image_url="https://img/deezer-search",
)
deezer_client = _FakeClient(
track_details={
"dz-song-1": {
"primary_artist": "Deezer Artist",
"album": {
"name": "Matching Album",
"release_date": "2024-03-02",
"images": [{"url": "https://img/deezer-full"}],
},
"name": "Matching Title",
"track_number": 4,
"disc_number": 1,
}
},
search_results={"Matching Title": [candidate]},
)
spotify_client = _FakeClient(
search_results={
"Matching Title": [
SimpleNamespace(
id="sp-song-1",
name="Matching Title",
album="Matching Album",
artists=["Spotify Artist"],
image_url="https://img/spotify-search",
)
]
}
)
monkeypatch.setattr(unknown_artist_fixer_module, "get_primary_source", lambda: "deezer")
monkeypatch.setattr(
unknown_artist_fixer_module,
"get_client_for_source",
lambda source: {"deezer": deezer_client, "spotify": spotify_client}.get(source),
)
track = {
"title": "Matching Title",
"album_title": "Matching Album",
"spotify_track_id": "",
"deezer_id": "",
"itunes_track_id": "",
}
result = job._resolve_metadata(SimpleNamespace(sleep_or_stop=lambda seconds: False), track, "/tmp/track.flac")
assert result["artist"] == "Deezer Artist"
assert result["album"] == "Matching Album"
assert result["source"] == "deezer_title_search"
assert deezer_client.search_calls == [("Matching Title", 5)]
assert spotify_client.search_calls == []
def test_unknown_artist_fixer_supports_hydrabase_title_search(monkeypatch):
job = UnknownArtistFixerJob()
_install_tag_reader(monkeypatch)
hydrabase_candidate = SimpleNamespace(
id="hy-song-1",
name="Hydra Match",
album="Hydra Album",
artists=["Hydra Artist"],
image_url="https://img/hydra-search",
)
hydrabase_client = _FakeClient(
track_details={
"hy-song-1": {
"primary_artist": "Hydra Artist",
"album": {
"name": "Hydra Album",
"release_date": "2024-04-03",
"images": [{"url": "https://img/hydra-full"}],
},
"name": "Hydra Match",
"track_number": 2,
"disc_number": 1,
}
},
search_results={"Hydra Match": [hydrabase_candidate]},
)
spotify_client = _FakeClient()
monkeypatch.setattr(unknown_artist_fixer_module, "get_primary_source", lambda: "hydrabase")
monkeypatch.setattr(
unknown_artist_fixer_module,
"get_client_for_source",
lambda source: {"hydrabase": hydrabase_client, "spotify": spotify_client}.get(source),
)
track = {
"title": "Hydra Match",
"album_title": "Hydra Album",
"spotify_track_id": "",
"deezer_id": "",
"itunes_track_id": "",
}
result = job._resolve_metadata(SimpleNamespace(sleep_or_stop=lambda seconds: False), track, "/tmp/track.flac")
assert result["artist"] == "Hydra Artist"
assert result["source"] == "hydrabase_title_search"
assert hydrabase_client.search_calls == [("Hydra Match", 5)]
assert spotify_client.search_calls == []