How the Claude-Video Download Module Uses yt-dlp for Fetching Videos and Captions
The claude-video download module orchestrates yt-dlp through two dedicated Python functions: fetch_captions() for subtitle-only retrieval and download_url() for full video downloads, both located in skills/watch/scripts/download.py.
The claude-video repository by bradautomates provides a reusable skill for processing video content with Claude. At its core lies a download module that abstracts yt-dlp into clean Python interfaces, handling everything from 720p video extraction to WebVTT subtitle generation. This article breaks down exactly how the module leverages yt-dlp's CLI capabilities through structured subprocess calls.
Overview of the Download Architecture
The download module is designed around a dispatcher pattern. The main entry point, download(), routes requests to specialized handlers based on input type:
- Remote URLs →
download_url()orfetch_captions() - Local file paths →
resolve_local()
This abstraction ensures downstream scripts like watch.py and transcribe.py receive consistent dictionary structures regardless of media source.
Key files in the download pipeline:
| File | Purpose |
|---|---|
skills/watch/scripts/download.py |
Core yt-dlp orchestration |
skills/watch/scripts/watch.py |
Entry point calling download() |
skills/watch/scripts/transcribe.py |
Consumes VTT output from downloads |
skills/watch/scripts/config.py |
Shared configuration defaults |
Fetching Captions Without Video Download
The fetch_captions() function provides lightweight subtitle retrieval when video content already exists or isn't needed. Located at skills/watch/scripts/download.py#L65-L95, this function demonstrates precise yt-dlp flag selection.
Implementation Details
def fetch_captions(url: str, out_dir: Path) -> dict:
"""Download only subtitles for a given URL."""
if not shutil.which("yt-dlp"):
raise RuntimeError("yt-dlp not found")
out_dir.mkdir(parents=True, exist_ok=True)
template = str(out_dir / "video.%(ext)s")
cmd = [
"yt-dlp",
"--skip-download", # Skip video entirely
"--write-subs", # Request manual subtitles
"--write-auto-subs", # Request auto-generated subtitles
"--sub-langs", "en.*", # English language tracks only
"--sub-format", "vtt", # Preferred format
"--convert-subs", "vtt", # Force WebVTT output
"--output", template,
url
]
subprocess.run(cmd, check=True)
return {
"video_path": None,
"subtitle_path": _pick_subtitle(out_dir),
"info": _read_info(out_dir),
"downloaded": False
}
The --skip-download flag is critical here—it prevents any video bytes from transferring while still querying YouTube's subtitle endpoints. The module enforces WebVTT format through dual flags: --sub-format vtt requests VTT from the source, and --convert-subs vtt guarantees conversion if source subtitles exist in SRT or other formats.
The function returns a standardized dictionary with downloaded: False explicitly signaling that no video file was retrieved.
Downloading Video with Optional Captions
For full media retrieval, download_url() at skills/watch/scripts/download.py#L15-L63 constructs a more complex yt-dlp invocation with format selection, parallel downloading, and integrated subtitle handling.
Video Format Selection Strategy
def download_url(url: str, out_dir: Path, audio_only: bool = False) -> dict:
"""Download video/audio with embedded subtitle retrieval."""
if not shutil.which("yt-dlp"):
raise RuntimeError("yt-dlp not found")
out_dir.mkdir(parents=True, exist_ok=True)
template = str(out_dir / "video.%(ext)s")
# Format selector: best 720p video + audio, or audio-only
fmt = "bestaudio/best" if audio_only else "bestvideo[height<=720]+bestaudio/best"
cmd = [
"yt-dlp",
"-N", "8", # 8 parallel fragment downloads
"-f", fmt, # Stream selection
"--merge-output-format", "mp4", # Container normalization
"--write-subs",
"--write-auto-subs",
"--sub-langs", "en.*",
"--sub-format", "vtt",
"--convert-subs", "vtt",
"--no-playlist", # Single video, no playlist expansion
"--ignore-errors", # Continue on non-critical failures
"--output", template,
url
]
subprocess.run(cmd, check=True)
return {
"video_path": _pick_video(out_dir),
"subtitle_path": _pick_subtitle(out_dir),
"info": _read_info(out_dir),
"downloaded": True
}
Key yt-dlp Optimizations
-N 8: Enables multithreaded fragment downloading, significantly improving throughput on high-latency connections.bestvideo[height<=720]+bestaudio: Constrains vertical resolution to 720p, balancing quality against storage and processing overhead for Claude's vision capabilities.--merge-output-format mp4: Normalizes outputs to MP4 container regardless of source codec, ensuring predictable downstream handling.
The audio_only parameter switches the format selector to bestaudio/best, producing M4A or similar audio containers without video streams.
Supporting Utilities and Return Uniformity
Both download functions rely on shared helpers that enforce consistent behavior:
URL Detection and Local File Handling
def is_url(source: str) -> bool:
"""Detect whether input is a remote URL."""
parsed = urllib.parse.urlparse(source)
return bool(parsed.scheme and parsed.netloc)
def resolve_local(path: str) -> dict:
"""Return compatible structure for already-local files."""
path_obj = Path(path).resolve()
return {
"video_path": str(path_obj),
"subtitle_path": None,
"info": {"title": path_obj.stem},
"downloaded": False
}
Post-Processing Helpers
_pick_video(out_dir): Locates the downloaded video file using glob patterns against expected extensions._pick_subtitle(out_dir): Selects the best available VTT file, preferring manual subtitles over auto-generated when multiple English tracks exist._read_info(out_dir): Parsesvideo.info.jsonproduced by yt-dlp's default metadata extraction, surfacing title, duration, uploader, and other metadata.
Unified Dispatch Function
def download(source: str, out_dir: Path, audio_only: bool = False) -> dict:
"""Route to appropriate handler based on source type."""
if is_url(source):
return download_url(source, out_dir, audio_only)
return resolve_local(source)
Practical Usage Examples
Subtitle-Only Retrieval
from pathlib import Path
from skills.watch.scripts.download import fetch_captions
url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
out_dir = Path("/tmp/lecture_captions")
result = fetch_captions(url, out_dir)
print(result["subtitle_path"]) # → /tmp/lecture_captions/video.en.vtt
print(result["info"]["title"]) # → metadata from info.json
Standard Video Download (720p with Captions)
from pathlib import Path
from skills.watch.scripts.download import download
url = "https://www.youtube.com/watch?v=exampleID"
out_dir = Path("/tmp/processed_video")
dl = download(url, out_dir)
print(dl["video_path"]) # → /tmp/processed_video/video.mp4
print(dl["subtitle_path"]) # → /tmp/processed_video/video.en.vtt
print(dl["downloaded"]) # → True
Audio-Only Extraction
from pathlib import Path
from skills.watch.scripts.download import download
url = "https://www.youtube.com/watch?v=podcastID"
out_dir = Path("/tmp/podcast_audio")
dl = download(url, out_dir, audio_only=True)
print(dl["video_path"]) # → /tmp/podcast_audio/video.m4a
Summary
fetch_captions()inskills/watch/scripts/download.pyretrieves WebVTT subtitles without downloading video bytes, using--skip-downloadwith targeted subtitle flags.download_url()handles full media retrieval with 720p format selection, parallel downloads (-N 8), MP4 container normalization, and integrated subtitle fetching.- Return dictionaries maintain consistent structure across all paths, containing
video_path,subtitle_path,infometadata, and booleandownloadedstatus. - Utility functions (
is_url,resolve_local,_pick_video,_pick_subtitle,_read_info) provide input flexibility and post-processing reliability. - The
download()dispatcher enables transparent handling of both remote URLs and local file paths for downstreamwatch.pyandtranscribe.pyoperations.
Frequently Asked Questions
What yt-dlp version requirements exist for claude-video?
The module requires any yt-dlp version supporting --convert-subs and parallel download flags (-N). These have been stable since 2022 releases. The code verifies installation via shutil.which("yt-dlp") but does not enforce specific version checks.
Can the download module fetch non-English subtitles?
As implemented in bradautomates/claude-video, the subtitle language is hardcoded to en.* in both fetch_captions() and download_url(). Modifying --sub-langs to other language codes (e.g., es.*, ja.*) would require editing skills/watch/scripts/download.py directly.
What happens if a video has no available subtitles?
The yt-dlp process completes successfully but produces no VTT files. The _pick_subtitle() helper returns None, which downstream scripts like transcribe.py handle by falling back to Whisper transcription on the audio track.
Why is video resolution capped at 720p?
The format selector bestvideo[height<=720]+bestaudio intentionally limits vertical resolution. This 720p ceiling reduces download time, storage requirements, and processing load for Claude's vision model while maintaining sufficient quality for content comprehension.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →