reference-video-fetch · git:20260916.bd0eb26 · 2026-09-16 · sha256 3a86e5122ea7f804

reference-video-fetch git:20260916.bd0eb26A

Immutable. This exact content is served forever at /api/v1/blob/3a86e5122ea7f804.

---
name: reference-video-fetch
description: 用 yt-dlp 匿名(不登录、不传 cookie)获取 B 站 / YouTube 参考视频页面并写出抓取记录,供模板在需要动作、节奏或镜头参考时使用;含画质上限、失败分类和“只留本机、不再分发”边界。
---

# 参考视频获取(B 站 / YouTube)

目标:用户只给了一个视频链接、没有文件时,让 Agent 把参考视频取到本机,并留下可核对的抓取记录。**默认匿名**,不使用任何登录态。

本目录可独立安装:`SKILL.md` + `scripts/fetch_reference.py`。依赖只有 `yt-dlp`(和可选的 `ffprobe`)。

## 何时使用,何时不要用

- **使用**:模板需要动作、运镜、节奏、台词或镜头参考,用户没有自备文件,只给了公开页面链接。
- **不要使用**:用户已经提供文件(用户文件优先);素材是作者自有或已获授权(应走固定版本的媒体库,例如 `video-regen-assets`);目标是番剧、付费内容或需要大会员的清晰度。
- **不要用它替代来源记录**:抓到的是第三方作品,只在用户本机用于分析,不进入仓库、媒体库或其他再分发渠道。

## 能力与限制(先讲给用户听)

- **默认取匿名能给到的最高画质**。不传 `--max-height` 时按站点匿名上限来(实测有视频可到 1080p30,也有更高的只在登录后才放开)。`1080p60`、`1080p+`、4K、番剧与付费内容通常需要登录或大会员;本工具**不传 cookie**,所以只能取匿名可得的画质,不会偷偷降级也不假装拿到了更高画质。需要控制体积或后续算力时,用 `--max-height` 显式设上限。
- **站点内容会变**。同一个 BV 号可能被删除、替换或改画质;记录里的 SHA-256 只代表本次抓到的版本,**不能当作 pinned 素材**,也不能承诺跨时间复现。
- **只取片段不可靠**。CDN 直链缺少 Referer,`--download-sections` 一类的分段抓取会失败;要么整条下载,要么改用更低画质。
- **竖屏按短边算**。格式选择用分辨率短边(1080×1920 记为 1080p),避免竖屏视频被误判成“超过 1080p”。

## 步骤

1. **先探测**,不要直接下载:

   ```bash
   python3 scripts/fetch_reference.py --url "<视频页面链接>" --probe --out <项目参考目录>
   ```

   把打印出的**标题、作者、时长、匿名可用画质**回给用户确认,确认是同一支视频再继续。

2. **下载**(默认写 `<out>/<视频ID>.mp4` 与同名 `.fetch.json`):

   ```bash
   python3 scripts/fetch_reference.py --url "<视频页面链接>" --out <项目参考目录> \
     --limit-rate 4M --sleep-requests 1
   ```

   默认取匿名最高画质;`--max-height 720` 之类的上限只在明确要省体积或降算力时使用。需要“拿不到指定画质就失败”时加 `--require-height 1080`,避免悄悄用 360p 顶替。

3. **核对记录**。`<视频ID>.mp4.fetch.json` 至少应包含:`page_url`、`title`、`uploader`、`duration_seconds`、`selected_format_id`、`bytes`、`sha256`、`transport: no-login`、`redistribution: local-reference-only`、`notes`。
   记录里出现 `quality_limited: true` 或 `notes` 提到匿名上限时,要在交付说明里如实转述。

4. **接回模板流程**。把记录路径写进用户项目的来源台账;模板后续步骤只引用这个本地文件与其记录,不引用原始页面直链。

## 失败与降级

| 情况 | 退出码 | 处理 |
| --- | --- | --- |
| 没有 `yt-dlp` | 3 | 安装 `yt-dlp`,或回落到“请用户自备文件” |
| 不是公开视频页面(媒体直链、番剧、合集、其他站点) | 2 | 请用户给正常的视频页面链接 |
| 视频不存在、私密或区域限制 | 4 | 报告具体原因,请用户自备或换一条参考 |
| 匿名画质低于要求 | 5 | 报告实际可得的画质,请用户自备更高画质文件 |
| 输出已存在 | 6 | 默认保留旧文件;确认覆盖才加 `--force` |
| 时长超过上限 | 7 | 默认 900s;确认要整条再显式提高 `--max-duration` |
| 其他下载错误 | 8 | 保留错误原文,退避后最多重试一次,不静默换源 |

任何失败都要**回到“用户自备参考视频”这条主路径**,不能因为抓取失败就改变模板的效果目标或跳过参考绑定。

## 拿不到时:先穷尽自动路径,再交回用户

抓取失败时按顺序处理,**不要直接跳到“请用户下载”**:

1. 退避后重试一次(`--sleep-requests`、隔一会儿重跑),排除一次性抖动;
2. 换等价来源:作者主页、同一作品的另一条投稿、官方发布页;
3. 确认不是本地问题:`yt-dlp` 能否执行、网络是否正常、是否只是高清晰度需要会员而低清晰度可用;
4. 仍然拿不到,才把下载交回用户,并说明失败原因。

通常只能交给用户的情况:资源在**网盘**里(夸克、百度、蓝奏、Google Drive、OneDrive、Discord 附件等);需要**登录或大会员**才能拿到目标清晰度(番剧、付费内容、`1080p60` 以上);页面**区域限制**、需要验证码,或站点直接拒绝自动化访问。

交回用户时要给全这四项,不要只说“下载一下”:

1. **在哪下**:原始页面链接(有浏览器能力时可直接打开该页面)。
2. **下哪个**:文件名与期望的字节数;如果对方给了多个版本,指明要哪一个。
3. **放哪里**:目标绝对路径(用户项目的参考目录)。
4. **怎么验**:下载后由 Agent 核对大小;必要时用 `sha256sum`/`shasum -a 256` 比对。

拿到文件后照常继续:登记来源(链接、作者、获取日期、哈希),并在记录里标明这是**用户提供**而不是自动抓取,例如 `transport: user-provided`。私人分享链接、网盘提取码和账号信息只留在用户本地,不写进模板或仓库。

## 合规与礼貌

- 只抓用户指定的、用于本地分析的参考视频;不批量抓取、不抓合集、不再分发。
- 保留原始链接与作者署名,写进模板的 `sources.md` 或用户项目记录。
- 默认限速与请求间隔;失败退避重试,不并发轰炸站点。
- 第三方内容权利归原作者,本仓库 MIT 许可不覆盖它。

## 离线验证

```bash
python3 -m unittest discover -s skills/reference-video-fetch/tests -v
```

测试全部离线(伪造 yt-dlp/ffprobe 输出):链接规范化、短链解析、媒体直链拒绝、竖屏短边选流、画质上限与 `--require-height`、已存在文件保护、缺失工具、不可用页面、时长上限、抓取记录字段、以及“命令里绝不出现 cookie 参数”。真实站点的画质与可用性随时间变化,需要时用 `--probe` 现场核对。