captube 0.1.0

Turn a YouTube slide-lecture video into a PDF of its unique slides, using ffmpeg keyframes + perceptual dedup.
use anyhow::{Context, Result, bail};
use std::path::{Path, PathBuf};
use std::process::Command;

/// Download a YouTube video with yt-dlp into `workdir`.
/// Returns the path to the downloaded media file.
pub fn fetch_video(url: &str, workdir: &Path) -> Result<PathBuf> {
    let output_tmpl = workdir.join("video.%(ext)s");

    let status = Command::new("yt-dlp")
        .arg("--no-playlist")
        .arg("--no-progress")
        .arg("--quiet")
        // Video-only mp4 at <=720p — audio is irrelevant for slide capture
        // and skipping it avoids the audio download + mux step.
        .arg("-f")
        .arg("bv*[height<=720][ext=mp4]/b[height<=720][ext=mp4]/best[height<=720]")
        // Parallel fragment download where the format supports it.
        .arg("--concurrent-fragments")
        .arg("4")
        .arg("-o")
        .arg(&output_tmpl)
        .arg(url)
        .status()
        .context("failed to invoke yt-dlp; is it installed?")?;

    if !status.success() {
        bail!("yt-dlp exited with status {status}");
    }

    // Find whatever yt-dlp actually wrote.
    for entry in std::fs::read_dir(workdir)? {
        let entry = entry?;
        let p = entry.path();
        if let Some(name) = p.file_name().and_then(|s| s.to_str()) {
            if name.starts_with("video.") {
                return Ok(p);
            }
        }
    }
    bail!("yt-dlp finished but no video file was found in {}", workdir.display())
}