| name | video-craw |
| description | 按关键词从 YouTube / Bilibili 自动抓取视频并提取统一格式的音频(默认 WAV 16kHz 单声道,适合 TTS / ASR / 声音克隆 / Demucs 去伴奏)。支持单个/多个人名快速调用、完整 YAML 配置、以及读取 .txt 关键词列表文件批量处理(每个关键词产出 1 条音频)。当用户说"帮我爬一下 xxx 的声音/视频/音频"、"采集 xxx 的语料"、"给我下 xxx 在 B站/YouTube 的音频"、"做个声音克隆数据集"、"按关键词批量下载并转 wav"、"给你一个关键词列表文件批量抓"、"按这份 txt 名单每人来一段"、或提到 yt-dlp / bilisearch / demucs / 声纹数据 / 语料采集时使用。 |
video-craw
按关键词,自动从 YouTube / Bilibili 搜索 → 下载 → 提取并统一转码为音频文件。可选 Demucs v4 人声分离。
支持三种调用方式:
| 方式 | 适用场景 | 入口 |
|---|
| 快速模式 | 用户只给了少量人物名 + 简单偏好 | scripts/run_quick.sh |
| 关键词文件模式 | 用户给了一份 .txt 名单(每行 1 个关键词),要求每个关键词来 1 条音频 | scripts/run_keywords.sh |
| 完整配置模式 | 用户给了详细 yaml 或要精细控制(每人不同抓取数等) | scripts/run.sh -c <config.yaml> |
所有路径均相对本 skill 目录解析,可整目录迁移。
第一次使用前
skill 自带 scripts/setup.sh,会在 skill 目录下创建 .venv 并安装 requirements.txt。两个 run*.sh 入口都会在首次运行时自动调用它,无需手动 setup。
系统依赖:必须有 ffmpeg。如果 setup 报警 "未检测到 ffmpeg",提示用户安装:
brew install ffmpeg
sudo apt install ffmpeg
决策流程
用户请求
│
├─ 给了 .txt 关键词列表文件("按这份名单"/"读这个 txt")?
│ → 走【关键词文件模式】,scripts/run_keywords.sh -f <txt 路径>
│ (每行 1 个关键词;每关键词严格产出 1 条音频)
│
├─ 只给人物名 / 平台 / 数量 等简单参数?
│ → 走【快速模式】,scripts/run_quick.sh
│
├─ 已经有 config.yaml?
│ → 走【完整配置模式】,scripts/run.sh -c <路径>
│
└─ 需要精细控制(每人不同抓取数 / cookies / 自定义 demucs 模型)?
→ 复制 config.example.yaml 改完,再走完整配置模式
不确定先用 --dry-run 让用户确认搜索命中,再正式跑(仅快速模式 / 完整配置模式支持 --dry-run;关键词文件模式直接执行)。
快速模式(推荐起手)
bash scripts/run_quick.sh \
--person "周杰伦" \
--person "罗永浩" \
--per-platform 5
常用参数(全部可选,缺省即默认 wav/16kHz/mono/中间10秒):
| 参数 | 说明 |
|---|
--person <name> | 必填,可重复 |
--output <dir> | 输出根目录,默认 <skill_dir>/downloads/;传相对路径会相对用户当前 cwd解析;传绝对路径直接用 |
--per-platform N | 每平台抓取条数,默认 5 |
--youtube N / --bilibili N | 单独覆盖某平台数量,0 = 关闭该平台 |
--format wav|mp3|m4a | 默认 wav |
--sample-rate / --channels | 默认 16000 / 1 |
--clip-seconds N | 截取中间多少秒,0 = 保留全长,默认 10(声音克隆友好规格,无特殊需求别改) |
--min-duration N | 短于此秒的源直接跳过,默认 10(必须 ≥ --clip-seconds,否则源不够长无法截取) |
--max-duration N | 单条最长秒数,0 = 不限,默认 1800 |
--vocal | 启用 Demucs 人声分离(去伴奏) |
--diarize | 启用 pyannote 说话人分离,只保留视频里说话最多的那个人;首次需要 HF token |
--hf-token <token> | HuggingFace token;留空读环境变量 HF_TOKEN |
--min-target-total-sec N | 目标人总时长不足时跳过该条;默认 5.0 |
--proxy | 例:http://127.0.0.1:7890,YouTube 在国内通常需要 |
--cookies-youtube / --cookies-bilibili | Netscape 格式 cookies 文件路径 |
--dry-run | 只搜索打印,不下载 |
-v | 调试日志 |
run_quick.sh 内部会在 --output 目录下生成一份 _generated_config.yaml 再调用主程序,便于复盘。
关键词文件模式(推荐用于批量名单)
用户给一份 .txt,每行一个关键词(空行 / # 注释自动忽略)。每个关键词严格产出 1 条音频;某关键词在所有平台、所有候选都拿不到才记为 fail。
bash scripts/run_keywords.sh -f /path/to/keywords.txt
默认输出 = 10 秒 wav,已经是声音克隆 / TTS 参考音的常用规格。不要在没有明确需求时改 --clip-seconds。
用户若说"我要 5 秒"/"全长保留"/"30 秒片段"再相应传 --clip-seconds 5 / --clip-seconds 0 / --clip-seconds 30,并把 --min-duration 提到 ≥ --clip-seconds(否则源不够长截不出来)。
参数:
| 参数 | 说明 |
|---|
-f / --file <path> | 必填,关键词 txt 文件 |
-o / --output <dir> | 输出根目录,默认 <skill_dir>/downloads/ |
--platforms bilibili youtube | 平台尝试顺序;第一个成功就停。默认 bilibili youtube |
--candidates-per-platform N | 每平台拉多少候选轮流尝试(容错失败/过滤);默认 3 |
--format / --sample-rate / --channels | 同快速模式 |
--clip-seconds N | 默认 10;0 保留全长 |
--min-duration / --max-duration | 同快速模式 |
--vocal | 启用 Demucs 人声分离 |
--diarize | 启用 pyannote 说话人分离,只保留说话最多的人 |
--hf-token <token> | HuggingFace token;留空读环境变量 HF_TOKEN |
--min-target-total-sec N | 目标人总时长不足时跳过该条;默认 5.0 |
--proxy | 例 http://127.0.0.1:7890;用 youtube 时几乎必填 |
--cookies-youtube / --cookies-bilibili | cookies 文件路径 |
-v | 调试日志 |
样例 keywords.txt 见 keywords.example.txt。
关键差异 vs 快速模式:
- 快速模式:"1 个人 × 每平台 N 条"——产出可能很多
- 关键词文件模式:"N 个关键词 × 每个仅 1 条"——产出条数 = 关键词条数
如果某关键词全军覆没(比如时长全被过滤),日志会打 [fail] '<keyword>' 所有平台/候选都未拿到可用音频,进程退出码 2。
完整配置模式
cp <skill_dir>/config.example.yaml ./my_config.yaml
bash <skill_dir>/scripts/run.sh -c ./my_config.yaml
bash <skill_dir>/scripts/run.sh -c ./my_config.yaml --dry-run
bash <skill_dir>/scripts/run.sh -c ./my_config.yaml --person "周杰伦"
配置里 output_dir 写相对路径(如默认的 ./downloads)会落到 skill 目录下;想自定义到别处,写绝对路径。
完整字段说明见 config.example.yaml,要点:
audio.format / sample_rate / channels — TTS/ASR 友好默认 wav 16000 1;声音克隆若需 24kHz 改 sample_rate: 24000
audio.clip_seconds — 默认截取中间 10 秒;想保留全长设 0
vocal_extract.enabled: true — 开启 Demucs 去伴奏;首次会下载模型权重 (~80MB),Mac 上推荐 device: mps
diarize.enabled: true — 开启说话人分离;多人视频做克隆素材必开。会自动取视频里说话最多的那位作为目标人
defaults.youtube / defaults.bilibili — 每平台默认 top N,0 关闭
persons[].platforms — 可逐人覆盖每平台数量
默认音频规格(不要随意改)
| 项 | 默认 | 含义 |
|---|
--format | wav | TTS / ASR / Demucs 都吃 wav |
--sample-rate | 16000 | 16kHz 是声音克隆 / VALL-E / GPT-SoVITS 等常用输入;24kHz 模型才需要改 24000 |
--channels | 1 | 单声道,下游模型基本都要单声道 |
--clip-seconds | 10 | 从音频中间截取 10 秒作为最终产物;声音克隆经验值 |
--min-duration | 10 | 原视频 < 10s 直接跳过(保证够截 10s) |
⚠️ 协同约束:min_duration ≥ clip_seconds。否则源音不够长,截不出目标长度。
用户没明确说要别的规格时,保持默认即可;他要"5 秒短片段"/"完整音频"/"24kHz"再相应改对应参数。
输出结构
默认所有产物落在 <skill_dir>/downloads/ 下(包括快速模式默认输出和示例配置),即此 skill 自带的 downloads/ 子目录。如需放别处,给 --output 传绝对路径,或修改 yaml 里的 output_dir 为绝对路径。
<skill_dir>/downloads/
├── .manifest.json # 去重 / 续传清单
├── 周杰伦/
│ ├── youtube/<video_id>__<title>.wav
│ └── bilibili/<video_id>__<title>.wav
└── Taylor Swift/
└── youtube/...
- 文件名
{video_id}__{安全标题}.{ext},便于回溯
.manifest.json 让重跑天然去重;删条目即可强制重下
常见坑(提前规避)
| 现象 | 处理 |
|---|
Sign in to confirm you're not a bot (YouTube) | 让用户配置 --cookies-youtube 或换出口/代理 |
| 国内连不上 YouTube | 几乎一定要 --proxy |
启用 --vocal 第一次很慢 | Demucs 在下载 ~80MB 模型权重,之后会缓存复用 |
| 想做声音克隆但歌曲带 BGM | 必须加 --vocal,否则会污染训练 |
| B站合集多 P 只下了第一个 | 默认行为;要全 P 需逐 URL 处理 |
torchcodec / torch 安装大 | 用户不需要 demucs 时,可在 requirements.txt 注释掉最后两行后再 setup |
启用 --diarize 报 pyannote 需要 HuggingFace token | 在 HF settings 拿 token,并在浏览器同意 pyannote/speaker-diarization-3.1 的模型协议;然后 export HF_TOKEN=hf_xxx 或传 --hf-token |
--diarize 后某条音频被记 [skip 已过滤] diarize: 目标说话人 ... 总时长 X.Xs | 这条视频里"说话最多的那个人"也讲得太少。要么调低 --min-target-total-sec,要么换源 |
| 多人对谈/采访视频做声音克隆,发现混入了别人 | 必须加 --diarize(最好同时 --vocal)。前提是目标人在该视频里说得最多——否则换一条目标人占主导的源视频 |
多说话人场景(采访 / 对谈 / 圆桌)
只开 --vocal 只能去 BGM、不分人。多人视频做声音克隆数据时,必须再加 --diarize,否则克隆出的音色会被记者/嘉宾污染。
--diarize 的策略很简单:跑 pyannote diarization → 取这条视频里说话总时长最长的那个 speaker → 把他的所有片段拼成一条单说话人 wav。前提是目标人在该视频里是主角(演讲者、采访被采访者、答记者问的主角等)。如果目标人在视频里只是配角,就换一条他主导的源视频。
何时开
| 场景 | 推荐组合 |
|---|
| 单人演讲 / 单人 vlog | 不开 diarize(音轨只有一人,开了浪费时间) |
| 单人 MV / 翻唱 | --vocal,不开 diarize |
| 多人采访 / 答记者问 / 播客主咖 | --vocal --diarize |
| 多人圆桌且目标人不是主角 | 不要用此 skill,换一条目标人主导的源视频 |
一次性准备
- 在 https://huggingface.co/settings/tokens 拿 token(read 权限即可)。
- 浏览器登录后访问 pyannote/speaker-diarization-3.1,点同意协议。
export HF_TOKEN=hf_xxx 写进 shell rc,或每次传 --hf-token。
同意协议是一次性动作;token 也只设一次。之后所有 diarize 调用都走缓存。
用法示例
bash scripts/run_quick.sh \
--person "Trump press conference" \
--per-platform 5 \
--vocal --diarize \
--proxy http://127.0.0.1:7890
bash scripts/run_keywords.sh \
-f keywords.txt \
--vocal --diarize
默认行为细节
- 开
--diarize 后,clip_seconds 的"截中间 N 秒"会自动延后到说话人分离之后执行——否则前 10s 里可能根本没目标人说话。
- 拼接结果统一为 wav;非 wav 输入会被替换扩展名。
- 目标人总说话时长
< min_target_total_sec(默认 5s)的视频会被记为 [skip 已过滤],进 manifest 失败计数 → 关键词文件模式会自动尝试下一个候选。
min_target_total_sec 必须 ≥ clip_seconds,否则截不出目标长度——脚本不会强校验,由用户保证。
性能预期(M2 Mac,CPU 后端)
| 输入时长 | demucs(htdemucs) | pyannote diarization |
|---|
| 1 分钟 | ~10s | ~15s |
| 10 分钟 | ~90s | ~120s |
| 30 分钟 | ~5min | ~6min |
GPU/MPS 下能再快 3-5 倍。pyannote 在 MPS 上偶有 op 不支持,代码里已自动回退 CPU。
与其他 skill 的衔接
抓回来的 wav 通常是下游素材:
- 声音克隆 / 角色扮演聊天 → 配合
chat-with-anyone skill 使用
- TTS 训练 / 推理参考音 → 配合
tts skill 使用
- 表达性语音 → 配合
characteristic-voice skill 使用
这种场景下 agent 应在拿到 wav 路径后,主动建议用户进入下一个 skill。
文件结构
video-craw/
├── SKILL.md
├── fetch_audio.py # 主入口(被脚本调用)
├── requirements.txt
├── config.example.yaml # 完整配置模板
├── src/
│ ├── config.py
│ ├── searchers.py # YouTube + Bilibili 关键词搜索
│ ├── downloader.py # yt-dlp + ffmpeg 流水线
│ ├── vocal.py # Demucs 人声提取(去 BGM)
│ ├── diarize.py # pyannote 说话人分离 + 目标说话人提取
│ └── manifest.py
├── keywords.example.txt # 关键词文件模式样例
└── scripts/
├── setup.sh # 自动建 venv + 装依赖(幂等)
├── run.sh # 完整配置模式入口
├── run_quick.sh # 快速模式入口
├── quick_fetch.py # 快速模式实现
├── run_keywords.sh # 关键词文件模式入口
└── fetch_keywords.py # 关键词文件模式实现(每关键词产出 1 条)