import server.mf # noqa: F401 import musicfetch_core as mf def test_pure_playlist_url_is_playlist(): assert mf.is_playlist_url("https://music.youtube.com/playlist?list=PLabc") is True assert mf.is_playlist_url("https://www.youtube.com/playlist?list=PLabc") is True def test_watch_with_list_is_not_playlist(): assert mf.is_playlist_url("https://www.youtube.com/watch?v=abc&list=PLx") is False def test_plain_watch_is_not_playlist(): assert mf.is_playlist_url("https://www.youtube.com/watch?v=abc") is False def test_non_url_is_not_playlist(): assert mf.is_playlist_url("Daft Punk - Discovery") is False class _CP: def __init__(self, stdout): self.stdout = stdout self.returncode = 0 def test_expand_playlist_ytdlp_fallback(monkeypatch): import json as _json monkeypatch.setattr(mf, "YTMusic", None) payload = {"title": "My Mix", "entries": [ {"id": "v1", "title": "Song One", "uploader": "Artist A"}, {"id": "v2", "title": "Song Two", "channel": "Artist B"}, {"id": None, "title": "skip"}, ]} monkeypatch.setattr(mf.subprocess, "run", lambda *a, **k: _CP(_json.dumps(payload))) title, hits = mf.expand_playlist("https://www.youtube.com/playlist?list=PLx") assert title == "My Mix" assert [h.payload["videoId"] for h in hits] == ["v1", "v2"] assert hits[0].artist == "Artist A" def test_download_playlist_counts_ok_and_total(monkeypatch): h1 = mf.Hit(source="youtube", kind="track", title="A", artist="X", payload={"videoId": "1"}) h2 = mf.Hit(source="youtube", kind="track", title="B", artist="Y", payload={"videoId": "2"}) h3 = mf.Hit(source="youtube", kind="track", title="C", artist="Z", payload={"videoId": "3"}) monkeypatch.setattr(mf, "expand_playlist", lambda url: ("PL Title", [h1, h2, h3])) monkeypatch.setattr(mf, "act_youtube", lambda hit, root, quality, dry_run: hit.title != "B") ok, total, title = mf.download_playlist("u", "/tmp", "best", False) assert (ok, total, title) == (2, 3, "PL Title") def test_download_playlist_track_exception_counts_as_failure(monkeypatch): h1 = mf.Hit(source="youtube", kind="track", title="A", artist="X", payload={"videoId": "1"}) h2 = mf.Hit(source="youtube", kind="track", title="B", artist="Y", payload={"videoId": "2"}) monkeypatch.setattr(mf, "expand_playlist", lambda url: ("T", [h1, h2])) def fake_act(hit, root, quality, dry_run): if hit.title == "B": raise RuntimeError("boom") return True monkeypatch.setattr(mf, "act_youtube", fake_act) ok, total, _ = mf.download_playlist("u", "/tmp", "best", False) assert (ok, total) == (1, 2) def test_yt_download_returns_true_on_zero_exit(monkeypatch): monkeypatch.setattr(mf.os, "makedirs", lambda *a, **k: None) monkeypatch.setattr(mf.subprocess, "run", lambda *a, **k: _CP("")) assert mf.yt_download("u", "/tmp/x", "best", False) is True def test_yt_download_dry_run_returns_true(monkeypatch): assert mf.yt_download("u", "/tmp/x", "best", True) is True