feat: add feikuai player parsing

This commit is contained in:
Harold
2026-04-26 08:52:47 +08:00
parent 6bc012401a
commit 0aa6292d3f
2 changed files with 68 additions and 1 deletions
+27
View File
@@ -116,3 +116,30 @@ class TestFeikuaiSpider(unittest.TestCase):
vod["vod_play_url"],
"第1集$/vodplay/1-1-1.html#第2集$/vodplay/1-1-2.html$$$第1集$/vodplay/1-2-1.html$$$夸克资源$https://pan.quark.cn/s/demo1$$$百度合集$https://pan.baidu.com/s/demo2",
)
def test_base64decode_decodes_fixture(self):
self.assertEqual(
self.spider._base64decode("aHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20vdjIubTN1OA=="),
"https://cdn.example.com/v2.m3u8",
)
@patch.object(Spider, "_request_html")
def test_player_content_supports_encrypt_1_and_encrypt_2(self, mock_request_html):
mock_request_html.side_effect = [
'<script>player_aaaa={"url":"https%3A//cdn.example.com/v1.m3u8","encrypt":"1"}</script>',
'<script>player_aaaa={"url":"aHR0cHM6Ly9jZG4uZXhhbXBsZS5jb20vdjIubTN1OA==","encrypt":"2"}</script>',
]
direct = self.spider.playerContent("feikuai", "/vodplay/1-1-1.html", {})
encoded = self.spider.playerContent("feikuai", "/vodplay/1-1-2.html", {})
self.assertEqual(direct["parse"], 0)
self.assertEqual(direct["url"], "https://cdn.example.com/v1.m3u8")
self.assertEqual(encoded["parse"], 0)
self.assertEqual(encoded["url"], "https://cdn.example.com/v2.m3u8")
@patch.object(Spider, "_request_html")
def test_player_content_falls_back_when_script_missing(self, mock_request_html):
mock_request_html.return_value = "<html><body>empty</body></html>"
result = self.spider.playerContent("feikuai", "/vodplay/1-1-3.html", {})
self.assertEqual(result["parse"], 1)
self.assertEqual(result["jx"], 1)
self.assertEqual(result["url"], "https://feikuai.tv/vodplay/1-1-3.html")
+41 -1
View File
@@ -1,7 +1,9 @@
# coding=utf-8
import base64
import json
import re
import sys
from urllib.parse import quote, urljoin
from urllib.parse import quote, unquote, urljoin
from base.spider import Spider as BaseSpider
@@ -134,6 +136,21 @@ class Spider(BaseSpider):
def _join_group_urls(self, groups):
return "$$$".join("#".join(group) for group in groups if group)
def _base64decode(self, value):
try:
return base64.b64decode(str(value or "")).decode("utf-8")
except Exception:
return ""
def _extract_player_data(self, html):
matched = re.search(r"player_aaaa\s*=\s*(\{[\s\S]*?\})", str(html or ""))
if not matched:
return {}
try:
return json.loads(matched.group(1))
except Exception:
return {}
def categoryContent(self, tid, pg, filter, extend):
page = max(1, int(pg))
url = self.host + f"/vodshow/{tid}--------{page}---.html"
@@ -213,3 +230,26 @@ class Spider(BaseSpider):
"vod_play_url": self._join_group_urls(play_urls),
}
return {"list": [vod]}
def playerContent(self, flag, id, vipFlags):
raw_id = str(id or "")
if raw_id.startswith(("http://", "https://")) and any(
raw_id.lower().split("?")[0].endswith(ext) for ext in [".m3u8", ".mp4", ".flv"]
):
return {"parse": 0, "jx": 0, "url": raw_id}
target = self.host + raw_id
data = self._extract_player_data(self._request_html(target))
raw_url = str(data.get("url") or "")
encrypt = str(data.get("encrypt") or "")
media_url = ""
if encrypt == "1":
media_url = unquote(raw_url)
elif encrypt == "2":
media_url = unquote(self._base64decode(raw_url))
elif raw_url:
media_url = raw_url
if media_url.startswith("http"):
return {"parse": 0, "jx": 0, "url": media_url}
return {"parse": 1, "jx": 1, "url": target}