import json import unittest from pathlib import Path from unittest.mock import patch FIXTURES_DIR = Path(__file__).resolve().parent / "fixtures" def load_fixture(name: str) -> str: return (FIXTURES_DIR / name).read_text(encoding="utf-8") class CollectorParsingTests(unittest.TestCase): def test_netease_playlist_square_parser_extracts_playlist_candidates(self): from musicdl.catalogsync.collectors.netease import parse_playlist_square_html items = parse_playlist_square_html(load_fixture("netease_playlist_square.html")) self.assertEqual(2, len(items)) self.assertEqual("netease", items[0].platform) self.assertEqual("7583298906", items[0].remote_id) self.assertEqual("playlist_url", items[0].parse_strategy) self.assertEqual("https://music.163.com/#/playlist?id=7583298906", items[0].url) self.assertEqual(1230000, items[0].play_count) self.assertEqual(4567, items[1].play_count) def test_netease_toplist_parser_extracts_playlist_style_rankings(self): from musicdl.catalogsync.collectors.netease import parse_toplist_payload items = parse_toplist_payload(json.loads(load_fixture("netease_toplist.json"))) self.assertEqual(2, len(items)) self.assertEqual("19723756", items[0].remote_id) self.assertEqual("netease_toplist", items[0].parse_strategy) self.assertEqual("https://music.163.com/#/playlist?id=19723756", items[0].url) self.assertEqual(7654321, items[0].play_count) self.assertEqual(345678, items[1].play_count) def test_qq_playlist_square_parser_extracts_playlist_candidates(self): from musicdl.catalogsync.collectors.qq import parse_playlist_square_payload items = parse_playlist_square_payload(json.loads(load_fixture("qq_playlist_square.json"))) self.assertEqual(2, len(items)) self.assertEqual("qq", items[0].platform) self.assertEqual("7707261125", items[0].remote_id) self.assertEqual("playlist_url", items[0].parse_strategy) self.assertEqual("https://y.qq.com/n/ryqq/playlist/7707261125", items[0].url) def test_qq_playlist_square_parser_extracts_collected_song_count_when_present(self): from musicdl.catalogsync.collectors.qq import parse_playlist_square_payload payload = { "data": { "list": [ { "dissid": "7707261125", "dissname": "QQ Count Playlist", "songnum": 42, "creator": {"name": "Collector"}, } ] } } items = parse_playlist_square_payload(payload) self.assertEqual(1, len(items)) self.assertEqual(42, items[0].collected_song_count) def test_qq_toplist_parser_marks_entries_for_special_detail_resolution(self): from musicdl.catalogsync.collectors.qq import parse_toplist_payload items = parse_toplist_payload(json.loads(load_fixture("qq_toplist.json"))) self.assertEqual(2, len(items)) self.assertEqual("4", items[0].remote_id) self.assertEqual("qq_toplist", items[0].parse_strategy) self.assertEqual("https://y.qq.com/n/ryqq/toplist/4", items[0].url) def test_kuwo_playlist_square_parser_extracts_ssr_playlist_links(self): from musicdl.catalogsync.collectors.kuwo import parse_playlist_square_html items = parse_playlist_square_html(load_fixture("kuwo_playlist_square.html")) self.assertEqual(2, len(items)) self.assertEqual("kuwo", items[0].platform) self.assertEqual("3694434192", items[0].remote_id) self.assertEqual("playlist_url", items[0].parse_strategy) self.assertEqual("https://www.kuwo.cn/playlist_detail/3694434192", items[0].url) self.assertEqual(3215000, items[0].play_count) self.assertEqual(6789, items[1].play_count) def test_kuwo_toplist_parser_extracts_rank_entries_from_ssr_state(self): from musicdl.catalogsync.collectors.kuwo import parse_toplist_html items = parse_toplist_html(load_fixture("kuwo_toplist.html")) self.assertEqual(2, len(items)) self.assertEqual("489927", items[0].remote_id) self.assertEqual("kuwo_toplist", items[0].parse_strategy) self.assertEqual("16", items[0].metadata["sourceid"]) self.assertEqual("https://www.kuwo.cn/rankList?bangId=489927", items[0].url) self.assertEqual(1234567, items[0].play_count) self.assertEqual(765432, items[1].play_count) def test_kuwo_toplist_parser_can_fallback_without_node(self): from musicdl.catalogsync.collectors.kuwo import parse_toplist_html with patch("musicdl.catalogsync.collectors.kuwo.subprocess.run", side_effect=RuntimeError("node missing")): items = parse_toplist_html(load_fixture("kuwo_toplist.html")) self.assertEqual(2, len(items)) self.assertEqual("489927", items[0].remote_id) self.assertEqual("16", items[0].metadata["sourceid"]) self.assertEqual(1234567, items[0].play_count) if __name__ == "__main__": unittest.main()