Files
tvboxzt/py/tests/test_金牌.py
T
2026-04-24 16:33:34 +08:00

215 lines
8.5 KiB
Python

import hashlib
import unittest
from importlib.machinery import SourceFileLoader
from pathlib import Path
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
MODULE = SourceFileLoader("jinpai_spider", str(ROOT / "金牌.py")).load_module()
Spider = MODULE.Spider
class TestJinPaiSpider(unittest.TestCase):
def setUp(self):
Spider._instance = None
self.spider = Spider()
self.spider.init()
@patch("jinpai_spider.time.time", return_value=1713952212.345)
def test_signed_headers_generates_expected_hashes(self, _mock_time):
headers = self.spider._signed_headers({"pageNum": "1", "type1": "2"})
expected_t = "1713952212345"
expected_obj = "pageNum=1&type1=2&key=cb808529bae6b6be45ecfab29a4889bc&t=1713952212345"
expected_sign = hashlib.sha1(
hashlib.md5(expected_obj.encode("utf-8")).hexdigest().encode("utf-8")
).hexdigest()
self.assertEqual(headers["t"], expected_t)
self.assertEqual(headers["sign"], expected_sign)
self.assertEqual(headers["Referer"], "https://m.jiabaide.cn/")
@patch.object(Spider, "_fetch_json")
def test_home_content_returns_class_filters_and_hot_list(self, mock_fetch_json):
mock_fetch_json.side_effect = [
{"data": [{"typeId": 1, "typeName": "电影"}, {"typeId": 2, "typeName": "剧集"}]},
{
"data": {
"1": {
"typeList": [{"itemText": "动作", "itemValue": "dongzuo"}],
"plotList": [{"itemText": "剧情"}],
"districtList": [{"itemText": "中国香港"}],
"languageList": [{"itemText": "粤语"}],
"yearList": [{"itemText": "2026"}],
}
}
},
{
"data": [
{
"vodId": 9,
"vodName": "热播片",
"vodPic": "https://img/9.jpg",
"vodRemarks": "更新至10集",
"vodDoubanScore": "8.6",
"vodPubdate": "2026-01-01",
"typeId": 1,
"typeName": "电影",
}
]
},
]
result = self.spider.homeContent(False)
self.assertEqual(
result["class"],
[{"type_id": "1", "type_name": "电影"}, {"type_id": "2", "type_name": "剧集"}],
)
self.assertEqual(result["filters"]["1"][0]["key"], "type")
self.assertEqual(result["filters"]["1"][0]["value"][0], {"n": "全部", "v": ""})
self.assertEqual(result["filters"]["1"][0]["value"][1], {"n": "动作", "v": "dongzuo"})
self.assertEqual(result["filters"]["1"][-1]["key"], "by")
self.assertEqual(result["list"][0]["vod_remarks"], "更新至10集_8.6")
self.assertEqual(result["list"][0]["vod_year"], "2026")
def test_home_video_content_returns_empty_list(self):
self.assertEqual(self.spider.homeVideoContent(), {"list": []})
@patch.object(Spider, "_fetch_json")
def test_category_content_maps_filters_to_api_payload(self, mock_fetch_json):
mock_fetch_json.return_value = {
"data": {
"list": [
{
"vodId": 11,
"vodName": "分类片",
"vodPic": "https://img/11.jpg",
"vodRemarks": "完结",
"vodDoubanScore": "7.1",
"vodPubdate": "2025-09-09",
"typeId": 1,
"typeName": "电影",
}
]
}
}
result = self.spider.categoryContent(
"1",
"2",
False,
{"area": "中国香港", "lang": "粤语", "year": "2025", "by": "4", "type": "dongzuo", "class": "剧情"},
)
self.assertEqual(
mock_fetch_json.call_args.args,
(
"/api/mw-movie/anonymous/video/list",
{
"area": "中国香港",
"lang": "粤语",
"pageNum": "2",
"pageSize": "30",
"sort": "4",
"sortBy": "1",
"type": "dongzuo",
"type1": "1",
"v_class": "剧情",
"year": "2025",
},
),
)
self.assertEqual(result["page"], 2)
self.assertEqual(result["limit"], 30)
self.assertEqual(result["list"][0]["vod_id"], "11")
self.assertNotIn("pagecount", result)
def test_search_content_returns_empty_for_blank_keyword(self):
self.assertEqual(self.spider.searchContent("", False, "1"), {"page": 1, "limit": 30, "total": 0, "list": []})
@patch.object(Spider, "_fetch_json")
def test_search_content_maps_keyword_and_page(self, mock_fetch_json):
mock_fetch_json.return_value = {
"data": {
"list": [
{
"vodId": 21,
"vodName": "搜索片",
"vodPic": "https://img/21.jpg",
"vodRemarks": "更新",
"vodDoubanScore": "8.0",
"vodPubdate": "2024-01-01",
"typeId": 2,
"typeName": "剧集",
}
]
}
}
result = self.spider.searchContent("繁花", False, "3")
self.assertEqual(
mock_fetch_json.call_args.args,
(
"/api/mw-movie/anonymous/video/searchByWordPageable",
{"keyword": "繁花", "pageNum": "3", "pageSize": "30"},
),
)
self.assertEqual(result["page"], 3)
self.assertEqual(result["list"][0]["vod_name"], "搜索片")
self.assertEqual(result["list"][0]["vod_year"], "2024")
@patch.object(Spider, "_fetch_json")
def test_detail_content_maps_metadata_and_episode_ids(self, mock_fetch_json):
mock_fetch_json.return_value = {
"data": {
"vodId": 88,
"vodName": "详情片",
"vodPic": "https://img/88.jpg",
"vodClass": "动作",
"vodRemarks": "更新至12集",
"vodYear": "2026",
"vodArea": "中国香港",
"vodLang": "粤语",
"vodDirector": "导演甲",
"vodActor": "演员甲/演员乙",
"vodContent": "一段简介",
"episodeList": [{"name": "第1集", "nid": 9001}, {"name": "第2集", "nid": 9002}],
}
}
result = self.spider.detailContent(["88"])
vod = result["list"][0]
self.assertEqual(mock_fetch_json.call_args.args, ("/api/mw-movie/anonymous/video/detail", {"id": "88"}))
self.assertEqual(vod["vod_id"], "88")
self.assertEqual(vod["vod_name"], "详情片")
self.assertEqual(vod["vod_play_from"], "金牌线路")
self.assertEqual(vod["vod_play_url"], "第1集$88@9001#第2集$88@9002")
def test_detail_content_returns_empty_for_blank_id(self):
self.assertEqual(self.spider.detailContent([""]), {"list": []})
@patch.object(Spider, "_fetch_json")
def test_player_content_returns_first_episode_url_with_headers(self, mock_fetch_json):
mock_fetch_json.return_value = {
"data": {
"list": [
{"name": "1080P", "url": "https://cdn.example/1080.m3u8"},
{"name": "720P", "url": "https://cdn.example/720.m3u8"},
]
}
}
result = self.spider.playerContent("金牌线路", "88@9001", {})
self.assertEqual(
mock_fetch_json.call_args.args,
("/api/mw-movie/anonymous/v2/video/episode/url", {"clientType": "3", "id": "88", "nid": "9001"}),
)
self.assertEqual(
result,
{
"parse": 0,
"playUrl": "",
"url": "https://cdn.example/1080.m3u8",
"header": {"User-Agent": self.spider.mobile_ua},
},
)
def test_player_content_rejects_broken_play_id(self):
self.assertEqual(
self.spider.playerContent("金牌线路", "broken", {}),
{"parse": 0, "playUrl": "", "url": "", "header": {}},
)