# Douyin Jiexi Skill

> 抖音视频「先要 cookie → 双路线解析 → 下载 → 全片解析 → 删除视频 → 输出结果」一条龙。 用户发来抖音分享文案/短链/视频链接，或要求解析、分析、看某个抖音视频时使用： 开头先向用户要抖音 cookie（仅存本地），随后自动下载视频，按秒抽取全片画面、拼成版图、 离线转写整段语音，分析完删除视频本体防止占内存。 触发词：抖音、解析视频、分析视频、抖音链接、抖音文案、douyin。 Use when the user shares a Douyin (TikTok China) link and wants the video parsed, downloaded, or analyzed.

- Skill: `zhangruilin158/douyin-jiexi-skill` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add zhangruilin158/douyin-jiexi-skill`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zhangruilin158/douyin-jiexi-skill/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: zhangruilin158 (https://skillmd.com/u/zhangruilin158)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/zhangruilin158/douyin-jiexi-skill

---


# 抖音视频解析 / 下载 / 全片解析 / 清理（douyin-jiexi-skill）

## 触发场景
用户发来**抖音分享文案、短链（`v.douyin.com/xxx`）、或视频链接**，并说要"解析 / 分析 / 看看 / 下载"这个视频。

## 流程图

```mermaid
flowchart TD
    A[用户发来抖音链接/文案] --> B{本地已有 cookie?}
    B -- 否 --> C[大模型向用户要 cookie\n用户粘贴一次]
    C --> D[存入 scripts/config.local.json\n已 gitignore，不上传]
    B -- 是 --> E[开始解析]
    D --> E
    E --> F{双路线解析}
    F --> G["路线1: 本地自算签名\n需 cookie + 本地核心"]
    F --> H["路线2: 第三方解析 API\n无需 cookie（兜底）"]
    G --> I{拿到无水印直链?}
    H --> I
    I -- 否 --> H
    I -- 是 --> J[下载视频到临时目录]
    J --> K[全片解析: 逐秒帧 + 5x5 版图 + 语音转写]
    K --> L[得出解析结果]
    L --> M[删除视频本体]
    M --> N[输出解析结果给用户]
```

---

## 0. 开头：先要用户给 cookie（必做，别跳过）

**任何解析/下载动作之前，先确认 cookie 已就位。**

```bash
# 本机是否已有 cookie？看 config.local.json 里有没有 cookie 字段
cat "<skill目录>/scripts/config.local.json" 2>nul
```

- **有 cookie** → 直接进第 1 步。
- **没有** → 在对话里直接问用户要（不必绕弯子）：

  > 把抖音网页版 cookie 贴给我：浏览器打开 douyin.com 并登录 → F12 → Network →
  > 随便点一个请求 → 复制 `Request Headers` 里的 `Cookie` 整行。我存到本地配置，之后不用再贴。

  用户贴来后，用一条命令存好（**不要**把 cookie 写进任何会被提交的文件或聊天记录长期留存）：

  ```bash
  python "<skill目录>/scripts/douyin.py" set-cookie "<用户给的 cookie 字符串>"
  ```

  cookie 落在 `scripts/config.local.json`（已在 `.gitignore`，**绝不会上传到 GitHub**）。

### cookie 怎么输入最方便（设计说明）
- **首选：本地配置文件 + 一次性粘贴**。首次让用户在对话里贴一次，存 `config.local.json`，
  之后脚本自动读，用户再也不用贴。cookie 长且含 `sessionid/ttwid/msToken` 等敏感 token，
  聊天里反复粘贴既难看又有泄露风险；落本地文件最省事也最干净。
- **临时覆盖**：任何命令加 `--cookie "..."` 直传本次用，也会顺手写回本地配置。
- **不想在对话里贴**：用户可自己跑 `python douyin.py set-cookie "..."` 交互式存。
- **为什么不让大模型"记住"**：cookie 是凭据，放聊天/记忆里不安全；以本机 gitignored 文件为唯一真相源。

> cookie 的作用：启用「路线1 本地自算签名」（对当前抖音风控更稳）。路线2 第三方 API 本身**无需 cookie**；
> 所以即使没 cookie，流程也能跑——但按用户要求，开头一律先要 cookie。

---

## 1. 双路线解析（拿到无水印直链）

```bash
cd <工作目录>
python "<skill目录>/scripts/douyin.py" run "<用户给的原文，原样贴进去>"
```

脚本自己从文案里抠链接，然后**双路线**拿直链：

| 路线 | 需要 | 说明 |
|---|---|---|
| ① 本地自算签名 | cookie + 本地核心 `douyin-slim-parser` | 复用 exe 提取的解析核心，自己算 X-Bogus/A-Bogus 直连官方接口 |
| ② 第三方解析 API | 无 | `api.doukan1.top/32.php` 等，服务器代算签名（兜底，保证能拿到） |

路线①优先；拿不到直链自动回落②。返回 JSON 带 `source` 字段标来源（`local` / 第三方 host）。

**解析 → 下载 → ffprobe 取元数据 → 全片逐秒抽帧 → 拼 5×5 版图 → 离线转写语音 → 删除视频本体**

输出 JSON（节选）：
```json
{
  "ok": true, "title": "视频标题", "type": "video", "source": "local|thirdparty",
  "cleaned": true,
  "frames_dir": "<工作目录>\\.douyin-frames",
  "items": [{
    "media": {
      "duration_sec": 15.2, "width": 1080, "height": 1920, "video_codec": "hevc",
      "audio_codec": "aac", "bytes": 3456789, "mode": "full",
      "frame_count": 15, "frames_dir": "...\\item00", "frames_fps": 1.0,
      "sheets": ["...\\sheets\\sheet_01.jpg"], "sheet_seconds": 25,
      "transcript": {"ok": true, "engine": "faster-whisper", "model": "small",
                     "language": "zh", "duration": 15.2,
                     "segments": [{"start": 0.0, "end": 3.2, "text": "第一句"}],
                     "text": "整段文字"}
    }
  }]
}
```

**产出三件套，覆盖整段视频（"整个视频解析"，不抽片段）**：
| 产出 | 位置 | 说明 |
|---|---|---|
| 逐秒帧 | `frames_dir/f_00001.jpg …` | 默认 1 秒 1 帧，上限 600 帧（`--fps` / `--max-frames` 可调） |
| 拼版图 | `frames_dir/sheets/sheet_NN.jpg` | 5×5 拼图，**一张覆盖 25 秒**，快速通览全片 |
| 语音转写 | `transcript.text` / `transcript.segments` | 带时间戳，离线跑，无需联网 |

## 2. 下载视频
自动落到系统临时目录（`tempfile.mkdtemp`），带 `Referer: https://www.douyin.com/` 防直链防盗链。
图集（pics）逐张下载。

