From dcd658291df61482e729f4df05cf06a01e0f5412 Mon Sep 17 00:00:00 2001
From: Harold <8866033@gmail.com>
Date: Sat, 18 Apr 2026 11:22:29 +0800
Subject: [PATCH] feat: add czzy iframe player parsers
---
py/tests/test_czzy.py | 53 ++++++++++++++++++++++++++++++++++
py/厂长资源.py | 66 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+)
diff --git a/py/tests/test_czzy.py b/py/tests/test_czzy.py
index 513f33f..d0318bc 100644
--- a/py/tests/test_czzy.py
+++ b/py/tests/test_czzy.py
@@ -1,8 +1,12 @@
import unittest
+from base64 import b64encode
from importlib.machinery import SourceFileLoader
from pathlib import Path
from unittest.mock import patch
+from Cryptodome.Cipher import AES
+from Cryptodome.Util.Padding import pad
+
ROOT = Path(__file__).resolve().parents[1]
MODULE = SourceFileLoader("czzy_spider", str(ROOT / "厂长资源.py")).load_module()
@@ -147,6 +151,55 @@ class TestCZZYSpider(unittest.TestCase):
self.assertEqual(result["list"][0]["vod_id"], "/movie/example.html")
self.assertEqual(result["list"][0]["vod_name"], "示例影片")
+ def test_extract_iframe_src(self):
+ html = ''
+ self.assertEqual(
+ self.spider._extract_iframe_src(html, "https://www.czzy89.com"),
+ "https://www.czzy89.com/player-v2/test",
+ )
+
+ def test_extract_player_url_prefers_mysvg_then_art_url(self):
+ self.assertEqual(
+ self.spider._extract_player_url_from_iframe("var mysvg='https://video.example/a.m3u8';"),
+ "https://video.example/a.m3u8",
+ )
+ self.assertEqual(
+ self.spider._extract_player_url_from_iframe("art.url='https://video.example/b.m3u8';"),
+ "https://video.example/b.m3u8",
+ )
+
+ def test_extract_player_url_decodes_data_payload(self):
+ original = "https://video.example/data.m3u8"
+ middle = len(original) // 2
+ obfuscated = original[:middle] + "ABCDEFG" + original[middle:]
+ encoded = "".join("{:02x}".format(ord(ch)) for ch in obfuscated)[::-1]
+ html = 'var config = {"data":"%s"};' % encoded
+ self.assertEqual(self.spider._extract_player_url_from_iframe(html), original)
+
+ def test_extract_player_url_decrypts_player_payload(self):
+ payload = '{"url":"https://video.example/encrypted.m3u8"}'
+ key = b"VFBTzdujpR9FWBhe"
+ iv = b"1234567890abcdef"
+ cipher = AES.new(key, AES.MODE_CBC, iv)
+ encrypted = b64encode(cipher.encrypt(pad(payload.encode("utf-8"), AES.block_size))).decode("utf-8")
+ html = 'var player="%s";var rand="%s";' % (encrypted, iv.decode("utf-8"))
+ self.assertEqual(
+ self.spider._extract_player_url_from_iframe(html),
+ "https://video.example/encrypted.m3u8",
+ )
+
+ def test_extract_player_url_supports_wp_nonce_fallback(self):
+ html = """
+
+ """
+ self.assertEqual(
+ self.spider._extract_player_url_from_iframe(html),
+ "https://video.example/wp.m3u8",
+ )
+
if __name__ == "__main__":
unittest.main()
diff --git a/py/厂长资源.py b/py/厂长资源.py
index e1924bf..48da7b7 100644
--- a/py/厂长资源.py
+++ b/py/厂长资源.py
@@ -1,7 +1,13 @@
# coding=utf-8
+import base64
+import json
+import re
import sys
from urllib.parse import quote, urljoin
+from Cryptodome.Cipher import AES
+from Cryptodome.Util.Padding import unpad
+
from base.spider import Spider as BaseSpider
sys.path.append("..")
@@ -209,6 +215,66 @@ class Spider(BaseSpider):
}
return {"list": [vod]}
+ def _extract_iframe_src(self, html, host):
+ match = re.search(r"