Files
hugo e27cc22cfb Initial MaterialSub release
Derived from pengchujin/jzsub at 222a90265d2a8797ca258eb1a980cee0863a8311; preserve the upstream MIT license and attribution.
2026-08-25 13:07:03 +08:00

102 lines
3.2 KiB
Python
Executable File

#!/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())