from __future__ import annotations import subprocess from dataclasses import dataclass from pathlib import Path from typing import Any from scripts.video_analysis.error_types import ErrorInfo, make_error @dataclass class _Ok: value: Any def is_ok(self) -> bool: return True def is_err(self) -> bool: return False @dataclass class _Err: err: ErrorInfo def is_ok(self) -> bool: return False def is_err(self) -> bool: return True def ok(value: Any) -> _Ok: return _Ok(value) def err(error: ErrorInfo) -> _Err: return _Err(error) def validate_output_path(path: Path) -> _Ok | _Err: if path.exists() and path.is_dir(): return err(make_error("OutputIsDirectory", "validate_output_path", str(path))) path.parent.mkdir(parents=True, exist_ok=True) return ok(path) def build_ydl_args(url: str, output: Path) -> list[str]: return [ "yt-dlp", "--format", "bestvideo[ext=mp4]/best", "--output", str(output), "--no-warnings", "--quiet", url, ] def download_video(url: str, output: Path) -> _Ok | _Err: validated = validate_output_path(output) if validated.is_err(): return validated completed = subprocess.run( build_ydl_args(url, output), capture_output=True, text=True, ) log_path = output.with_suffix(".log") log_path.write_text( f"# yt-dlp log\n# url: {url}\n# output: {output}\n# returncode: {completed.returncode}\n\nstdout:\n{completed.stdout}\n\nstderr:\n{completed.stderr}\n", encoding="utf-8", ) if completed.returncode != 0: return err(make_error("YtdlpError", "download_video", completed.stderr[:500])) return ok({"output": str(output), "log": str(log_path), "returncode": completed.returncode})