#!/usr/bin/env python3 """Run MaterialSub dependency and font checks before a long download.""" from __future__ import annotations import argparse import json import shutil import sys from typing import Any, Sequence import burn_subtitles as burn def assess(*, font: str, allow_missing_font: bool, youtube: bool) -> tuple[int, dict[str, Any]]: if sys.version_info < (3, 10): return 2, { "complete": False, "stage": "dependency_required", "error": "Python 3.10 or newer is required", } yt_dlp = shutil.which("yt-dlp") if not yt_dlp: return 2, { "complete": False, "stage": "dependency_required", "error": "yt-dlp was not found in PATH", } try: ffmpeg, ffprobe = burn._required_executables() burn._require_libass_subtitles_filter(ffmpeg) except burn.BurnError as exc: return 2, { "complete": False, "stage": "dependency_required", "error": str(exc), } warnings: list[str] = [] if youtube and not shutil.which("deno"): warnings.append( "Deno was not found; current yt-dlp may expose fewer YouTube formats" ) installed = burn._font_installed(font) if installed is False and not allow_missing_font: return 3, { "complete": False, "stage": "font_decision_required", "font": font, "font_installed": False, "substitution_allowed": False, "instruction": ( "Install the requested font, or rerun preflight and the final burn " "with --allow-missing-font to accept libass substitution" ), "warnings": warnings, } if installed is False: warnings.append(f"Font {font!r} is missing; libass substitution was accepted") elif installed is None: warnings.append(f"Could not verify whether font {font!r} is installed") return 0, { "complete": True, "stage": "preflight_complete", "font": font, "font_installed": installed, "substitution_allowed": bool(installed is False and allow_missing_font), "executables": { "yt_dlp": yt_dlp, "ffmpeg": ffmpeg, "ffprobe": ffprobe, }, "warnings": warnings, } def _parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Check MaterialSub dependencies before downloading.") parser.add_argument("--font", default="MiSans") parser.add_argument("--allow-missing-font", action="store_true") parser.add_argument("--youtube", action="store_true") return parser def main(argv: Sequence[str] | None = None) -> int: args = _parser().parse_args(argv) font = args.font.strip() if not font: print(json.dumps({"complete": False, "error": "font cannot be empty"})) return 2 exit_code, result = assess( font=font, allow_missing_font=args.allow_missing_font, youtube=args.youtube, ) print(json.dumps(result, ensure_ascii=False, sort_keys=True)) return exit_code if __name__ == "__main__": raise SystemExit(main())