How yt-dlp Integration Handles Video Downloading and Caption Fetching in Claude-Video
The Claude-Video skill uses yt-dlp as its sole external binary to fetch videos and extract English VTT subtitles, orchestrating caption-only metadata retrieval and full media downloads through a unified Python wrapper in skills/watch/scripts/download.py.
The bradautomates/claude-video repository implements a robust yt-dlp integration that isolates all external binary interactions to a single module. This design allows the skill to efficiently retrieve video metadata and subtitles without downloading the actual media file when possible, while gracefully falling back to full video extraction when needed. The integration supports both local file paths and remote URLs, handling format conversion, subtitle language filtering, and error recovery automatically.
Detecting URLs vs. Local Files
The integration first determines whether the user provided a remote URL or a local file path. In skills/watch/scripts/download.py, the is_url function checks if the source string starts with http or https, while resolve_local handles filesystem paths.
def is_url(source: str) -> bool:
return source.startswith(("http://", "https://"))
def resolve_local(path: str) -> dict:
# Returns dict with file path and downloaded=False
return {"video_path": path, "downloaded": False, ...}
When is_url returns False, the skill bypasses yt-dlp entirely and processes the local file directly. This binary-agnostic approach allows the rest of the pipeline to operate identically on both downloaded and locally supplied media.
Fetching Metadata and Captions Without Downloading
For URL-based sources, the skill first attempts to retrieve subtitles without downloading the video file. The watch.py script calls fetch_captions (lines 98-100) to build a yt-dlp command that skips the media download but extracts metadata and subtitles.
The fetch_captions function (lines 65-95 in download.py) constructs a subprocess command with the following flags:
--skip-download– Prevents video retrieval--write-info-json– Saves metadata to a JSON file--write-subsand--write-auto-subs– Captures manual and auto-generated subtitles--sub-langs en.*– Filters for English language tracks only--sub-format vtt --convert-subs vtt– Enforces VTT format output
After execution, helper functions _pick_subtitle and _read_info locate the best VTT file and parse the metadata JSON, returning a dictionary containing the subtitle path (or None) and video information.
from skills.watch.scripts.download import fetch_captions
result = fetch_captions("https://youtube.com/watch?v=...", Path("./work"))
print(result["subtitle_path"]) # Path to VTT file or None
print(result["info"]["title"]) # Video metadata
Full Video and Audio Downloads
When subtitle-only retrieval is insufficient—such as when frame extraction is required—the skill falls back to download (called at lines 120-126 in watch.py). This function delegates to download_url (lines 115-162), which constructs a comprehensive yt-dlp command for media retrieval.
The download_url implementation specifies:
-N 8– Uses up to 8 parallel fragment workers for faster downloads- Format selection limited to 720p video (or
ba/bestaudiowhenaudio_only=True) --merge-output-format mp4– Combines separate video/audio streams into MP4- The same subtitle flags as
fetch_captionsto capture VTT files during download --no-playlist --ignore-errors– Skips playlists and continues on individual errors
After execution, _pick_video locates the downloaded media file while _pick_subtitle extracts the VTT path. The function returns a complete dictionary with video_path, subtitle_path, info metadata, and downloaded=True.
from skills.watch.scripts.download import download
# For video + subtitles
result = download("https://vimeo.com/12345", Path("./work"), audio_only=False)
# For audio-only extraction
audio_result = download("https://youtube.com/...", Path("./work"), audio_only=True)
Error Handling and Edge Cases
The integration handles several failure modes gracefully:
- Missing binary: Both
fetch_captionsanddownload_urlverify yt-dlp existence and exit withSystemExitpointing to installation instructions (e.g.,brew install yt-dlp) - Subtitle failures: HTTP 429 or other subtitle download errors are ignored as long as the video file succeeds (
result.returncodeis not checked for video presence) - No available captions: When
_pick_subtitlefinds no VTT files, it returnsNone; downstream code falls back to Whisper transcription if enabled - Audio-only mode: The format selector switches to best audio, producing an audio file while maintaining the same return structure
The setup.py module validates that both yt-dlp and ffmpeg/ffprobe are installed before the skill attempts any downloads.
Orchestration Flow in watch.py
The high-level flow in skills/watch/scripts/watch.py optimizes for minimal bandwidth:
- Initial check: Create temporary working directory and call
fetch_captionsfor metadata and subtitles - Subtitle parsing: If VTT files exist,
parse_vttconverts them to transcript segments - Conditional download: If subtitles are missing or frames are needed, call
downloadto fetch the actual media - Post-processing: Frame extraction and transcription modules operate on the resulting files
This two-phase approach ensures that simple transcript requests never trigger unnecessary video downloads, while maintaining a consistent interface for downstream processing.
Summary
- Centralized wrapper: All yt-dlp interaction is isolated in
skills/watch/scripts/download.py, making the skill testable and binary-agnostic - Dual-mode operation:
fetch_captionsretrieves metadata without video, whiledownload/download_urlhandles full media extraction with parallel workers and 720p limits - VTT enforcement: Both paths force English subtitles (
en.*) into VTT format and parse them via_pick_subtitle - Resilient design: The integration tolerates missing subtitles, network errors, and missing binaries with clear fallback paths
- Audio support: Setting
audio_only=Trueswitches the format selector to best audio while maintaining identical return structures
Frequently Asked Questions
What happens if yt-dlp is not installed on the system?
The skill checks for the yt-dlp binary at runtime in both fetch_captions and download_url. If the binary is missing, the functions raise SystemExit with a clear message directing the user to install yt-dlp via package managers like brew install yt-dlp or pip install yt-dlp, preventing cryptic failures.
Can I download audio only without fetching the video file?
Yes. Pass audio_only=True to the download function. This switches the yt-dlp format selector from 720p video to ba/bestaudio, downloading only the audio stream while still attempting to retrieve VTT subtitles and metadata. The returned dictionary uses the same keys, with video_path pointing to the audio file.
What subtitle formats does the Claude-Video integration support?
The integration exclusively uses VTT format. Both fetch_captions and download_url pass --sub-format vtt --convert-subs vtt to yt-dlp, ensuring all subtitle tracks (manual and auto-generated) are converted to VTT. The _pick_subtitle helper specifically searches for .vtt files in the output directory.
How does the skill handle videos that have no captions available?
When yt-dlp produces no VTT files, _pick_subtitle returns None for the subtitle_path key. The watch.py orchestration detects this and falls back to Whisper transcription if the user has enabled audio processing. If the operation requires frames or the user disabled transcription, the skill proceeds with video download but marks subtitles as unavailable.
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 →