youtube-transcript by michalparkola/tapestry-skills-for-claude-code
npx skills add https://github.com/michalparkola/tapestry-skills-for-claude-code --skill youtube-transcript此技能通过 yt-dlp 帮助下载 YouTube 视频的字幕(字幕/说明文字)。
当用户出现以下情况时激活此技能:
--write-sub) - 质量最高--write-auto-sub) - 通常可用重要:始终首先检查 yt-dlp 是否已安装:
which yt-dlp || command -v yt-dlp
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
根据系统尝试自动安装:
macOS (Homebrew):
brew install yt-dlp
Linux (apt/Debian/Ubuntu):
sudo apt update && sudo apt install -y yt-dlp
替代方案 (pip - 适用于所有系统):
pip3 install yt-dlp
# 或者
python3 -m pip install yt-dlp
如果安装失败:通知用户需要手动安装 yt-dlp,并提供来自 https://github.com/yt-dlp/yt-dlp#installation 的安装说明。
在尝试下载之前,务必先执行此操作:
yt-dlp --list-subs "YOUTUBE_URL"
这会显示有哪些字幕类型可用,而无需下载任何内容。查找:
首先尝试此方法 - 质量最高,由人工创建:
yt-dlp --write-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
如果手动字幕不可用:
yt-dlp --write-auto-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
两个命令都会创建一个 .vtt 文件(WebVTT 字幕格式)。
仅当手动和自动生成字幕都不可用时使用此方法。
# 获取音频文件大小估算
yt-dlp --print "%(filesize,filesize_approx)s" -f "bestaudio" "YOUTUBE_URL"
# 或者获取时长进行估算
yt-dlp --print "%(duration)s %(title)s" "YOUTUBE_URL"
重要:向用户显示文件大小并询问:“没有可用的字幕。我可以下载音频(大约 X MB)并使用 Whisper 进行转录。您要继续吗?”
等待用户确认后再继续。
command -v whisper
如果未安装,询问用户:“Whisper 未安装。是否使用 pip install openai-whisper 安装?(模型需要约 1-3GB 空间)这是一次性安装。”
等待用户确认后再安装。
如果获得批准则安装:
pip3 install openai-whisper
yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "YOUTUBE_URL"
# 自动检测语言(推荐)
whisper audio_VIDEO_ID.mp3 --model base --output_format vtt
# 或者如果已知语言则指定
whisper audio_VIDEO_ID.mp3 --model base --language en --output_format vtt
模型选项(目前坚持使用 base):
tiny - 最快,准确度最低(约 1GB)base - 良好的平衡(约 1GB)← 使用此选项small - 准确度更好(约 2GB)medium - 非常好(约 5GB)large - 最佳准确度(约 10GB)转录完成后,询问用户:“转录完成!您希望我删除音频文件以节省空间吗?”
如果回答是:
rm audio_VIDEO_ID.mp3
yt-dlp --print "%(title)s" "YOUTUBE_URL"
使用此命令基于视频标题创建有意义的文件名。清理标题以确保文件系统兼容性:
/ 替换为 -$(yt-dlp --print "%(title)s" "URL" | tr '/' '-' | tr ':' '-')YouTube 的自动生成 VTT 文件包含重复行,因为字幕是渐进式显示且时间戳有重叠。在转换为纯文本时,务必在保留原始说话顺序的同时去重。
python3 -c "
import sys, re
seen = set()
with open('transcript.en.vtt', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > transcript.txt
# 获取视频标题
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "YOUTUBE_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
# 查找 VTT 文件
VTT_FILE=$(ls *.vtt | head -n 1)
# 转换并去重
python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > "${VIDEO_TITLE}.txt"
echo "✓ 已保存至: ${VIDEO_TITLE}.txt"
# 清理 VTT 文件
rm "$VTT_FILE"
echo "✓ 已清理临时 VTT 文件"
.vtt):包含时间戳和格式,适用于视频播放器.txt):仅文本内容,适用于阅读或分析{output_name}.{language_code}.vtt(例如 transcript.en.vtt)--write-sub 来获取手动字幕VIDEO_URL="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# 获取视频标题用于文件名
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
OUTPUT_NAME="transcript_temp"
# ============================================
# 步骤 1: 检查 yt-dlp 是否已安装
# ============================================
if ! command -v yt-dlp &> /dev/null; then
echo "未找到 yt-dlp,正在尝试安装..."
if command -v brew &> /dev/null; then
brew install yt-dlp
elif command -v apt &> /dev/null; then
sudo apt update && sudo apt install -y yt-dlp
else
pip3 install yt-dlp
fi
fi
# ============================================
# 步骤 2: 列出可用字幕
# ============================================
echo "正在检查可用字幕..."
yt-dlp --list-subs "$VIDEO_URL"
# ============================================
# 步骤 3: 首先尝试手动字幕
# ============================================
echo "正在尝试下载手动字幕..."
if yt-dlp --write-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "✓ 手动字幕下载成功!"
ls -lh ${OUTPUT_NAME}.*
else
# ============================================
# 步骤 4: 回退到自动生成字幕
# ============================================
echo "手动字幕不可用。正在尝试自动生成字幕..."
if yt-dlp --write-auto-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "✓ 自动生成字幕下载成功!"
ls -lh ${OUTPUT_NAME}.*
else
# ============================================
# 步骤 5: 最后手段 - Whisper 转录
# ============================================
echo "⚠ 此视频没有可用的字幕。"
# 获取文件大小
FILE_SIZE=$(yt-dlp --print "%(filesize_approx)s" -f "bestaudio" "$VIDEO_URL")
DURATION=$(yt-dlp --print "%(duration)s" "$VIDEO_URL")
TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL")
echo "视频: $TITLE"
echo "时长: $((DURATION / 60)) 分钟"
echo "音频大小: ~$((FILE_SIZE / 1024 / 1024)) MB"
echo ""
echo "您希望下载并使用 Whisper 进行转录吗?(y/n)"
read -r RESPONSE
if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then
# 检查 Whisper
if ! command -v whisper &> /dev/null; then
echo "Whisper 未安装。现在安装吗?(需要约 1-3GB 空间)(y/n)"
read -r INSTALL_RESPONSE
if [[ "$INSTALL_RESPONSE" =~ ^[Yy]$ ]]; then
pip3 install openai-whisper
else
echo "没有 Whisper 无法继续。退出。"
exit 1
fi
fi
# 下载音频
echo "正在下载音频..."
yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "$VIDEO_URL"
# 获取实际的音频文件名
AUDIO_FILE=$(ls audio_*.mp3 | head -n 1)
# 转录
echo "正在使用 Whisper 进行转录(这可能需要几分钟)..."
whisper "$AUDIO_FILE" --model base --output_format vtt
# 清理
echo "转录完成!删除音频文件吗?(y/n)"
read -r CLEANUP_RESPONSE
if [[ "$CLEANUP_RESPONSE" =~ ^[Yy]$ ]]; then
rm "$AUDIO_FILE"
echo "音频文件已删除。"
fi
ls -lh *.vtt
else
echo "转录已取消。"
exit 0
fi
fi
fi
# ============================================
# 步骤 6: 转换为可读的纯文本并去重
# ============================================
VTT_FILE=$(ls ${OUTPUT_NAME}*.vtt 2>/dev/null || ls *.vtt | head -n 1)
if [ -f "$VTT_FILE" ]; then
echo "正在转换为可读格式并移除重复项..."
python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > "${VIDEO_TITLE}.txt"
echo "✓ 已保存至: ${VIDEO_TITLE}.txt"
# 清理临时 VTT 文件
rm "$VTT_FILE"
echo "✓ 已清理临时 VTT 文件"
else
echo "⚠ 未找到要转换的 VTT 文件"
fi
echo "✓ 完成!"
注意:此完整工作流程通过适当的错误检查和在每个决策点向用户提示来处理所有场景。
1. yt-dlp 未安装
2. 没有可用的字幕
--write-sub 和 --write-auto-sub3. 无效或私密视频
https://www.youtube.com/watch?v=VIDEO_ID4. Whisper 安装失败
pip3 install openai-whisper”5. 下载中断或失败
--no-check-certificate 重试6. 多种字幕语言
--sub-langs en 仅下载英语--list-subs 列出可用选项--list-subs)每周安装数
273
仓库
GitHub 星标数
297
首次出现
2026年1月20日
安全审计
安装于
opencode242
gemini-cli236
codex236
cursor226
github-copilot220
kimi-cli202
This skill helps download transcripts (subtitles/captions) from YouTube videos using yt-dlp.
Activate this skill when the user:
--write-sub) - highest quality--write-auto-sub) - usually availableIMPORTANT : Always check if yt-dlp is installed first:
which yt-dlp || command -v yt-dlp
Attempt automatic installation based on the system:
macOS (Homebrew) :
brew install yt-dlp
Linux (apt/Debian/Ubuntu) :
sudo apt update && sudo apt install -y yt-dlp
Alternative (pip - works on all systems) :
pip3 install yt-dlp
# or
python3 -m pip install yt-dlp
If installation fails : Inform the user they need to install yt-dlp manually and provide them with installation instructions from https://github.com/yt-dlp/yt-dlp#installation
ALWAYS do this first before attempting to download:
yt-dlp --list-subs "YOUTUBE_URL"
This shows what subtitle types are available without downloading anything. Look for:
Try this first - highest quality, human-created:
yt-dlp --write-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
If manual subtitles aren't available:
yt-dlp --write-auto-sub --skip-download --output "OUTPUT_NAME" "YOUTUBE_URL"
Both commands create a .vtt file (WebVTT subtitle format).
ONLY use this if both manual and auto-generated subtitles are unavailable.
# Get audio file size estimate
yt-dlp --print "%(filesize,filesize_approx)s" -f "bestaudio" "YOUTUBE_URL"
# Or get duration to estimate
yt-dlp --print "%(duration)s %(title)s" "YOUTUBE_URL"
IMPORTANT : Display the file size to the user and ask: "No subtitles are available. I can download the audio (approximately X MB) and transcribe it using Whisper. Would you like to proceed?"
Wait for user confirmation before continuing.
command -v whisper
If not installed, ask user: "Whisper is not installed. Install it with pip install openai-whisper (requires ~1-3GB for models)? This is a one-time installation."
Wait for user confirmation before installing.
Install if approved:
pip3 install openai-whisper
yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "YOUTUBE_URL"
# Auto-detect language (recommended)
whisper audio_VIDEO_ID.mp3 --model base --output_format vtt
# Or specify language if known
whisper audio_VIDEO_ID.mp3 --model base --language en --output_format vtt
Model Options (stick to base for now):
tiny - fastest, least accurate (~1GB)base - good balance (~1GB) ← USE THISsmall - better accuracy (~2GB)medium - very good (~5GB)large - best accuracy (~10GB)After transcription completes, ask user: "Transcription complete! Would you like me to delete the audio file to save space?"
If yes:
rm audio_VIDEO_ID.mp3
yt-dlp --print "%(title)s" "YOUTUBE_URL"
Use this to create meaningful filenames based on the video title. Clean the title for filesystem compatibility:
/ with -$(yt-dlp --print "%(title)s" "URL" | tr '/' '-' | tr ':' '-')YouTube's auto-generated VTT files contain duplicate lines because captions are shown progressively with overlapping timestamps. Always deduplicate when converting to plain text while preserving the original speaking order.
python3 -c "
import sys, re
seen = set()
with open('transcript.en.vtt', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > transcript.txt
# Get video title
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "YOUTUBE_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
# Find the VTT file
VTT_FILE=$(ls *.vtt | head -n 1)
# Convert with deduplication
python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > "${VIDEO_TITLE}.txt"
echo "✓ Saved to: ${VIDEO_TITLE}.txt"
# Clean up VTT file
rm "$VTT_FILE"
echo "✓ Cleaned up temporary VTT file"
.vtt): Includes timestamps and formatting, good for video players.txt): Just the text content, good for reading or analysis{output_name}.{language_code}.vtt (e.g., transcript.en.vtt)--write-sub instead for manual subtitlesVIDEO_URL="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
# Get video title for filename
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
OUTPUT_NAME="transcript_temp"
# ============================================
# STEP 1: Check if yt-dlp is installed
# ============================================
if ! command -v yt-dlp &> /dev/null; then
echo "yt-dlp not found, attempting to install..."
if command -v brew &> /dev/null; then
brew install yt-dlp
elif command -v apt &> /dev/null; then
sudo apt update && sudo apt install -y yt-dlp
else
pip3 install yt-dlp
fi
fi
# ============================================
# STEP 2: List available subtitles
# ============================================
echo "Checking available subtitles..."
yt-dlp --list-subs "$VIDEO_URL"
# ============================================
# STEP 3: Try manual subtitles first
# ============================================
echo "Attempting to download manual subtitles..."
if yt-dlp --write-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "✓ Manual subtitles downloaded successfully!"
ls -lh ${OUTPUT_NAME}.*
else
# ============================================
# STEP 4: Fallback to auto-generated
# ============================================
echo "Manual subtitles not available. Trying auto-generated..."
if yt-dlp --write-auto-sub --skip-download --output "$OUTPUT_NAME" "$VIDEO_URL" 2>/dev/null; then
echo "✓ Auto-generated subtitles downloaded successfully!"
ls -lh ${OUTPUT_NAME}.*
else
# ============================================
# STEP 5: Last resort - Whisper transcription
# ============================================
echo "⚠ No subtitles available for this video."
# Get file size
FILE_SIZE=$(yt-dlp --print "%(filesize_approx)s" -f "bestaudio" "$VIDEO_URL")
DURATION=$(yt-dlp --print "%(duration)s" "$VIDEO_URL")
TITLE=$(yt-dlp --print "%(title)s" "$VIDEO_URL")
echo "Video: $TITLE"
echo "Duration: $((DURATION / 60)) minutes"
echo "Audio size: ~$((FILE_SIZE / 1024 / 1024)) MB"
echo ""
echo "Would you like to download and transcribe with Whisper? (y/n)"
read -r RESPONSE
if [[ "$RESPONSE" =~ ^[Yy]$ ]]; then
# Check for Whisper
if ! command -v whisper &> /dev/null; then
echo "Whisper not installed. Install now? (requires ~1-3GB) (y/n)"
read -r INSTALL_RESPONSE
if [[ "$INSTALL_RESPONSE" =~ ^[Yy]$ ]]; then
pip3 install openai-whisper
else
echo "Cannot proceed without Whisper. Exiting."
exit 1
fi
fi
# Download audio
echo "Downloading audio..."
yt-dlp -x --audio-format mp3 --output "audio_%(id)s.%(ext)s" "$VIDEO_URL"
# Get the actual audio filename
AUDIO_FILE=$(ls audio_*.mp3 | head -n 1)
# Transcribe
echo "Transcribing with Whisper (this may take a few minutes)..."
whisper "$AUDIO_FILE" --model base --output_format vtt
# Cleanup
echo "Transcription complete! Delete audio file? (y/n)"
read -r CLEANUP_RESPONSE
if [[ "$CLEANUP_RESPONSE" =~ ^[Yy]$ ]]; then
rm "$AUDIO_FILE"
echo "Audio file deleted."
fi
ls -lh *.vtt
else
echo "Transcription cancelled."
exit 0
fi
fi
fi
# ============================================
# STEP 6: Convert to readable plain text with deduplication
# ============================================
VTT_FILE=$(ls ${OUTPUT_NAME}*.vtt 2>/dev/null || ls *.vtt | head -n 1)
if [ -f "$VTT_FILE" ]; then
echo "Converting to readable format and removing duplicates..."
python3 -c "
import sys, re
seen = set()
with open('$VTT_FILE', 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
" > "${VIDEO_TITLE}.txt"
echo "✓ Saved to: ${VIDEO_TITLE}.txt"
# Clean up temporary VTT file
rm "$VTT_FILE"
echo "✓ Cleaned up temporary VTT file"
else
echo "⚠ No VTT file found to convert"
fi
echo "✓ Complete!"
Note : This complete workflow handles all scenarios with proper error checking and user prompts at each decision point.
1. yt-dlp not installed
2. No subtitles available
--write-sub and --write-auto-sub3. Invalid or private video
https://www.youtube.com/watch?v=VIDEO_ID4. Whisper installation fails
pip3 install openai-whisper"5. Download interrupted or failed
--no-check-certificate if SSL issues occur6. Multiple subtitle languages
--sub-langs en for English only--list-subs first--list-subs)Weekly Installs
273
Repository
GitHub Stars
297
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode242
gemini-cli236
codex236
cursor226
github-copilot220
kimi-cli202
Skills CLI 使用指南:AI Agent 技能包管理器安装与管理教程
27,400 周安装