extract-transcript Skill
When invoked, follow these steps in order. Do not skip steps.
Step 0 — Verify and install dependencies
Check each tool and install if missing. Stop and report clearly if any install fails.
youtube-transcript-api
pip install youtube-transcript-api
Always needed — used in Step 3 to check for an existing YouTube transcript.
yt-dlp
yt-dlp --version
If not found:
pip install yt-dlp
Whisper
whisper --help
If not found:
pip install openai-whisper
Whisper is only used if no YouTube transcript is found in Step 3. Install it regardless — it is fast and needed as a fallback.
ffmpeg
ffmpeg -version
If not found, install via winget (Windows 11):
winget install --id Gyan.FFmpeg -e
If winget fails, stop and tell the user:
"ffmpeg is required but could not be installed automatically. Please download it from https://ffmpeg.org/download.html, extract it, and add the
bin/folder to your system PATH. Then re-run this skill."
python-docx
pip install python-docx
Always needed — used in Step 6 to generate the summary .docx.
After any install, re-verify the tool is available before continuing. If it still fails, stop and report the error.
Step 1 — Get the YouTube URL
If the user already provided a URL in their message, use it. If not, ask:
"Please provide the YouTube URL you'd like to transcribe."
Step 2 — Create the base output folder
Create doc summaries output inside the current working directory if it does not already exist:
mkdir -p "doc summaries output"
The per-video subfolder will be created in Step 3 once the video title is known.
Step 3 — Resolve video title and check for a YouTube transcript
This step does two things in one script:
- Fetches the video title from YouTube metadata (always needed for the subfolder name and filenames).
- Checks whether YouTube already provides a transcript. If yes, saves it to disk and skips audio download entirely.
Write and run this Python script:
import re, os, subprocess, json
from youtube_transcript_api import YouTubeTranscriptApi
from youtube_transcript_api._errors import NoTranscriptFound, TranscriptsDisabled
url = "<URL>"
base_output = "doc summaries output"
# --- Fetch video title ---
meta = subprocess.run(
["yt-dlp", "--dump-json", "--skip-download", url],
capture_output=True, text=True
)
raw_title = json.loads(meta.stdout)["title"]
# Sanitize title for use as a folder/file name (strip Windows-illegal characters)
illegal = r'\/:*?"<>|'
title = "".join(c for c in raw_title if c not in illegal).strip()
# --- Create per-video subfolder ---
video_folder = os.path.join(base_output, title)
os.makedirs(video_folder, exist_ok=True)
# --- Check for YouTube transcript ---
video_id = re.search(r"(?:v=|youtu\.be/)([^&?/]+)", url).group(1)
ytt = YouTubeTranscriptApi()
try:
transcript_list = ytt.list(video_id)
# Prefer manual English captions → auto-generated English → anything available
transcript_obj = None
source = None
for t in transcript_list:
if not t.is_generated and t.language_code.startswith("en"):
transcript_obj = t
source = "manual"
break
if transcript_obj is None:
for t in transcript_list:
if t.is_generated and t.language_code.startswith("en"):
transcript_obj = t
source = "auto-generated"
break
if transcript_obj is None:
transcript_obj = next(iter(transcript_list))
source = "auto-generated" if transcript_obj.is_generated else "manual"
fetched = transcript_obj.fetch()
text = " ".join(entry.text for entry in fetched)
txt_path = os.path.join(video_folder, f"{title}.txt")
with open(txt_path, "w", encoding="utf-8") as f:
f.write(text)
print(f"TRANSCRIPT_FOUND|{source}|{title}|{video_folder}|{txt_path}")
except (NoTranscriptFound, TranscriptsDisabled):
print(f"NO_TRANSCRIPT|{title}|{video_folder}")
except Exception as e:
print(f"NO_TRANSCRIPT|{title}|{video_folder}|error: {e}")
If the output starts with TRANSCRIPT_FOUND:
- Parse:
source,title,video_folder,txt_pathfrom the pipe-delimited output. - Tell the user: "YouTube transcript found ({source}). Skipping audio download and Whisper."
- Skip Steps 4 and 5. Go directly to Step 6.
If the output starts with NO_TRANSCRIPT:
- Parse:
title,video_folderfrom the output. - Tell the user: "No YouTube transcript available — downloading audio and transcribing with Whisper."
- Continue to Step 4.
Step 4 — Download audio
(Only reached if Step 3 found no transcript.)
Download the MP3 directly into the video subfolder resolved in Step 3:
yt-dlp -x --audio-format mp3 "<URL>" -o "doc summaries output/<title>/%(title)s.%(ext)s"
Replace <title> with the sanitized title from Step 3. If yt-dlp reports an error (private video, age-restricted, unavailable), tell the user and stop.
Step 5 — Transcribe
(Only reached if Step 3 found no transcript.)
Find the .mp3 file inside doc summaries output/<title>/. Run Whisper on it, outputting the transcript into the same subfolder:
whisper "doc summaries output/<title>/<filename>.mp3" --output_format txt --output_dir "doc summaries output/<title>" --device cuda
If CUDA is unavailable (no NVIDIA GPU), retry with CPU:
whisper "doc summaries output/<title>/<filename>.mp3" --output_format txt --output_dir "doc summaries output/<title>" --device cpu
Let the user know transcription is running. GPU typically finishes in under a minute; CPU may take several minutes for longer videos.
After Whisper finishes, locate the .txt it created inside the subfolder and set txt_path to that file's full path for use in Step 6.
Step 6 — Generate summary .docx and .txt
Read the transcript from txt_path. Generate two summary files inside doc summaries output/<title>/ using a single Python script:
| File | Purpose |
|---|---|
<title> - Summary.txt |
Plain text — readable in VS Code, easy to copy-paste |
<title> - Summary.docx |
Formatted Word doc — upload to Google Drive to open as a Google Doc |
Both files must contain the same content in these sections:
- Title — video title
- Overview — 2-3 sentence summary of what the video is about
- Detailed Summary — subsections matching the main topics covered in the video
- Key Points — numbered list, each with a bold label (in the .docx) and a 1-2 sentence explanation
- Main Takeaways — bulleted list of the most actionable/important conclusions
- Tools or Concepts Referenced — 2-column table (Name | Description) of every tool, platform, or concept mentioned
Plain text formatting (.txt)
Use plain ASCII so the file is clean in any editor:
================================================
VIDEO TITLE HERE
================================================
OVERVIEW
--------
Paragraph text here.
DETAILED SUMMARY
----------------
Topic Heading
~~~~~~~~~~~~~
Paragraph text here.
KEY POINTS
----------
1. Bold Label — Explanation sentence here.
2. Bold Label — Explanation sentence here.
MAIN TAKEAWAYS
--------------
• Takeaway one
• Takeaway two
TOOLS AND CONCEPTS REFERENCED
------------------------------
Name | Description
----------------------|---------------------------------------------
Tool name | Description here.
Save both files to doc summaries output/<title>/.
Step 7 — Report results
When complete, tell the user:
- The full path of the video subfolder:
<cwd>/doc summaries output/<title>/ - List every file inside it:
<title>.mp3— downloaded audio (only present if Whisper path was taken)<title>.txt— raw transcript<title> - Summary.txt— plain text summary (open in VS Code)<title> - Summary.docx— formatted summary (upload to Google Drive)
- Whether the transcript came from YouTube (manual or auto-generated) or was generated by Whisper.
- Print the first ~300 characters of the raw transcript so the user can verify it looks correct.
- Remind the user they can upload the
.docxto Google Drive and it will open automatically as a Google Doc.
Error handling reference
| Error | Action |
|---|---|
| pip not found | Tell user to install Python from https://www.python.org/downloads/ |
| Private / unavailable video | Tell user yt-dlp cannot download this video |
| ffmpeg not in PATH after install | Instruct user to restart terminal or add ffmpeg to PATH manually |
| Whisper CUDA out of memory | Retry with --model base or --model tiny to reduce VRAM usage |
| Whisper CUDA not available | Retry with --device cpu (will be slower) |
| No audio track / unsupported format | yt-dlp will report this; relay the message to the user |
| youtube-transcript-api import error | Run pip install youtube-transcript-api and retry Step 3 |
| Illegal characters in folder name | The Step 3 script sanitizes the title — if mkdir still fails, strip all non-alphanumeric characters except spaces and dashes |
| yt-dlp title parse fails (empty stdout) | The video may be private or geo-blocked; tell the user and stop |