76 lines
1.6 KiB
Python
76 lines
1.6 KiB
Python
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})
|