Initial MaterialSub release

Derived from pengchujin/jzsub at 222a90265d2a8797ca258eb1a980cee0863a8311; preserve the upstream MIT license and attribution.
This commit is contained in:
2026-08-25 13:07:03 +08:00
commit e27cc22cfb
24 changed files with 7620 additions and 0 deletions
@@ -0,0 +1,214 @@
from __future__ import annotations
import importlib.util
import argparse
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
import threading
import unittest
SCRIPT = Path(__file__).resolve().parents[1] / "scripts" / "ingest_embedded_hls.py"
sys.path.insert(0, str(SCRIPT.parent))
SPEC = importlib.util.spec_from_file_location("ingest_embedded_hls", SCRIPT)
assert SPEC is not None and SPEC.loader is not None
ingest = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(ingest)
class EmbeddedHlsTests(unittest.TestCase):
def test_resource_map_must_be_private(self) -> None:
with tempfile.TemporaryDirectory() as directory:
path = Path(directory) / "resources.json"
path.write_text(json.dumps({"schema_version": 1}), encoding="utf-8")
os.chmod(path, 0o644)
with self.assertRaisesRegex(ingest.IngestError, "chmod 600"):
ingest._read_private_resource_map(path)
os.chmod(path, 0o600)
self.assertEqual(
ingest._read_private_resource_map(path), {"schema_version": 1}
)
def test_private_map_can_be_the_only_job_entry_when_cleanup_is_enabled(self) -> None:
with tempfile.TemporaryDirectory() as directory:
output = Path(directory)
resource_map = output / "resource-map.json"
resource_map.write_text('{"schema_version": 1}', encoding="utf-8")
os.chmod(resource_map, 0o600)
self.assertEqual(
ingest._prepare_output_dir(
output,
resource_map,
resume=False,
cleanup_resource_map=True,
),
output,
)
with self.assertRaisesRegex(ingest.IngestError, "not empty"):
ingest._prepare_output_dir(
output,
resource_map,
resume=False,
cleanup_resource_map=False,
)
def test_authorization_query_only_propagates_to_same_origin(self) -> None:
root = "https://cdn.example/media/video.m3u8?Policy=secret&Key=pair"
same = ingest._authorized_resource_url(
"https://cdn.example/media/segment.ts?part=1", root
)
foreign = ingest._authorized_resource_url(
"https://captions.example/subtitle.vtt", root
)
self.assertIn("part=1", same)
self.assertIn("Policy=secret", same)
self.assertIn("Key=pair", same)
self.assertEqual(foreign, "https://captions.example/subtitle.vtt")
def test_rewrites_segments_and_aes128_key(self) -> None:
root = "https://cdn.example/hls/video.m3u8?Policy=secret"
source = """#EXTM3U
#EXT-X-KEY:METHOD=AES-128,URI="video.key"
#EXTINF:10,
segment-0.ts
#EXT-X-ENDLIST
"""
rewritten = ingest.rewrite_media_playlist(source, root)
self.assertIn(
'URI="https://cdn.example/hls/video.key?Policy=secret"', rewritten
)
self.assertIn(
"https://cdn.example/hls/segment-0.ts?Policy=secret", rewritten
)
def test_rejects_master_playlist(self) -> None:
source = """#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1000000
high.m3u8
"""
with self.assertRaisesRegex(ingest.IngestError, "master playlist"):
ingest.rewrite_media_playlist(source, "https://cdn.example/master.m3u8")
def test_rejects_drm_protection(self) -> None:
source = """#EXTM3U
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="key",KEYFORMAT="com.apple.streamingkeydelivery"
#EXTINF:10,
segment.ts
"""
with self.assertRaisesRegex(ingest.IngestError, "will not bypass DRM"):
ingest.rewrite_media_playlist(source, "https://cdn.example/video.m3u8")
@unittest.skipUnless(
shutil.which("ffmpeg") and shutil.which("ffprobe") and shutil.which("yt-dlp"),
"FFmpeg and yt-dlp are required for the local integration test",
)
def test_local_media_playlist_reaches_standard_translation_stage(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source = root / "source"
output = root / "output"
source.mkdir()
output.mkdir()
subprocess.run(
[
shutil.which("ffmpeg") or "ffmpeg",
"-hide_banner",
"-loglevel",
"error",
"-f",
"lavfi",
"-i",
"color=c=blue:s=320x180:r=24:d=2",
"-f",
"lavfi",
"-i",
"sine=frequency=440:duration=2",
"-c:v",
"libx264",
"-pix_fmt",
"yuv420p",
"-c:a",
"aac",
"-hls_time",
"1",
"-hls_playlist_type",
"vod",
str(source / "media.m3u8"),
],
check=True,
)
(source / "captions.vtt").write_text(
"WEBVTT\n\n00:00:00.000 --> 00:00:01.500\nHello from the test video.\n",
encoding="utf-8",
)
handler = partial(SimpleHTTPRequestHandler, directory=str(source))
server = ThreadingHTTPServer(("127.0.0.1", 0), handler)
server_thread = threading.Thread(target=server.serve_forever, daemon=True)
server_thread.start()
try:
port = server.server_address[1]
resource_map = root / "resource-map.json"
resource_map.write_text(
json.dumps(
{
"schema_version": 1,
"page_url": f"http://127.0.0.1:{port}/page",
"playlist_url": f"http://127.0.0.1:{port}/media.m3u8?Policy=test",
"title": "Embedded test",
"id": "fixture",
"duration_seconds": 2,
"width": 320,
"height": 180,
"subtitle": {
"url": f"http://127.0.0.1:{port}/captions.vtt",
"language": "en",
"kind": "manual",
"label": "English",
"format": "vtt",
},
}
),
encoding="utf-8",
)
os.chmod(resource_map, 0o600)
args = argparse.Namespace(
resource_map=resource_map,
output_dir=output,
target_lang="zh-CN",
deliver="full",
concurrent_fragments=2,
mp4_fallback=False,
resume=False,
cleanup_resource_map=False,
)
exit_code = ingest.execute(args)
self.assertEqual(exit_code, 3)
manifest = json.loads((output / "download-manifest.json").read_text())
self.assertEqual(manifest["status"], "bilingual_required")
self.assertTrue((output / "subtitles" / "subtitle-manifest.json").is_file())
self.assertEqual(
manifest["authentication"]["mode"],
"browser-confirmed-resource-map",
)
finally:
server.shutdown()
server.server_close()
server_thread.join(timeout=5)
if __name__ == "__main__":
unittest.main()