feat: add feikuai player parsing
This commit is contained in:
@@ -116,3 +116,30 @@ class TestFeikuaiSpider(unittest.TestCase):
|
|||||||
vod["vod_play_url"],
|
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",
|
"第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
@@ -1,7 +1,9 @@
|
|||||||
# coding=utf-8
|
# coding=utf-8
|
||||||
|
import base64
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from urllib.parse import quote, urljoin
|
from urllib.parse import quote, unquote, urljoin
|
||||||
|
|
||||||
from base.spider import Spider as BaseSpider
|
from base.spider import Spider as BaseSpider
|
||||||
|
|
||||||
@@ -134,6 +136,21 @@ class Spider(BaseSpider):
|
|||||||
def _join_group_urls(self, groups):
|
def _join_group_urls(self, groups):
|
||||||
return "$$$".join("#".join(group) for group in groups if group)
|
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):
|
def categoryContent(self, tid, pg, filter, extend):
|
||||||
page = max(1, int(pg))
|
page = max(1, int(pg))
|
||||||
url = self.host + f"/vodshow/{tid}--------{page}---.html"
|
url = self.host + f"/vodshow/{tid}--------{page}---.html"
|
||||||
@@ -213,3 +230,26 @@ class Spider(BaseSpider):
|
|||||||
"vod_play_url": self._join_group_urls(play_urls),
|
"vod_play_url": self._join_group_urls(play_urls),
|
||||||
}
|
}
|
||||||
return {"list": [vod]}
|
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}
|
||||||
|
|||||||
Reference in New Issue
Block a user