"""Library-aware Lidarr behaviour: never add a duplicate artist, never grab a random album, and describe a release in words a person understands.""" import server.mf # noqa: F401 — loads musicfetch, registers musicfetch_core import musicfetch_core as mf JACKO = {"id": 3, "artistName": "Michael Jackson", "foreignArtistId": "mj-mbid"} def _no_add(*_a, **_kw): raise AssertionError("add_artist must not be called for an existing artist") # --- find_library_artist / ensure_artist ----------------------------------- def test_find_library_artist_matches_name_case_insensitively(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) assert mf.find_library_artist(name="michael jackson") == JACKO def test_find_library_artist_matches_mbid_when_name_differs(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) assert mf.find_library_artist(name="Jacko", foreign_id="mj-mbid") == JACKO def test_find_library_artist_returns_none_when_absent(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) assert mf.find_library_artist(name="Overgrown") is None def test_ensure_artist_never_adds_a_duplicate(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) monkeypatch.setattr(mf, "add_artist", _no_add) res = mf.ensure_artist({"artistName": "Michael Jackson"}, "/media/music", False, False) assert res["state"] == "existing" assert res["artist"] == JACKO assert res["name"] == "Michael Jackson" def test_ensure_artist_adds_when_missing(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: []) monkeypatch.setattr(mf, "add_artist", lambda meta, root, search_all, dry_run: {"id": 9, "artistName": "Overgrown"}) res = mf.ensure_artist({"artistName": "Overgrown", "foreignArtistId": "og"}, "/media/music", False, False) assert res["state"] == "added" assert res["artist"]["id"] == 9 def test_ensure_artist_reports_failure(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: []) monkeypatch.setattr(mf, "add_artist", lambda *a, **kw: None) res = mf.ensure_artist({"artistName": "Overgrown"}, "/media/music", False, False) assert res["state"] == "failed" assert res["artist"] is None def test_act_lidarr_artist_does_not_add_existing(monkeypatch, capsys): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) monkeypatch.setattr(mf, "add_artist", _no_add) hit = mf.Hit(source="lidarr", kind="artist", title="Michael Jackson", artist="Michael Jackson", payload={"artist": {"artistName": "Michael Jackson"}}) assert mf.act_lidarr_artist(hit, "/media/music", False, False) is True assert "already in Lidarr" in capsys.readouterr().out # --- album matching -------------------------------------------------------- LIB_ALBUMS = [ {"id": 11, "title": "Off the Wall", "foreignAlbumId": "otw"}, {"id": 12, "title": "Thriller (Deluxe Edition)", "foreignAlbumId": "thr-deluxe"}, ] def test_match_album_prefers_the_musicbrainz_id(): got = mf._match_album(LIB_ALBUMS, {"title": "Something Else", "foreignAlbumId": "otw"}) assert got["id"] == 11 def test_match_album_matches_title_ignoring_case_and_punctuation(): got = mf._match_album(LIB_ALBUMS, {"title": "off the wall!"}) assert got["id"] == 11 def test_match_album_ignores_an_edition_suffix(): got = mf._match_album(LIB_ALBUMS, {"title": "Thriller"}) assert got["id"] == 12 def test_match_album_returns_none_instead_of_a_random_album(): assert mf._match_album(LIB_ALBUMS, {"title": "Bad"}) is None def test_ensure_album_reports_missing_album_rather_than_guessing(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) monkeypatch.setattr(mf, "_artist_albums", lambda artist_id: LIB_ALBUMS) res = mf.ensure_album({"title": "Bad", "artist": {"artistName": "Michael Jackson"}}, "/media/music", False, False) assert res["album"] is None assert res["album_state"] == "missing" assert res["artist_state"] == "existing" def test_ensure_album_monitors_an_unmonitored_album(monkeypatch): album = {"id": 11, "title": "Off the Wall", "monitored": False} puts = [] monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) monkeypatch.setattr(mf, "_artist_albums", lambda artist_id: [album]) monkeypatch.setattr(mf, "lidarr_put", lambda path, payload, **kw: puts.append(payload) or {}) res = mf.ensure_album({"title": "Off the Wall", "artist": {"artistName": "Michael Jackson"}}, "/media/music", False, False) assert res["album_state"] == "monitored" assert res["album_id"] == 11 assert puts == [{"albumIds": [11], "monitored": True}] def test_ensure_album_leaves_a_monitored_album_alone(monkeypatch): album = {"id": 11, "title": "Off the Wall", "monitored": True} monkeypatch.setattr(mf, "library_artists", lambda: [JACKO]) monkeypatch.setattr(mf, "_artist_albums", lambda artist_id: [album]) monkeypatch.setattr(mf, "lidarr_put", lambda *a, **kw: (_ for _ in ()).throw( AssertionError("must not re-monitor"))) res = mf.ensure_album({"title": "Off the Wall", "artist": {"artistName": "Michael Jackson"}}, "/media/music", False, False) assert res["album_state"] == "existing" # --- releases -------------------------------------------------------------- def _release(**kw): base = {"guid": "g1", "indexerId": 2, "title": "Overgrown-Lay_Cold-WEB-2023", "size": 312 * 1024 * 1024, "seeders": 24, "indexer": "Redacted", "quality": {"quality": {"name": "FLAC"}}} base.update(kw) return base def test_release_label_is_readable(): label = mf.release_label(_release()) assert label == "FLAC, 312 MB, 24 seeders, Redacted" def test_release_label_uses_gigabytes_for_big_files(): assert "2.0 GB" in mf.release_label(_release(size=2 * 1024 * 1024 * 1024)) def test_release_label_flags_a_rejected_release(): label = mf.release_label(_release(rejected=True, rejections=["Not a preferred word"])) assert "not recommended" in label assert "Not a preferred word" in label def test_release_label_falls_back_to_the_raw_title(): assert mf.release_label({"title": "Weird.Release"}) == "Weird.Release" def test_sort_releases_puts_rejected_last_and_best_seeded_first(): low = _release(guid="low", seeders=2) high = _release(guid="high", seeders=90) bad = _release(guid="bad", seeders=500, rejected=True) order = [r["guid"] for r in mf.sort_releases([low, bad, high])] assert order == ["high", "low", "bad"] def test_list_releases_skips_a_call_without_a_real_album_id(): assert mf.list_releases(0) == [] assert mf.list_releases(None) == [] def test_grab_release_posts_the_exact_guid_and_indexer(monkeypatch): posted = {} monkeypatch.setattr(mf, "lidarr_post", lambda path, payload, **kw: posted.update(path=path, payload=payload) or {}) assert mf.grab_release(_release()) is True assert posted["path"] == "/api/v1/release" assert posted["payload"] == {"guid": "g1", "indexerId": 2} def test_grab_release_refuses_an_incomplete_release(monkeypatch): monkeypatch.setattr(mf, "lidarr_post", lambda *a, **kw: (_ for _ in ()).throw( AssertionError("must not post"))) assert mf.grab_release({"title": "no guid"}) is False # --- album dispatch -------------------------------------------------------- def _album_hit(): return mf.Hit(source="lidarr", kind="album", title="Lay Cold", album="Lay Cold", artist="Overgrown", payload={"album": {"title": "Lay Cold", "artist": {"artistName": "Overgrown"}}}) def test_act_lidarr_album_grabs_the_best_release(monkeypatch, capsys): grabbed = {} monkeypatch.setattr(mf, "ensure_album", lambda *a, **kw: { "album": {"id": 5}, "album_id": 5, "artist_name": "Overgrown", "album_title": "Lay Cold", "artist_state": "existing", "album_state": "existing"}) monkeypatch.setattr(mf, "list_releases", lambda album_id, **kw: [_release(guid="best")]) monkeypatch.setattr(mf, "grab_release", lambda rel, dry_run=False: grabbed.update(guid=rel["guid"]) or True) assert mf.act_lidarr_album(_album_hit(), "/media/music", False, False) is True assert grabbed["guid"] == "best" out = capsys.readouterr().out assert "Overgrown is already in Lidarr." in out assert "download client" in out def test_act_lidarr_album_falls_through_when_no_indexer_has_it(monkeypatch, capsys): monkeypatch.setattr(mf, "ensure_album", lambda *a, **kw: { "album": {"id": 5}, "album_id": 5, "artist_name": "Overgrown", "album_title": "Lay Cold", "artist_state": "added", "album_state": "monitored"}) monkeypatch.setattr(mf, "list_releases", lambda album_id, **kw: []) assert mf.act_lidarr_album(_album_hit(), "/media/music", False, False) is False out = capsys.readouterr().out assert "Added Overgrown to Lidarr." in out assert "Now monitoring" in out def test_act_lidarr_album_uses_the_picked_release(monkeypatch): grabbed = {} monkeypatch.setattr(mf, "ensure_album", lambda *a, **kw: { "album": {"id": 5}, "album_id": 5, "artist_name": "Overgrown", "album_title": "Lay Cold", "artist_state": "existing", "album_state": "existing"}) monkeypatch.setattr(mf, "list_releases", lambda album_id, **kw: [_release(guid="a"), _release(guid="b")]) monkeypatch.setattr(mf, "pick_release", lambda releases: releases[1]) monkeypatch.setattr(mf, "grab_release", lambda rel, dry_run=False: grabbed.update(guid=rel["guid"]) or True) assert mf.act_lidarr_album(_album_hit(), "/media/music", False, False, choose_release=True) is True assert grabbed["guid"] == "b" def test_act_lidarr_album_sends_nothing_when_the_user_quits(monkeypatch): monkeypatch.setattr(mf, "ensure_album", lambda *a, **kw: { "album": {"id": 5}, "album_id": 5, "artist_name": "Overgrown", "album_title": "Lay Cold", "artist_state": "existing", "album_state": "existing"}) monkeypatch.setattr(mf, "list_releases", lambda album_id, **kw: [_release()]) monkeypatch.setattr(mf, "pick_release", lambda releases: None) monkeypatch.setattr(mf, "grab_release", lambda *a, **kw: (_ for _ in ()).throw( AssertionError("must not grab"))) assert mf.act_lidarr_album(_album_hit(), "/media/music", False, False, choose_release=True) is True # --- guards ---------------------------------------------------------------- def test_norm_title_keeps_accented_letters(): assert mf._norm_title("Björk") == "björk" assert mf._norm_title("AC/DC") == "ac dc" def test_base_title_of_an_all_bracket_title_matches_nothing(): assert mf._base_title("(Untitled)") == "" assert mf._match_album([{"id": 1, "title": "(Whatever)"}], {"title": "(Untitled)"}) is None def test_set_album_monitored_refuses_an_album_without_a_library_id(monkeypatch): monkeypatch.setattr(mf, "lidarr_put", lambda *a, **kw: (_ for _ in ()).throw( AssertionError("must not PUT"))) assert mf.set_album_monitored({"title": "Lay Cold"}, False) is False def test_ensure_album_stops_when_lidarr_gives_no_artist_id(monkeypatch): monkeypatch.setattr(mf, "library_artists", lambda: []) monkeypatch.setattr(mf, "add_artist", lambda *a, **kw: {"artistName": "Overgrown"}) monkeypatch.setattr(mf, "_artist_albums", lambda artist_id: (_ for _ in ()).throw( AssertionError("must not list every album"))) res = mf.ensure_album({"title": "Lay Cold", "artist": {"artistName": "Overgrown"}}, "/media/music", False, False) assert res["album"] is None assert res["album_state"] == "missing"