"""Local-only resolved HLS/VTT + native model smoke; no live requests.""" import base64 import http.server import json from pathlib import Path import subprocess import sys import tempfile import threading from urllib.parse import parse_qs, urlsplit binary = str(Path(sys.argv[1]).resolve()) fixtures = Path(sys.argv[2]).resolve() seen = [] errors = [] class Handler(http.server.BaseHTTPRequestHandler): def log_message(self, *_): pass def transport(self): path = urlsplit(self.path).path try: encoded, suffix = path.lstrip("/").split("/", 1) target, referer = encoded.split("~") def decode(value): raw = base64.urlsafe_b64decode(value + "=" * (-len(value) % 4)) return bytes(byte ^ [1, 2, 3][index % 3] for index, byte in enumerate(raw)).decode() upstream = urlsplit(decode(target)) if not upstream.path.startswith("/transport-"): return False assert decode(referer) == "https://transport.example/" assert self.headers.get("X-Secret") is None and self.headers.get("Referer") is None, "private headers leaked to proxy" except (ValueError, UnicodeError): return False query = parse_qs(upstream.query) if upstream.path.endswith(".m3u8"): assert query == {"skip": ["fixture"]}, "provider query or token-removal rule lost" port = self.server.server_port if upstream.path == "/transport-master.m3u8": def encode(value): raw = value.encode() return base64.urlsafe_b64encode(bytes(byte ^ [1, 2, 3][index % 3] for index, byte in enumerate(raw))).decode().rstrip("=") nested = (f"http://localhost:{port}/" + encode(f"http://127.0.0.1:{port}/transport-variant.m3u8?token=private") + "~" + encode("https://transport.example/") + "/pl.m3u8") data = f"#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH=1\n{nested}\n".encode() elif upstream.path == "/transport-variant.m3u8": data = (f'#EXTM3U\n#EXT-X-KEY:METHOD=AES-128,URI="http://2130706433:{port}/transport-private"\n' '#EXTINF:1,\nhttps://foreign.invalid/transport-segment.bin\n#EXT-X-ENDLIST\n').encode() elif upstream.path == "/transport-segment.bin": assert upstream.hostname == "127.0.0.1", "segment origin rewrite lost" data = bytes(range(256)) else: errors.append("unexpected transport request") self.send_error(403) return True self.send_response(200) self.send_header("Content-Length", str(len(data))) self.end_headers() self.wfile.write(data) return True def do_GET(self): if self.transport(): return path = urlsplit(self.path).path seen.append(path) alternate = path.startswith("/alternate/") captions = path.startswith("/captions/") if alternate or captions: path = "/" + path.split("/", 2)[2] expected = "alternate-private" if alternate else "subtitle-private" if captions or path == "/english.jpeg" else "stream-private" if self.headers.get("X-Resource") != expected: errors.append("wrong resource headers: " + path) self.send_error(403) return if path == "/master.m3u8": query = parse_qs(urlsplit(self.path).query) if query.get("token") != ["fixture"] or (alternate and query.get("rewrite") != ["1"]): errors.append("master token or provider query lost") data = b'#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH=500000\nvariant.m3u8?token=variant\n' elif path == "/variant.m3u8": query = parse_qs(urlsplit(self.path).query) if query.get("token") != ["variant"] or (alternate and query.get("rewrite") != ["1"]): errors.append("variant token or provider query lost") data = (fixtures / "resolved-vod.m3u8").read_bytes() if alternate: data = data.replace(b"resolved-vod-", b"https://invalid.example/alternate/resolved-vod-") elif path == "/english.jpeg": data = (b'WEBVTT\n\n00:00.000 --> 00:10.000\nAlternate English cue\n' if alternate else b'WEBVTT\n\n00:00.000 --> 00:02.000\nFirst English cue\n\n00:02.000 --> 00:04.000\nSecond English cue\n') elif path.startswith("/resolved-vod-") and path.endswith(".ts"): data = (fixtures / path[1:]).read_bytes() else: self.send_error(404) return self.send_response(200) self.send_header("Content-Length", str(len(data))) self.send_header("Content-Type", "text/vtt" if path.endswith(".jpeg") else "application/octet-stream") self.end_headers() self.wfile.write(data) subprocess.run(["ffmpeg", "-hide_banner", "-loglevel", "error", "-y", "-i", str(fixtures / "av.mp4"), "-c:v", "libx264", "-g", "24", "-keyint_min", "24", "-sc_threshold", "0", "-c:a", "aac", "-hls_time", "1", "-hls_playlist_type", "vod", "-hls_segment_filename", str(fixtures / "resolved-vod-%d.ts"), str(fixtures / "resolved-vod.m3u8")], check=True) server = http.server.ThreadingHTTPServer(("127.0.0.1", 0), Handler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() try: base = f"http://127.0.0.1:{server.server_port}" with tempfile.TemporaryDirectory(prefix="terebi-resolved-") as temp: source = Path(temp) / "source.json" progress = Path(temp) / "progress.jsonl" source.write_text(json.dumps({"version": 1, "url": base + "/master.m3u8?token=fixture", "headers": {"X-Resource": "stream-private"}, "identity": {"provider": "miruro", "media_id": "fixture-ID", "episode": 1}, "title": "Local resolved fixture", "subtitles": [{"url": base + "/english.jpeg", "format": "vtt", "language": "en", "label": "English", "default": True, "headers": {"X-Resource": "subtitle-private"}}]})) source.chmod(0o600) subprocess.run([binary, str(source), str(progress)], check=True, timeout=100) records = [json.loads(line) for line in progress.read_text().splitlines()] assert records and all(record["version"] == 2 and record["media_identity"] == {"provider": "miruro", "media_id": "fixture-ID", "episode": 1} for record in records), "stable episode progress identity" assert any(record["completion_eligible"] for record in records), "acknowledged video progress eligible" assert "stream-private" not in progress.read_text() and "token=" not in progress.read_text(), "progress has no transport secrets" assert not errors, errors assert {"/master.m3u8", "/variant.m3u8", "/english.jpeg"}.issubset(seen), "master, nested playlist and external VTT fetched" assert {"/alternate/master.m3u8", "/alternate/english.jpeg"}.issubset(seen), "alternate video host and independent caption provider fetched" assert any(path.endswith(".ts") for path in seen), "media segment fetched" print("PASS: model HLS/VTT playback, independent resource headers, tokens, stable progress") finally: server.shutdown() server.server_close() thread.join()