import unittest from importlib.machinery import SourceFileLoader from pathlib import Path from unittest.mock import patch ROOT = Path(__file__).resolve().parents[1] MODULE = SourceFileLoader("youknow_spider", str(ROOT / "youknow.py")).load_module() Spider = MODULE.Spider class TestYouKnowSpider(unittest.TestCase): def setUp(self): self.spider = Spider() self.spider.init() def test_home_content_exposes_expected_categories(self): content = self.spider.homeContent(False) class_ids = [item["type_id"] for item in content["class"]] self.assertEqual(class_ids, ["index", "drama", "movie", "variety", "anime", "short", "doc"]) def test_parse_list_cards_extracts_compact_vod_id(self): html = """
更新至10集
""" cards = self.spider._parse_list_cards(html) self.assertEqual( cards, [ { "vod_id": "1234", "vod_name": "示例影片", "vod_pic": "https://www.youknow.tv/cover.jpg", "vod_remarks": "更新至10集", } ], ) def test_parse_list_cards_prefers_nested_lazyload_original_over_placeholder_src(self): html = """
一念梦离
更新中
""" cards = self.spider._parse_list_cards(html) self.assertEqual(cards[0]["vod_pic"], "https://www.youknow.tv/upload/vod/20260409-1/f1d0233129bc59adb6d2e8fa6396e681.jpg") @patch.object(Spider, "_request_html") def test_home_video_content_uses_today_updates_page(self, mock_request_html): mock_request_html.return_value = """
HD
""" result = self.spider.homeVideoContent() self.assertEqual(result["list"][0]["vod_id"], "111") self.assertEqual(result["list"][0]["vod_name"], "今日更新") @patch.object(Spider, "_request_html") def test_category_content_builds_page_result(self, mock_request_html): mock_request_html.return_value = """
完结
""" result = self.spider.categoryContent("movie", "2", False, {}) self.assertEqual(result["page"], 2) self.assertEqual(mock_request_html.call_args.args[0], "/show/2--------2---/") self.assertEqual(result["list"][0]["vod_id"], "222") @patch.object(Spider, "_request_html") def test_category_content_uses_page1_path_without_page_number(self, mock_request_html): mock_request_html.return_value = """
HD
""" result = self.spider.categoryContent("movie", "1", False, {}) self.assertEqual(mock_request_html.call_args.args[0], "/show/2-----------/") self.assertEqual(result["list"][0]["vod_id"], "555") @patch.object(Spider, "_request_html") def test_search_content_reuses_card_parser(self, mock_request_html): mock_request_html.return_value = """
抢先版
""" result = self.spider.searchContent("繁花", False, "1") self.assertEqual(result["list"][0]["vod_id"], "333") self.assertEqual(result["list"][0]["vod_name"], "搜索影片") def test_parse_detail_page_extracts_fields_and_aligns_episode_sources(self): html = """

示例剧

类型:剧情
地区:大陆
年份:2026
导演:张三
主演:李四王五
语言:国语
备注:更新至2集
简介:

一段剧情简介

第1集 第2集
第1集 第2集
""" result = self.spider._parse_detail_page(html, "888") vod = result["list"][0] self.assertEqual(vod["vod_id"], "888") self.assertEqual(vod["path"], "https://www.youknow.tv/d/888/") self.assertEqual(vod["vod_name"], "示例剧") self.assertEqual(vod["type_name"], "剧情") self.assertEqual(vod["vod_area"], "大陆") self.assertEqual(vod["vod_year"], "2026") self.assertEqual(vod["vod_lang"], "国语") self.assertEqual(vod["vod_remarks"], "更新至2集") self.assertEqual(vod["vod_director"], "张三") self.assertEqual(vod["vod_actor"], "李四,王五") self.assertEqual(vod["vod_content"], "一段剧情简介") self.assertEqual(vod["vod_play_from"], "YouKnowTV") first_episode = vod["vod_play_url"].split("#")[0] self.assertTrue(first_episode.startswith("第1集$")) payload = self.spider._decode_episode_payload(first_episode.split("$", 1)[1]) self.assertEqual(payload["vod_id"], "888") self.assertEqual(payload["episode_index"], 1) self.assertEqual(len(payload["candidates"]), 2) @patch.object(Spider, "_request_html") def test_detail_content_builds_detail_request_url_from_vod_id(self, mock_request_html): mock_request_html.return_value = '

详情影片

第1集
' result = self.spider.detailContent(["123"]) self.assertEqual(mock_request_html.call_args.args[0], "https://www.youknow.tv/d/123/") self.assertEqual(result["list"][0]["vod_id"], "123") def test_extract_player_config_reads_player_aaaa(self): html = '' data = self.spider._parse_player_config(html) self.assertEqual(data["encrypt"], "1") def test_extract_player_config_supports_nested_object_literal(self): html = """ """ data = self.spider._parse_player_config(html) self.assertEqual(data["encrypt"], 2) self.assertEqual(data["vod_data"]["vod_name"], "示例影片") def test_decode_player_url_supports_encrypt_1_and_2(self): self.assertEqual( self.spider._decode_player_url("https%3A%2F%2Fvideo.example%2Fa.m3u8", "1"), "https://video.example/a.m3u8", ) encoded = "aHR0cHMlM0ElMkYlMkZ2aWRlby5leGFtcGxlJTJGYi5tM3U4" self.assertEqual( self.spider._decode_player_url(encoded, "2"), "https://video.example/b.m3u8", ) @patch.object(Spider, "_request_html") def test_player_content_collects_candidates_from_page_and_iframe(self, mock_request_html): payload = self.spider._encode_episode_payload( { "vod_id": "888", "episode_index": 1, "title": "第1集", "candidates": [ {"source": "线路A", "source_id": "1", "episode_url": "https://www.youknow.tv/p/888-1-1/"} ], } ) mock_request_html.side_effect = [ '', 'https://video.example/iframe-final.m3u8', ] result = self.spider.playerContent("YouKnowTV", payload, {}) self.assertEqual(result["parse"], 0) self.assertEqual(result["url"], "https://video.example/page.m3u8") self.assertEqual(result["header"]["Referer"], "https://www.youknow.tv/") @patch.object(Spider, "_request_html") def test_player_content_handles_nested_real_world_player_config(self, mock_request_html): payload = self.spider._encode_episode_payload( { "vod_id": "202774", "episode_index": 1, "title": "HD中字", "candidates": [ {"source": "线路1", "source_id": "1", "episode_url": "https://www.youknow.tv/p/202774-1-1/"} ], } ) mock_request_html.return_value = """ """ result = self.spider.playerContent("YouKnowTV", payload, {}) self.assertEqual(result["parse"], 0) self.assertEqual(result["url"], "https://vip.dytt-network.com/20260325/21334_18856b47/index.m3u8") @patch.object(Spider, "_request_html") def test_player_content_tries_next_candidate_when_first_fails(self, mock_request_html): payload = self.spider._encode_episode_payload( { "vod_id": "888", "episode_index": 1, "title": "第1集", "candidates": [ {"source": "线路A", "source_id": "1", "episode_url": "https://www.youknow.tv/p/888-1-1/"}, {"source": "线路B", "source_id": "2", "episode_url": "https://www.youknow.tv/p/888-2-1/"}, ], } ) mock_request_html.side_effect = [ "empty", "https://video.example/backup.m3u8", ] result = self.spider.playerContent("YouKnowTV", payload, {}) self.assertEqual(result["url"], "https://video.example/backup.m3u8") if __name__ == "__main__": unittest.main()