## 3. 全片解析（整个视频）
**必须真的把图读出来看**，不要只念元数据：
1. 先按顺序 Read 所有 `sheets`（一张图 = 25 秒）→ 建立全片时间线。
2. 挑信息量大的时刻（口播重点、字幕页、转场、商品/价格露出），按 `frame_count` 反推时间点，Read 对应 `f_XXXXX.jpg` 看细节。
3. 结合 `transcript.segments` 时间戳，把"画面变化"和"说了什么"对齐。

> `f_00001.jpg` 对应第 0 秒，`f_00025.jpg` 对应第 24 秒（1 秒 1 帧时）。

分析维度按用户意图选，默认覆盖：主题 / 画面 / 结构（钩子→中段→结尾）/ 文案（含逐句口播文稿）/ 可复用点。

## 4. 得出解析结果
汇总：标题、作者、时长、画面时间线、口播文稿、可借鉴点。这就是"解析结果"。

## 5. 删除视频
分析完**立即整目录删除**视频本体（`run` 默认删；`--keep` 才留）。

## 6. 输出结果
把第 4 步的解析结果告诉用户；并提示：视频已删、帧与版图在 `.douyin-frames\`（用完 `clean` 清）。

---

## 子命令

| 命令 | 用途 |
|---|---|
| `set-cookie "<cookie>"` | **开头用**：保存 cookie 到本地配置（一次性） |
| `run "<分享文案>"` | **默认**：要 cookie → 双路线解析 → 下载 → 全片解析 → 删视频 |
| `parse "<链接>"` | 只解析（双路线），看接口返回（调试用） |
| `fetch "<直链>"` | 已知直链时直接下载分析 |
| `clean` | 清 `.douyin-frames` 目录 |

`run` / `parse` 支持 `--cookie "..."`（本次用并写回）与 `--local-core <dir>`（指定路线1核心）。

常用参数：
| 参数 | 默认 | 说明 |
|---|---|---|
| `--fast` | 关 | 退回快速模式：只抽 N 张关键帧，不抽全片、不转写 |
| `--frames N` | 6 | 仅 `--fast` 时生效 |
| `--no-transcribe` | 关 | 全片抽帧但不做语音转写（长视频提速） |
| `--fps` | 1.0 | 全片抽帧频率（秒/帧）。`0.5` = 2 秒 1 帧 |
| `--max-frames` | 600 | 抽帧上限，防超长视频爆盘 |
| `--lang` | zh | 转写语言 |
| `--max-items N` | 9 | 图集最多下几张 |
| `--frames-dir <dir>` | `<cwd>/.douyin-frames` | 帧与版图落地目录 |
| `--keep` | 关 | 保留视频本体 |
| `--cookie "..."` | 配置值 | 本次 cookie（写回本地） |
| `--local-core <dir>` | 配置值 | 路线1 本地核心目录（douyin-slim-parser） |

---

## 接口与配置

**双路线**：
- 路线① 本地自算：需要 `cookie`（第 0 步）+ `local_core`（指向 `douyin-slim-parser` 目录，含 python310+pyc）。
- 路线② 第三方 API：无 cookie，按顺序降级重试：
  ```
  GET {api}?url=<encodeURIComponent(分享链接)>
  → {"code":200,"data":{"title","video","videos[]","images[]","cover"}}
  ```

配置优先级：**环境变量 > `scripts/config.local.json` > 内置默认值**。可配置项见 `scripts/config.example.json`：

| 配置 | 环境变量 | 说明 |
|---|---|---|
| `cookie` | `DOUYIN_COOKIE` | 抖音网页版 cookie（路线①用；已 gitignore） |
| `local_core` | `DOUYIN_LOCAL_CORE` | 本地解析核心目录（douyin-slim-parser） |
| `apis` | `DOUYIN_API`（逗号分隔） | 第三方解析服务端点，可换成自建 |
| `ffmpeg` / `ffprobe` | `FFMPEG_BIN` / `FFPROBE_BIN` | 不配则找 `scripts/tools/`、系统 PATH |
| `python` | `DOUYIN_PY` | 跑转写的解释器（需 faster-whisper），默认当前解释器 |

`config.local.json` 本机专属，**不要提交仓库**（已在 `.gitignore`）。

⚠️ 接口对无效链接返回占位（`title` 空、`video` 指向 `xq.mp4`）。脚本已识别，遇占位继续降级；
两个都占位 = 链接失效，直接告诉用户"链接失效或不是有效抖音链接"，别硬编结果。

---

## 依赖

| 依赖 | 必需 | 说明 |
|---|---|---|
| Python 3.9+ | 是 | 主脚本仅标准库 |
| ffmpeg / ffprobe | 是 | 抽帧、拼版图、抽音轨 |
| `faster-whisper` | 否 | 语音转写；没装则 `transcript.ok=false`，其余照常 |
| 路线①本地核心 | 否 | `douyin-slim-parser`（另存），用于本地自算签名 |

```bash
pip install faster-whisper        # 可选，仅转写需要
```

---

## 排错

| 现象 | 处理 |
|---|---|
| 两个接口都返回占位 | 链接失效/过期/非抖音。让用户重新复制分享链接 |
| `下载失败` / 响应过小 | 直链需 `Referer: https://www.douyin.com/`，脚本已带；仍失败重试一次 |
| 路线①本地核心报错 | 检查 `local_core` 路径与 `cookie`；不影响路线②兜底 |
| `transcript.ok=false` 且报 cublas/cudnn | CUDA 缺库，脚本已自动回落 CPU；或 `--device cpu` |
| `transcript.ok=false` 且模型下载失败 | `--model <本地模型目录>` 或设 `WHISPER_MODEL` |
| 图集（pics） | `type=pics`，逐张下载分析；无时长，抽帧跳过 |
| 抽不出帧 | `FFMPEG_BIN`/`FFPROBE_BIN` 指定路径，或把 ffmpeg 放进 `scripts/tools/` |
| 长视频慢 | 加 `--no-transcribe`，或调大 `--fps`（如 `2`） |

---

## 存储与清理规则

- 视频**下载到系统临时目录**，分析完**立即整目录删除**——不占内存。
- 帧与版图放工作目录 `.douyin-frames\`，供分析用；**分析完 `clean` 删掉**。
- 除用户明确说"留着视频"，否则一律不保留视频文件。

---

## 沟通风格（caveman 极简，默认生效）

讨论与汇报默认走极简风格，规则见同目录 `caveman/SKILL.md`：

- 结论先行；短句/碎片；砍客套、填充词、复述、铺垫。
- **原样保留**：命令、路径、精确报错、数值、代码。
- 例外（恢复正常语气）：安全警告、不可逆操作、用户表示没听懂。
- 汇报结构固定：结论 → 证据（路径/数值）→ 下一步。总量 ≤ 50 行。

---

## 合规边界

- 仅用于**个人学习/内容研究**类分析。
- 不要把下载到的视频再分发、二次发布或用于商业用途；不要协助去除他人作品水印后传播。
- 分析结论引用画面内容做概述即可，别整段搬运他人文案。
- cookie 仅存本机、仅用于本次解析，不上传、不共享。

