关于 clip-hand-skill
clip-hand-skill 是视频剪辑与处理参考技能,面向需要下载、转录和加工视频的创作者。内容涵盖字幕制作、画面裁剪、音频处理及多平台命令行用法。
主要功能
- 01yt-dlp 视频下载与元数据检查
- 02Whisper 转录及词级时间戳
- 03SRT 与 ASS 字幕生成
- 04FFmpeg 剪辑、裁剪和字幕烧录
- 05视频缩略图与场景分析
适用场景
- 01从在线视频提取片段
- 02为视频生成并嵌入字幕
- 03制作竖屏短视频
- 04分析静音段和场景切换
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rightnow-ai/ openfang --skill clip-hand-skill安装后在 Claude Code 中输入/clip-hand-skill确认已加载。
附带文件HAND.toml
详细介绍
视频剪辑专家知识
跨平台说明
所有工具(ffmpeg、ffprobe、yt-dlp、whisper)在 Windows、macOS 和 Linux 上都使用相同的 CLI 参数。差异仅在于 shell 语法:
| 功能 | macOS / Linux | Windows (cmd.exe) |
|---|---|---|
| 屏蔽 stderr | 2>/dev/null | 2>NUL |
| 筛选输出 | | grep pattern | | findstr pattern |
| 删除文件 | rm file1 file2 | del file1 file2 |
| 空输出设备 | -f null - | -f null -(相同) |
| ffmpeg 字幕路径 | subtitles=clip.srt | subtitles=clip.srt(相对路径可用,绝对路径需要 C\\:/path) |
重要:ffmpeg 滤镜路径(-vf "subtitles=...")始终需要使用正斜杠。在 Windows 上使用绝对路径时,请转义冒号:subtitles=C\\:/Users/me/clip.srt
创建 SRT/文本文件时,优先使用 file_write 工具,而不是 shell echo/heredoc。
yt-dlp 参考
选择格式下载
# Best video up to 1080p + best audio, merged
yt-dlp -f "bv[height<=1080]+ba/b[height<=1080]" --restrict-filenames -o "source.%(ext)s" "URL"
# 720p max (smaller, faster)
yt-dlp -f "bv[height<=720]+ba/b[height<=720]" --restrict-filenames -o "source.%(ext)s" "URL"
# Audio only (for transcription-only workflows)
yt-dlp -x --audio-format wav --restrict-filenames -o "audio.%(ext)s" "URL"
检查元数据
# Get full metadata as JSON (duration, title, chapters, available subs)
yt-dlp --dump-json "URL"
# Key fields: duration, title, description, chapters, subtitles, automatic_captions
YouTube 自动字幕
# Download auto-generated subtitles in json3 format (word-level timing)
yt-dlp --write-auto-subs --sub-lang en --sub-format json3 --skip-download --restrict-filenames -o "source" "URL"
# Download manual subtitles if available
yt-dlp --write-subs --sub-lang en --sub-format srt --skip-download --restrict-filenames -o "source" "URL"
# List available subtitle languages
yt-dlp --list-subs "URL"
常用参数
--restrict-filenames— 使用安全的 ASCII 文件名(不含空格/特殊字符)——在所有平台上都很重要--no-playlist— 即使 URL 属于播放列表,也只下载单个视频-o "template.%(ext)s"— 输出模板(%(ext)s 会自动检测格式)--cookies-from-browser chrome— 使用浏览器 Cookie 处理年龄限制内容--extract-audio/-x— 仅提取音频--audio-format wav— 将音频转换为 wav(供 whisper 使用)
Whisper 转录参考
为 Whisper 提取音频
# Extract mono 16kHz WAV (whisper's preferred input format)
ffmpeg -i source.mp4 -vn -ar 16000 -ac 1 -y audio.wav
基本转录
# Standard transcription with word-level timestamps
whisper audio.wav --model small --output_format json --word_timestamps true --language en
# Faster alternative (same flags, 4x speed)
whisper-ctranslate2 audio.wav --model small --output_format json --word_timestamps true --language en
模型大小
| 模型 | VRAM | 速度 | 质量 | 适用场景 |
|---|---|---|---|---|
| tiny | ~1GB | 最快 | 粗略 | 快速预览、测试流程 |
| base | ~1GB | 快 | 尚可 | 短片段、清晰语音 |
| small | ~2GB | 良好 | 良好 | 默认——最佳平衡 |
| medium | ~5GB | 慢 | 更好 | 重要内容、有口音的语音 |
| large-v3 | ~10GB | 最慢 | 最佳 | 最终成品、多种语言 |
注意:在 macOS Apple Silicon 上,可考虑使用 mlx-whisper,这是更快速的原生替代方案。
JSON 输出结构
{
"text": "full transcript text...",
"segments": [
{
"id": 0,
"start": 0.0,
"end": 4.52,
"text": " Hello everyone, welcome back.",
"words": [
{"word": " Hello", "start": 0.0, "end": 0.32, "probability": 0.95},
{"word": " everyone,", "start": 0.32, "end": 0.78, "probability": 0.91},
{"word": " welcome", "start": 0.78, "end": 1.14, "probability": 0.98},
{"word": " back.", "start": 1.14, "end": 1.52, "probability": 0.97}
]
}
]
}
- 当使用
--word_timestamps true时,segments[].words[]会提供单词级时间戳 probability表示置信度(< 0.5 = 可能有误)
解析 YouTube json3 字幕
格式结构
{
"events": [
{
"tStartMs": 1230,
"dDurationMs": 5000,
"segs": [
{"utf8": "hello ", "tOffsetMs": 0},
{"utf8": "world ", "tOffsetMs": 200},
{"utf8": "how ", "tOffsetMs": 450},
{"utf8": "are you", "tOffsetMs": 700}
]
}
]
}
提取单词时间戳
对于每个事件及其中的每个片段:
word_start_ms = event.tStartMs + seg.tOffsetMsword_start_secs = word_start_ms / 1000.0word_text = seg.utf8.trim()
没有 segs 的事件是换行或格式标记——跳过。
包含的 segs 仅为 "\n" 的事件是换行——跳过。
根据转录内容生成 SRT
SRT 格式
1
00:00:00,000 --> 00:00:02,500
First line of caption text
2
00:00:02,500 --> 00:00:05,100
Second line of caption text
编写优质 SRT 的规则
- 将单词分组为每行约 8-12 个单词的字幕(每行 2-3 秒)
- 在自然停顿处断句(句号、逗号、从句边界)
- 每行控制在 42 个字符以内,以便在移动设备上阅读
- 根据片段起始时间调整时间戳(从所有时间戳中减去片段起始时间)
- 时间戳格式:
HH:MM:SS,mmm(使用逗号分隔,而非句点) - 每个条目包含:索引行、时间戳行、文本行、空行
- 使用
file_write工具创建 SRT 文件——在所有平台上的行为都相同
使用 ASS 格式制作样式化字幕
制作动画/样式化字幕时,请使用 ASS 字幕格式,而不是 SRT:
ffmpeg -i clip.mp4 -vf "subtitles=clip.ass:force_style='FontSize=22,FontName=Arial,Bold=1,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Shadow=1,Alignment=2,MarginV=40'" -c:a copy output.mp4
ASS 样式关键属性:
PrimaryColour=&H00FFFFFF— 白色文字(AABBGGRR 格式)OutlineColour=&H00000000— 黑色描边Outline=2— 描边粗细Alignment=2— 底部居中MarginV=40— 距底边的边距FontSize=22— 适用于 1080x1920 竖屏的合适字号
FFmpeg 视频处理
场景检测
ffmpeg -i input.mp4 -filter:v "select='gt(scene,0.3)',showinfo" -f null - 2>&1
- 阈值 0.1 = 非常灵敏,0.5 = 仅检测主要切换
- 从 showinfo 输出中解析
pts_time:获取时间戳 - 在 macOS/Linux 上通过
grep showinfo传递管道,在 Windows 上通过findstr showinfo传递管道
静音检测
ffmpeg -i input.mp4 -af "silencedetect=noise=-30dB:d=1.5" -f null - 2>&1
d=1.5= 至少 1.5 秒的静音- 在输出中查找
silence_start和silence_end
剪辑提取
# Re-encoded (accurate cuts)
ffmpeg -ss 00:01:30 -to 00:02:15 -i input.mp4 -c:v libx264 -c:a aac -preset fast -crf 23 -movflags +faststart -y clip.mp4
# Lossless copy (fast but may have keyframe alignment issues)
ffmpeg -ss 00:01:30 -to 00:02:15 -i input.mp4 -c copy -y clip.mp4
- 将
-ss放在-i前 = 快速定位(提取时推荐使用) -to= 结束时间戳,-t= 时长
竖屏视频(Shorts/Reels/TikTok 使用 9:16)
# Center crop (when source is 16:9)
ffmpeg -i input.mp4 -vf "crop=ih*9/16:ih:(iw-ih*9/16)/2:0,scale=1080:1920" -c:a copy output.mp4
# Scale with letterbox padding (preserves full frame)
ffmpeg -i input.mp4 -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" -c:a copy output.mp4
烧录字幕
# SRT subtitles with styling (use relative path or forward-slash absolute path)
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=22,FontName=Arial,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Alignment=2,MarginV=40'" -c:a copy output.mp4
# Simple text overlay
ffmpeg -i input.mp4 -vf "drawtext=text='Caption':fontsize=48:fontcolor=white:borderw=3:bordercolor=black:x=(w-text_w)/2:y=h-th-40" output.mp4
Windows 路径转义:subtitles=C\\:/Users/me/subs.srt(冒号前使用双反斜杠)
生成缩略图
# At specific time (2 seconds in)
ffmpeg -i input.mp4 -ss 2 -frames:v 1 -q:v 2 -y thumb.jpg
# Best keyframe
ffmpeg -i input.mp4 -vf "select='eq(pict_type,I)',scale=1280:720" -frames:v 1 thumb.jpg
# Contact sheet
ffmpeg -i input.mp4 -vf "fps=1/10,scale=320:-1,tile=4x4" contact.jpg
视频分析
# Full metadata (JSON)
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
# Duration only
ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp4
# Resolution
ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 input.mp4
基于 API 的语音转文字参考
Groq Whisper API
最快的云端语音转文字服务,使用运行于 Groq 硬件上的 whisper-large-v3。提供免费套餐。
curl -s -X POST "https://api.groq.com/openai/v1/audio/transcriptions" \
-H "Authorization: Bearer $GROQ_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "[email protected]" \
-F "model=whisper-large-v3" \
-F "response_format=verbose_json" \
-F "timestamp_granularities[]=word" \
-o transcript_raw.json
响应:{"text": "...", "words": [{"word": "hello", "start": 0.0, "end": 0.32}]}
- 文件大小上限:25MB。对于更长的音频,请先使用 ffmpeg 分割。
- 单词级时间戳需要
timestamp_granularities[]=word。
OpenAI Whisper API
curl -s -X POST "https://api.openai.com/v1/audio/transcriptions" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "[email protected]" \
-F "model=whisper-1" \
-F "response_format=verbose_json" \
-F "timestamp_granularities[]=word" \
-o transcript_raw.json
响应格式与 Groq 相同。上限为 25MB。
Deepgram Nova-2
curl -s -X POST "https://api.deepgram.com/v1/listen?model=nova-2&smart_format=true&utterances=true&punctuate=true" \
-H "Authorization: Token $DEEPGRAM_API_KEY" \
-H "Content-Type: audio/wav" \
--data-binary @audio.wav \
-o transcript_raw.json
响应:{"results": {"channels": [{"alternatives": [{"words": [{"word": "hello", "start": 0.0, "end": 0.32, "confidence": 0.99}]}]}]}}
- 支持流式处理,但处理剪辑时请使用批量模式。
smart_format=true会添加标点并调整大小写。
TTS 参考
Edge TTS(免费,无需 API 密钥)
# List available voices
edge-tts --list-voices
# Generate speech
edge-tts --text "Your caption text here" --voice en-US-AriaNeural --write-media tts_output.mp3
# Other good voices: en-US-GuyNeural, en-GB-SoniaNeural, en-AU-NatashaNeural
安装:pip install edge-tts
OpenAI TTS
curl -s -X POST "https://api.openai.com/v1/audio/speech" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"tts-1","input":"Your text here","voice":"alloy"}' \
--output tts_output.mp3
语音:alloy、echo、fable、onyx、nova、shimmer
模型:tts-1(快速)、tts-1-hd(高质量)
ElevenLabs
curl -s -X POST "https://api.elevenlabs.io/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM" \
-H "xi-api-key: $ELEVENLABS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Your text here","model_id":"eleven_monolingual_v1"}' \
--output tts_output.mp3
语音 ID 21m00Tcm4TlvDq8ikWAM = Rachel(默认)。列出语音:GET /v1/voices
音频合并(TTS + 原始音频)
# Mix TTS over original audio (original at 30% volume, TTS at 100%)
ffmpeg -i clip.mp4 -i tts.mp3 \
-filter_complex "[0:a]volume=0.3[orig];[1:a]volume=1.0[tts];[orig][tts]amix=inputs=2:duration=first[out]" \
-map 0:v -map "[out]" -c:v copy -c:a aac -y clip_voiced.mp4
# Replace audio entirely (no original audio)
ffmpeg -i clip.mp4 -i tts.mp3 -map 0:v -map 1:a -c:v copy -c:a aac -shortest -y clip_voiced.mp4
质量与性能提示
- 快速预览时使用
-preset ultrafast,生成最终输出时使用-preset slow - 使用
-crf 23可获得良好质量(18 = 高,28 = 低,数值越低 = 文件越大) - 添加
-movflags +faststart,以生成适合网络播放的 MP4 - 使用
-threads 0自动检测 CPU 核心数 - 始终使用
-y,以覆盖文件而不询问
Telegram Bot API 参考
sendVideo — 上传视频并发送到聊天或频道
curl -s -X POST "https://api.telegram.org/bot<BOT_TOKEN>/sendVideo" \
-F "chat_id=<CHAT_ID>" \
-F "video=@clip_N_final.mp4" \
-F "caption=Clip title here" \
-F "parse_mode=HTML" \
-F "supports_streaming=true"
参数
| 参数 | 必填 | 描述 |
|---|---|---|
chat_id | 是 | 频道(-100XXXXXXXXXX 或 @channelname)、群组或用户的数字 ID |
video | 是 | 使用 @filepath 上传(最大 50MB),或使用 Telegram file_id 重新发送 |
caption | 否 | 文本说明,最多 1024 个字符 |
parse_mode | 否 | 使用 HTML 或 MarkdownV2 设置说明文本样式 |
supports_streaming | 否 | true 启用渐进式播放 |
成功响应
{"ok": true, "result": {"message_id": 1234, "video": {"file_id": "BAACAgI...", "file_size": 5242880}}}
错误响应
{"ok": false, "error_code": 400, "description": "Bad Request: chat not found"}
常见错误
| 错误代码 | 描述 | 解决方法 |
|---|---|---|
| 400 | 未找到聊天 | 验证 chat_id;必须将机器人添加到频道或群组 |
| 401 | 未授权 | 机器人令牌无效或已撤销 — 通过 @BotFather 重新生成 |
| 413 | 请求实体过大 | 文件超过 50MB — 重新编码:ffmpeg -i input.mp4 -fs 49M -c:v libx264 -crf 28 -preset fast -c:a aac -y output.mp4 |
| 429 | 请求过多 | 触发速率限制 — 等待响应中的 retry_after 秒 |
文件大小限制
通过 Bot API 上传视频时,Telegram 允许的文件大小上限为 50MB。如果剪辑超过此限制:
ffmpeg -i clip_N_final.mp4 -fs 49M -c:v libx264 -crf 28 -preset fast -c:a aac -movflags +faststart -y clip_N_tg.mp4
WhatsApp Business Cloud API 参考
两步流程:上传媒体 → 发送消息
WhatsApp Cloud API 要求先上传视频以获取 media_id,然后发送引用该 ID 的消息。
步骤 1 — 上传媒体
curl -s -X POST "https://graph.facebook.com/v21.0/<PHONE_NUMBER_ID>/media" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-F "file=@clip_N_final.mp4" \
-F "type=video/mp4" \
-F "messaging_product=whatsapp"
成功响应:
{"id": "1234567890"}
步骤 2 — 发送视频消息
curl -s -X POST "https://graph.facebook.com/v21.0/<PHONE_NUMBER_ID>/messages" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"to": "<RECIPIENT_PHONE>",
"type": "video",
"video": {
"id": "<MEDIA_ID>",
"caption": "Clip title here"
}
}'
成功响应:
{"messaging_product": "whatsapp", "contacts": [{"wa_id": "14155551234"}], "messages": [{"id": "wamid.HBgL..."}]}
文件大小限制
WhatsApp 视频上传的文件大小上限为 16MB。如果剪辑超过此限制:
ffmpeg -i clip_N_final.mp4 -fs 15M -c:v libx264 -crf 30 -preset fast -c:a aac -movflags +faststart -y clip_N_wa.mp4
24 小时消息窗口
对于非模板消息,WhatsApp 要求接收者在过去 24 小时内曾向你发送消息。如果收到“需要模板”错误,请:
- 请接收者先向商家号码发送任意消息
- 使用预先批准的消息模板,而不是自由格式的视频消息
常见错误
| 错误代码 | 描述 | 解决方法 |
|---|---|---|
| 100 | 参数无效 | 检查 phone_number_id 和收件人格式(不带 + 前缀,不含空格) |
| 190 | 访问令牌无效或已过期 | 在 Meta Business Settings 中重新生成令牌;临时令牌会在 24h 后过期 |
| 131030 | 收件人不在允许列表中 | 在测试模式下,将收件人添加到 Meta Developer Portal 中的允许号码列表 |
| 131047 | 需要重新互动消息或模板 | 收件人在过去 24h 内未发送消息 — 使用模板或请对方先发送消息 |
| 131053 | 媒体上传失败 | 文件过大或格式不受支持 — 重新编码为小于 16MB 的 MP4 |