Use this skill whenever the user wants to turn a video URL or a local video file into local study notes, including reusing existing subtitles when available, transcribing only when no usable subtitle text exists, extracting keyframes, and producing a concise Markdown learning note with embedded screenshots. If the input is a link, run the probe/download flow. If the input is a local video file, skip downloading and work from the local media plus any sidecar subtitle files.
This skill is self-contained under its own skill directory. In this workspace the canonical path is .agent/skills/video-study-notes/, and .codex/skills/video-study-notes/ resolves there as a compatibility symlink.
Reuse the bundled companion skills instead of re-deriving their workflows:
subskills/yt-dlp/SKILL.md for media download, subtitle probing, cookies, and authenticated access.subskills/media-transcribe/SKILL.md when no usable subtitle track is available and a transcription fallback is needed.The main skill keeps only project-wide helpers under scripts/:
scripts/extract_keyframes.pyscripts/prepare_audio.pyscripts/bootstrap_linux.shscripts/check_linux_env.pySubskill-specific helpers live with their subskills:
subskills/yt-dlp/scripts/run_yt_dlp.pysubskills/yt-dlp/scripts/resolve_project_root.pysubskills/media-transcribe/scripts/transcribe_audio.pysubskills/media-transcribe/scripts/find_local_subtitles.pyGiven one video source, build a local note project that:
This skill is intended to run on Linux machines and must use uv to manage the environment stored in the skill-local .venv.
Minimum system dependencies:
python3ffmpeguvRecommended bootstrap flow from the repo root:
cd .agent/skills/video-study-notes
sudo apt install -y python3 python3-venv ffmpeg
bash scripts/bootstrap_linux.sh
.venv/bin/python scripts/check_linux_env.py
Notes:
uv.Before creating any directories, resolve the folder layout first.
subskills/yt-dlp/scripts/resolve_project_root.py to sanitize names and compute the project root.
--output-base, the default base directory is <workspace_root>/output/, where <workspace_root> is the parent directory of the nearest .agent or .codex directory<workspace_root>/output/<Series Title>/<Video Title>/--entry-index for the selected item or pass its title explicitly with --video-title<workspace_root>/output/<Video Title>/Use human-readable names, but strip or replace path separators, control characters, and other filesystem-hostile characters.
Route the workflow from the user's input before doing any heavy work.
subskills/media-transcribe/scripts/find_local_subtitles.pymedia-transcribeAfter choosing the project root, keep everything for that video inside it.
If this is a standalone video:
<workspace_root>/output/<Video Title>/video/<workspace_root>/output/<Video Title>/audio/<workspace_root>/output/<Video Title>/subtitles/<workspace_root>/output/<Video Title>/transcripts/<workspace_root>/output/<Video Title>/keyframes/<workspace_root>/output/<Video Title>/notes.md<workspace_root>/output/<Video Title>/keyframe_timestamps.txtIf this video belongs to a series, add one more level first:
<workspace_root>/output/<Series Title>/<Video Title>/video/<workspace_root>/output/<Series Title>/<Video Title>/audio/<workspace_root>/output/<Series Title>/<Video Title>/subtitles/<workspace_root>/output/<Series Title>/<Video Title>/transcripts/<workspace_root>/output/<Series Title>/<Video Title>/keyframes/<workspace_root>/output/<Series Title>/<Video Title>/notes.md<workspace_root>/output/<Series Title>/<Video Title>/keyframe_timestamps.txtThe user explicitly wants all screenshots under the chosen project root's keyframes/ directory.
subskills/yt-dlp/scripts/resolve_project_root.py before any download step.--entry-index or explicit titles.--entry-index or --video-title to resolve_project_root.py.subskills/yt-dlp/scripts/resolve_project_root.py from the local file path and skip download steps entirely.video/, audio/, subtitles/, transcripts/, and keyframes/ inside that project root.yt-dlp subskill. If the site may require login, make subtitle probes with the same cookies strategy used for subtitle downloads.subskills/media-transcribe/scripts/find_local_subtitles.py.<project_root>/video/.<project_root>/subtitles/ and use them as the primary text source.<project_root>/subtitles/ and use them as the primary text source.<project_root>/audio/ and invoke the media-transcribe subskill to create an SRT transcript under <project_root>/transcripts/.
scripts/prepare_audio.py so the audio artifact lives deterministically under <project_root>/audio/<project_root>/audio/ or point prepare_audio.py at it so the note project stays self-containedscripts/extract_keyframes.py into <project_root>/keyframes/.<project_root>/keyframe_timestamps.txt, one timestamp per line, then run scripts/extract_keyframes.py again with --timestamps-file.<project_root>/notes.md by filling assets/note-template.md as the primary structure. Only diverge when the video clearly requires it.The helper script only extracts candidate frames. It does not score, rank, deduplicate, or select them for you. It does clear stale scene-*.jpg and cue-*.jpg candidates before rewriting those sets, so reruns stay deterministic.
Use the bundled helper script:
cd .agent/skills/video-study-notes
.venv/bin/python scripts/extract_keyframes.py --video "<project_root>/video/example.mp4" --output-dir "<project_root>/keyframes"
After you decide which subtitle/transcript timestamps are important, place them in a text file such as <project_root>/keyframe_timestamps.txt:
12.5
85.0