agentsclimarketplace

Youtube transcribe

Skill magnusrodseth/dotfiles/.claude/skills/youtube-transcribe

⚙️ There are many like them, but these dotfiles are mine. A stow-managed macOS setup: Zsh, Neovim, tmux, Ghostty, and a pile of Claude Code tooling.

Install
npx -y skills add magnusrodseth/dotfiles --skill youtube-transcribe

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Transcribe YouTube videos and extract key information using yt-dlp, optionally pulling verified screenshots of the video's visual explanations. Use when the user shares a YouTube URL and wants to transcribe it, summarize it, extract key points, take screenshots or frames from it, or dump learnings from a video. Triggers on YouTube links (youtube.com/watch, youtu.be) combined with requests to "transcribe", "summarize", "watch", "extract", "key points", "notes from this video", "screenshots", "frames", or "what does this video say".

SKILL.md

6.7 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

YouTube Transcribe

Turn a YouTube video into a note. Two tracks: the transcript track (always) and the frame track (when the video teaches visually). Requires yt-dlp and ffmpeg.

Track 1: Transcript

1. Metadata

yt-dlp --print title --print channel --print duration_string --print description "<URL>"

2. Subtitles

Manual subs first (punctuated, higher quality), auto-generated as fallback:

cd "$SCRATCH"   # scratchpad dir, not the vault
yt-dlp --write-sub --sub-lang en --skip-download --sub-format vtt -o "yt" "<URL>"
# nothing written? then:
yt-dlp --write-auto-sub --sub-lang en --skip-download --sub-format vtt -o "yt" "<URL>"

Output: yt.en.vtt. Other languages via --sub-lang no; list them with yt-dlp --list-subs "<URL>".

3. Clean into prose

python3 <skill_dir>/scripts/vtt.py text yt.en.vtt > clean.txt

Use the script, do not hand-roll a sed/awk pipeline. A prior version of this skill inlined awk '!seen[$0]++', and when the skill is invoked with a URL argument the $0 is interpolated with that URL before the agent reads it, so the dedup silently no-ops and every line comes out doubled. The script also decodes &lt;b&gt;-style escaped markup, which a plain tag-stripping sed leaves as literal text.

Then check the transcript is complete before writing anything. Speech runs roughly 130-190 words per minute, so wc -w clean.txt divided by the runtime should land in that band:

wc -w clean.txt   # expect ~130-190 words per minute of runtime

Well under it means content was lost, not that the speaker was slow. Confirm by comparing the last line of clean.txt against the last cue in the VTT (grep -o "^[0-9:.]* --> [0-9:.]*" yt.en.vtt | tail -1); a transcript ending mid-sentence is the tell.

This is not hypothetical. cmd_text used re.findall(r"[^.!?]*[.!?]+", text), which only returns chunks ending in punctuation and silently discards the tail after the final one. Auto-captions carry almost no punctuation, so the pathological case is a single stray period: it stops the or [text] fallback from firing while truncating everything after it. On a 19:40 video whose only period came from "...seagull grade 3." at the 10-minute mark, 51% of the transcript vanished and the output still read as a complete, plausible transcript. Fixed in vtt.py, but keep the check: a half-transcript is invisible in the output and produces a confidently wrong note.

4. Write the note

Summarise in your own words, quote the handful of lines you actually cite, and link into related notes. Do not paste the entire transcript into the note. It bloats the vault, and the synthesis is the thing worth keeping. Keep clean.txt in the scratchpad for the duration of the writing, then let it go.

Track 2: Frames

Worth doing when the video explains things visually: diagrams, on-screen equations, side-by-side comparisons, UI walkthroughs, charts. Skip for talking-head interviews and podcasts, where frames add nothing.

1. Download the video

yt-dlp -f "bv*[height<=1080][ext=mp4]+ba[ext=m4a]/b[height<=1080]" -o "video.mp4" "<URL>"

Run it in the background for anything over ~10 minutes; a 29-minute 1080p video is roughly 160 MB and takes a minute or two.

2. Map concepts to timestamps

Pick the phrases the speaker says at each visual moment, then look them up:

python3 <skill_dir>/scripts/vtt.py find yt.en.vtt \
    "the blades of the pupil" "more grain in the Iso 800" "Priority Modes exist in the center"

Prints 00:03:30 | the blades of the pupil diaphragm opening and closing. for each hit, and reports misses on stderr so a silent miss cannot be mistaken for a match.

3. Extract candidates

Seek a beat or two after the phrase; a graphic usually appears as it is being explained, not on the first syllable.

mkdir -p frames
while IFS='|' read -r ts name; do
  ffmpeg -loglevel error -ss "$ts" -i video.mp4 -frames:v 1 -q:v 2 "frames/$name.jpg" -y
done <<'EOF'
00:03:32|aperture-blades-diaphragm
00:10:14|iso-125-vs-800-grain
EOF

Descriptive kebab-case names describing the content, never frame-01.

4. LOOK at every frame before shipping it

This step is mandatory and is the whole point. Read each extracted image and confirm it actually shows what the transcript implied. Expect roughly one in five to miss: video cuts away, the graphic has not appeared yet, or the speaker is describing a result rather than showing the control.

For each candidate: keep it, re-extract at a shifted timestamp, or drop it.

Never ship an unverified frame, and never caption a frame with a claim it does not support. A wrong screenshot is worse than no screenshot, because a caption lends it false authority. If a concept resists capture after a retry or two, drop it and say so rather than approximating.

5. Save and embed

Into a per-video subdirectory, then embed each frame at the exact claim it supports, with a timestamp in the caption:

![[three-exposure-tiers.jpg]]
*The three prints he opens with (00:10): underexposed, correct, creatively correct.*

For an Obsidian vault: Attachments/<Video Title - Channel>/.

6. Clean up

rm -f video.mp4        # the big one; do not leave 160 MB in the scratchpad

Environment notes

  • Works in Claude Code on the web/mobile as well as locally, provided the environment's setup script installs yt-dlp and ffmpeg and YouTube is on the domain allowlist. Reading frames back uses ordinary image reading, which cloud sessions support.
  • A 403 on the CONNECT verb in cloud is often a transient proxy failure, not an allowlist error. Re-run once before debugging configuration; an allowlist rejection fails deterministically every time.
  • yt-dlp version warnings are safe to ignore. If extraction breaks oddly, update it first, since YouTube changes break old versions regularly.
  • Auto-generated subs lack punctuation and speaker labels; infer from context and say so in the note if the quotes are reconstructed.
  • Do all downloading and extraction in a scratchpad directory. Only verified, named frames belong in the vault.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.