diff --git a/py/tests/test_两个BT.py b/py/tests/test_两个BT.py index 3980333..23d98c2 100644 --- a/py/tests/test_两个BT.py +++ b/py/tests/test_两个BT.py @@ -169,6 +169,28 @@ class TestLiangGeBTSpider(unittest.TestCase): self.assertEqual(self.spider._decode_play_id(first_id)["pid"], "play-1") self.assertEqual(self.spider._decode_play_id(first_id)["sid"], "900") + def test_player_content_passthroughs_direct_media_url(self): + result = self.spider.playerContent("两个BT", "https://media.example/direct.m3u8", {}) + self.assertEqual(result["parse"], 0) + self.assertEqual(result["jx"], 0) + self.assertEqual(result["url"], "https://media.example/direct.m3u8") + self.assertEqual(result["header"]["Referer"], "https://www.bttwoo.com/") + + @patch.object(Spider, "_request_html") + def test_player_content_extracts_media_from_play_page(self, mock_request_html): + mock_request_html.return_value = """ + + """ + play_id = self.spider._encode_play_id("play-100", "900", "第1集") + result = self.spider.playerContent("两个BT", play_id, {}) + self.assertEqual(mock_request_html.call_args.args[0], "https://www.bttwoo.com/v_play/play-100.html") + self.assertEqual(result["parse"], 0) + self.assertEqual(result["jx"], 0) + self.assertEqual(result["url"], "https://media.example/final.mp4") + self.assertEqual(result["header"]["Referer"], "https://www.bttwoo.com/v_play/play-100.html") + if __name__ == "__main__": unittest.main() diff --git a/py/两个BT.py b/py/两个BT.py index af297ad..2ada792 100644 --- a/py/两个BT.py +++ b/py/两个BT.py @@ -79,7 +79,18 @@ class Spider(BaseSpider): return {"list": [detail]} if detail else {"list": []} def playerContent(self, flag, id, vipFlags): - return {"parse": 1, "jx": 1, "playUrl": "", "url": "", "header": {}} + play_id = str(id or "").strip() + if self._is_media_url(play_id): + return self._build_player_result(play_id, self.host + "/") + + meta = self._decode_play_id(play_id) + pid = meta.get("pid") or play_id + play_page_url = self.host + f"/v_play/{pid}.html" + html = self._request_html(play_page_url, referer=self.host + "/") + media_url = self._extract_media_url(html) + if media_url: + return self._build_player_result(media_url, play_page_url) + return self._build_parse_result(play_page_url, play_page_url) def _request_html(self, url, referer=None): headers = dict(self.headers) @@ -238,6 +249,49 @@ class Spider(BaseSpider): text = self._first_text(root, f"//*[contains(text(),'{label}')][1]") return re.sub(rf"^{label}[::]?", "", text).strip() + def _extract_media_url(self, html): + body = str(html or "") + patterns = [ + r'(https?://[^"\'\s<>]+\.(?:m3u8|mp4|flv|avi|mkv|ts)(?:\?[^"\'\s<>]*)?)', + r'"url"\s*:\s*"([^"]+\.(?:m3u8|mp4|flv|avi|mkv|ts)[^"]*)"', + r"'url'\s*:\s*'([^']+\.(?:m3u8|mp4|flv|avi|mkv|ts)[^']*)'", + ] + for pattern in patterns: + matched = re.search(pattern, body, re.I) + if matched: + value = matched.group(1) if matched.groups() else matched.group(0) + return self._abs_url(value) + return "" + + def _is_media_url(self, value): + return bool(re.search(r"\.(?:m3u8|mp4|flv|avi|mkv|ts)(?:\?|#|$)", str(value or ""), re.I)) + + def _build_player_result(self, url, referer): + return { + "parse": 0, + "jx": 0, + "playUrl": "", + "url": str(url or ""), + "header": { + "User-Agent": self.headers["User-Agent"], + "Referer": str(referer or self.host + "/"), + "Origin": self.host, + }, + } + + def _build_parse_result(self, url, referer): + return { + "parse": 1, + "jx": 1, + "playUrl": "", + "url": str(url or ""), + "header": { + "User-Agent": self.headers["User-Agent"], + "Referer": str(referer or self.host + "/"), + "Origin": self.host, + }, + } + def _abs_url(self, value): raw = str(value or "").strip() if not raw: