# 抖音视频下载（统一目录）

所有抖音下载都平铺在本目录，不再按视频分子目录。**同一条素材只保留最高像素的那一版。**
下载页：http://192.168.31.76:8899/56-%E6%8A%96%E9%9F%B3%E8%A7%86%E9%A2%91%E4%B8%8B%E8%BD%BD/

## 命名规则

```
NN_作者_标题_宽x高.mp4          ← 视频正片
NN_作者_标题_图集NN.png          ← 图文/图集：每张图一个文件
NN_作者_标题_宽x高_封面.webp     ← 官方封面（视频才有）
NN_作者_标题_*_元数据.json       ← 完整元数据 + 全部清晰度档位 / 图片清单
NN_作者_标题_*_预览-*.jpg        ← 抽帧（视频才有）
```

**文件名长度**：标题按「去掉 `#`、标点转空格 → 按空格分词 → 连字符拼接 → 总长 ≤40 字符且不切断词」截断，所以不会出现超长文件名（05 的文案有 100+ 字，截出来是 `Latent续写-内存不堆积-H3分段长视频生成工作流V6`）。

`NN` 是下载序号，**新内容自动取目录内已有序号 +1**（当前已有 01–05，下一条是 06）。同一条内容的所有附带文件共用同一前缀，所以平铺也不会混。

## 一键下载

```bash
# 分享短链、整段分享文案都能吃
node ~/Downloads/douyin-hq.js 'https://v.douyin.com/xxxxxxxx/'

# 可选参数
#   --tag=04_自定义名        手动指定文件名前缀
#   --hudir=<目录>           换输出目录
#   --work=<目录>            换工作目录（默认 /tmp/dy/hq）
#   --wait=<秒>              等扫码时长（已登录则跳过）
```

- **视频和图文都能下**：视频自动挑最高分辨率档；图文自动抓全部图并按 `q100.png` 无损档下载（见下文）。
- 登录态持久化在 `~/Downloads/.douyin-profile`，**扫过一次码之后就不用再扫**。
- 免登录的降级方案：`bash ~/Downloads/douyin-dl.sh '<分享链接>'`（只能拿 1080p 无水印）。
- 关键机制：用 Playwright 在登录态下打开视频页，**被动监听** `aweme/v1/web/aweme/detail/` 响应拿到完整 `bit_rate` 档位表，再按「分辨率 → mp4 优先 → 码率」排序取最高档。

## 内容清单

| # | 作者 | 标题 | 分辨率/规格 | 编码 | 帧率 | 时长 | 大小 |
|---|---|---|---|---|---|---:|---:|
| 01 | AI 观模者 | Qwen3.8-27B-GSQ-RCO 测评：16G卡最佳选择 | **2560×1440** | HEVC | 30 | 16:45.6 | 44.6 MiB |
| 02 | L | 去年夏天 · 白膜素材 | **1080×1920** | H.264 | 24 | 21.5 s | 1.59 MiB |
| 03 | L | 复仇摇 · AI 素材 | **720×1280** | H.264 | 24 | 14.08 s | 1.18 MiB |
| 04 | Feeling | 落日cp · 跟个风 | **图文** 2 图（1280×664 / 1280×720） | PNG 无损 | — | — | 0.53 MiB |
| 05 | Theodore | Latent续写 · H3 分段长视频生成工作流 V6 | **1920×1080** | H.264 | 30 | 10:44.2 | 35.7 MiB |

> - 01 原有两个版本（免登录 1920×1080 H.264 / 登录 2560×1440 HEVC），**已按「只留最高像素」删掉 1080p 那版**。
> - 02 和 03 都是**源分辨率即天花板**，没有更高档存在。
> - **02 和 03 是同一个账号**（昵称 `L`，unique_id `90624020045`）。签名：*"首发原创高质量白模风格视频…"*。这个号专做「白模/彩模 + 绿幕 + 舞蹈」AI 素材。03 文案里的 `@晚棠不吃榴莲` 是原舞作者。
> - **04 是图文（图集）不是视频**：`aweme_type=68`、`is_slides=1`。分享短链会跳到 `iesdouyin.com/share/slides/<id>/`（不是 `/share/video/`）。BGM 是《心云（剪辑版）》/ 烟嗓表哥（33 s），**接口没给可下载的音频地址**，所以只存了歌名到元数据。

### ⚠️ 目录里有一个未归类的文件

`dy-437JMeZfA6c-1080p.mp4`（54.9 MB，1024×576，11:12，2026-09-27 01:12 出现）**不是本流程产出的**——命名风格不匹配（本流程是 `NN_作者_标题_...`），推测是另一次会话或别的下载工具放进来的。内容是「手持手机视频通话」画面，与本目录其它素材无关。**未做改动**，等确认后再归位或删除。

## 图文 / 图集（04 号）的下载方式 —— 关键发现

抖音图文（`aweme_type=68`）的 `images[].url_list` **只给 `~tplv-dy-aweme-images:q75.webp`**（q75 有损、11 KB），
而 `download_url_list`（"保存到相册"那条）**带水印**（`~tplv-dy-water-v2:...`）。

**破法：把签名查询串整个丢掉，只留对象 key，换到不校验签名的 `pN.douyinpic.com` 主机上，模板就能随便改：**

```
原链（q75 有损、11 KB）  https://p3-pc-sign.douyinpic.com/tos-cn-p-0015/<key>~tplv-dy-aweme-images:q75.webp?lk3s=...&x-signature=...
改成（q100 无损、172 KB）https://p3.douyinpic.com/tos-cn-p-0015/<key>~tplv-dy-aweme-images:q100.png
```

实测模板矩阵（同一张图）：

| 模板 | HTTP | 大小 | 格式 |
|---|---|---:|---|
| `:q75.webp`（接口给的） | 200 | 11 KB | webp 1280×664 |
| `:q85.webp` / `:q90.webp` | 200 | 15 / 20 KB | webp |
| `:q100.webp` | 200 | 38 KB | webp |
| `:q75.jpeg` / `:q100.jpeg` / `:q100.image` | 200 | 20 KB | jpeg（jpeg 被钉死在 q75） |
| **`:q100.png`** | 200 | **172 KB** | **PNG rgb24（无损，取这个）** |
| `:origin.*` / 无模板 / `.webp` / `:q100.heic` | 400 / 空 | — | 不允许 |

脚本已内置：每张图按 `q100.png` → `q100.webp` → 接口原链 依次降级。

## 为什么 01 留的是 1440p

当时的实测结论（对比图已删，数据留档）：

| 指标 | 结果 |
|---|---|
| 同尺寸高频能量（拉普拉斯 YAVG） | 标题 +20%、正文 +31%、小字表 +38%，1440p 全胜 |
| 方向性 SSIM/PSNR | `1080p vs 1440p↓1080p` → SSIM 0.9769 / PSNR 37.04 dB；`1440p vs 1080p↑1440p` → 0.9707 / 34.08 dB。**前者更接近 → 1440p 含 1080p 放大不回来的真实细节** |

**但要记住代价与风险：**
- 1440p 档是 `adapt_lowest_1440_1`（1440 阶梯**码率最低**档，0.0029 bit/像素/帧）；被删的 1080p 是 `normal_1080_0`（0.0080 bit/像素/帧，**2.7 倍**）。1440p 靠像素多取胜，肉眼看差距不大。
- 1440p 是 **HEVC/H.265**，部分播放器/剪辑软件不认。**若哪天需要 H.264 兼容版**，用 `bash ~/Downloads/douyin-dl.sh 'https://v.douyin.com/QOmcej9H8_U/'` 随时能重新拉回那条 1080p。

## 各条清晰度档位实况

**01（源 2560×1440，共 21 档）** — 关键几档：

```
1920x1080 mp4  normal_1080_0        550622   ← 已删除的那版（仅 1080p）
1920x1080 mp4  1080_1_1             543330
1280x720  mp4  normal_720_0         469346
2560x1440 mp4  adapt_lowest_1440_1  371595   ← 保留的就是这条
```

**02（源 1080×1920，共 10 档）** — 源分辨率即天花板：

```
1080x1920 mp4  normal_1080_0  618627   ← 已选
 576x1024 mp4  normal_540_0   634565   ← 注意：码率数字比 1080p 还高，但像素少，不选
 720x1280 mp4  normal_720_0   539795
 ...（其余 7 档更低）
```

**03（源 720×1280，共 7 档）** — 源分辨率即天花板：

```
720x1280 mp4  normal_720_0  702527   ← 已选（同时是最高分辨率 + 最高码率）
720x1280 mp4  low_720_0     619102
576x1024 mp4  low_540_0     537274
 ...（其余 4 档更低）
```

> 通用规律：抖音会给**低分辨率单独做高码率档**（02 的 576×1024 就是），排序时**先看分辨率再看码率**——分辨率后期补不回来，码率差一点可以。

## 踩坑记录（重要，别再重走）

1. **`yt-dlp` 下不了抖音。** 它走 `www.douyin.com/aweme/v1/web/aweme/detail/`，报 `Fresh cookies (not necessarily logged in) are needed`；补 `ttwid` 无效。同接口纯 curl 访问 `403 Blocked by ArgusSecurityPlugin Uifid Not Found`；老的 `web/api/v2/aweme/iteminfo/` 返回 `status_code 11110 encrypt_data_miss`。
2. **免登录可行路子 = 移动端 SSR 分享页**（`www.iesdouyin.com/share/video/<id>/` 的 `window._ROUTER_DATA`）。必须：**Android/移动 UA**（iPhone UA 拿到空壳页）+ **带 `ttwid` 且请求两次** + **剥掉代理环境变量**。它只给 `playwm`(带 logo)/`play`(无水印) 直链，**档位最多 1080p**。
3. **抖音 web 端高清上登录锁。** 未登录打开视频页弹「登录后免费畅享高清视频」，且 `aweme/detail` 返回 **HTTP 200 但 body 长度 = 0**（风控空响应）——不是 4xx，极容易误判成接口坏掉。
4. **同批请求里 `multi/aweme/detail/` 未登录也能返回**（那是推荐流，不含目标视频）。用它当探针确认了 1440p 档位存在，才决定去登录。
5. **登录不会提升 1080p 画质。** 码率最高的仍是 `normal_1080_0`，与免登录下到的字节数完全一致。登录的唯一收益是多了那个 1440p 档。
6. **`download_addr`（"保存本地"那条）是 720p 且带 logo**（`lr=aweme_search_suffix`），比 `play_addr` 差，不要用。
7. 这三条**都没有抖音片尾引导卡**（末尾逐帧抽查确认）。对比：2026-09-14 那批 28 条片尾固定 3.0 秒，处理记录见 `../37-抖音视频去片尾/`。
8. **图文（图集）的短链不走 `/share/video/`**，而是跳 `/share/slides/<id>/`（`is_slides=1&schema_type=37`）。解析 id 的正则必须包含 `slides`，否则报「需要抖音分享链接」。另外 `iesdouyin.com/share/slides/<id>/` 页面里**没有** `window._ROUTER_DATA`，必须走 web 端 `aweme/detail`（登录态）才拿得到图片清单。

## 质检

- 视频：全部 `ffmpeg -f null -` 整条全解码，**零 error / warning**
- 图片：`ffprobe` 校验为合法 PNG（rgb24），尺寸 1280×664 / 1280×720
- 抽样目视：无抖音水印、无账号 ID 浮层、无片尾卡
- 视频仅取 `play_addr` 系档位（`playwm` 才带抖音 logo）；图片不用 `download_url_list`（那是有水印的"保存到相册"档）
- 校验值见 `sha256.txt`（含图片）

## 可选后续处理（需要就说）

1. **抠绿幕出带 Alpha 成品**（MOV qtrle / WebM VP9 / PNG 序列），直接叠背景；
2. **导出 PNG 帧序列**（02 ≈ 516 帧、03 ≈ 338 帧）给 AI 逐帧驱动；
3. **把 01 的 1440p 转 H.264**（换取播放器/剪辑软件兼容性，代价是二次编码）；
4. **批量下载**：把一批分享链接给我，一次跑完并自动编号；
5. ⚠️ 02/03 都是 **24 fps**，要喂给只吃 30/60fps 的流程需要真补帧，不是改时基就行。

## 视频信息

- 01：aweme_id `7687665215751736614`，发布 2026-09-21，点赞 438 / 分享 71 / 收藏 467
- 02：aweme_id `7681113602158603877`，发布 2026-06-04，点赞 24255 / 分享 5252 / 收藏 4502
- 03：aweme_id `7675399295693164153`，发布 2026-06-25，点赞 114 / 分享 124 / 收藏 88
- 04：aweme_id `7688528843355738515`，发布 2026-09-23，点赞 8919 / 分享 4473 / 收藏 2016 / 评论 554（图文）
- 05：aweme_id `7676102310153489683`，发布 2026-08-20，点赞 721 / 分享 149 / 收藏 711 / 评论 124
