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()