文件预览

extract_source_subtitle_frames.py

查看 YouTube Chinese Subtitle Burn-in 技能包中的文件内容。

文件内容

scripts/extract_source_subtitle_frames.py

#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
import shutil
import subprocess
from pathlib import Path


def get_duration(video: Path) -> float:
    result = subprocess.run(
        ["ffprobe", "-v", "error", "-print_format", "json", "-show_format", str(video)],
        check=False,
        text=True,
        capture_output=True,
    )
    if result.returncode != 0:
        raise SystemExit(result.stderr.strip() or "ffprobe failed")
    return float(json.loads(result.stdout).get("format", {}).get("duration") or 0)


def format_name(index: int, seconds: float) -> str:
    total = max(0, int(round(seconds)))
    hh = total // 3600
    mm = (total % 3600) // 60
    ss = total % 60
    return f"source-subtitle-check-{index:02d}-{hh:02d}-{mm:02d}-{ss:02d}.jpg"


def main() -> int:
    parser = argparse.ArgumentParser(description="Extract source-video frames for checking existing burned-in subtitles before choosing subtitle layout.")
    parser.add_argument("video", type=Path)
    parser.add_argument("--out-dir", type=Path, required=True)
    parser.add_argument("--count", type=int, default=5)
    args = parser.parse_args()

    if shutil.which("ffmpeg") is None or shutil.which("ffprobe") is None:
        print("FAIL: ffmpeg and ffprobe are required")
        return 1
    if not args.video.exists():
        print(f"FAIL: missing video {args.video}")
        return 1

    duration = get_duration(args.video)
    if duration <= 0:
        print("FAIL: source video duration is missing or zero")
        return 1
    count = max(3, args.count)
    fractions = [0.08, 0.25, 0.5, 0.75, 0.92]
    if count != 5:
        fractions = [(index + 1) / (count + 1) for index in range(count)]
    times = [min(duration - 0.1, max(0, duration * fraction)) for fraction in fractions]

    args.out_dir.mkdir(parents=True, exist_ok=True)
    for index, seconds in enumerate(times, 1):
        output = args.out_dir / format_name(index, seconds)
        result = subprocess.run(
            [
                "ffmpeg",
                "-y",
                "-ss",
                f"{seconds:.3f}",
                "-i",
                str(args.video),
                "-frames:v",
                "1",
                "-q:v",
                "2",
                str(output),
            ],
            check=False,
            text=True,
            capture_output=True,
        )
        if result.returncode != 0:
            print(result.stderr.strip())
            return 1
        print(f"wrote {output}")
    print(f"PASS: extracted {len(times)} source subtitle check frame(s)")
    print("Review these frames for existing hard subtitles before choosing bilingual mode.")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())