# Douyin Dub

> Reup video Douyin sang tiếng Việt bằng giọng AI, KHỚP GIÂY (dub-over), giữ giọng nhân vật nhất quán + phân biệt nhiều giọng. Dùng khi user dán LINK DOUYIN và muốn "dub / lồng tiếng Việt / reup lên Facebook/TikTok" (đặc biệt kênh ăn uống kiểu a Phong 邓炫疯疯). Input = 1 link Douyin.

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

---


# Douyin Dub — Playbook (input = 1 link Douyin)

Biến 1 clip Douyin (tiếng Trung) thành clip **lồng giọng AI tiếng Việt khớp giây**, giữ nguyên
hình + tiếng nền (nhai/ồn quán "thở" ở khoảng lặng). Máy lo phần cơ học (tải, bóc lời, TTS, ráp,
**tự chấm độ khớp**); **BẠN (Claude) lo phần đầu**: dịch thời thượng + phân giọng + vá câu lệch.

```
link ──dl.py──▶ video.mp4
video ──dub.py transcribe──▶ segs.json {start,end,zh,spk,vi:""}      (Whisper large-v3, zh)
segs.json ──[CLAUDE điền tay]──▶ segs_vi.json  (vi thời thượng + spk đúng)   ◀── KHÂU QUAN TRỌNG NHẤT
segs_vi.json ──dub.py render --no-voice──▶ pre-duck.mp4 + 3 SRT (gộp/.A/.B) + "📊 KHỚP %"
pre-duck.mp4 ──caption.py──▶ *_cap.mp4 (hộp vàng lời Việt + CHE phụ đề Trung)
*_cap.mp4 ──ffmpeg che-góc (5b)──▶ final.mp4 (che nốt cột chữ Trung góc phải)   ◀── OUTPUT MẶC ĐỊNH
GIAO: final.mp4 (KHÔNG giọng AI) + 3 SRT  → user tự lồng giọng AI trong CapCut
```
**MẶC ĐỊNH: LUÔN ra `final.mp4` (caption che, KHÔNG giọng) + 3 SRT.** Giọng AI để user làm ở CapCut. Đừng tự lồng edge-tts trừ khi user yêu cầu.

## Đường dẫn (cố định)
- Code skill: `~/.claude/skills/douyin-dub/` (`dub.py`, `dl.py`, `caption.py`, `setup.sh`)
- Runtime (dùng chung với douyin-reup): `~/DouyinReup/`
  - `engine/douyin-downloader/` + `cookies.json` — **do douyin-reup/install.sh dựng**. Cookie hết hạn → gõ "refresh cookies" trong Claude Desktop, hoặc `engine/.venv/bin/python -m tools.cookie_fetcher --output ~/DouyinReup/cookies.json`.
  - `.dubvenv/` — venv dub (tạo bằng `setup.sh`). Ký hiệu **PY=`~/DouyinReup/.dubvenv/bin/python`**.
  - `dub/<id>/` — thư mục làm việc mỗi clip.

## Setup (1 lần)
```bash
bash ~/.claude/skills/douyin-dub/setup.sh
```
Cài dub venv: faster-whisper, edge-tts, pydub, audioop-lts, yt-dlp + **easyocr (cho caption — kéo theo torch ~2GB)**.
Cần sẵn `~/DouyinReup/engine` + `cookies.json` (chạy `douyin-reup/install.sh` nếu chưa có).
**Model Whisper large-v3 (~3GB) tải ở lần transcribe đầu**; **model easyocr (~100MB) tải ở lần caption đầu** (cache lại sau).

## Quy trình (mỗi link) — dùng PY và SK=`~/.claude/skills/douyin-dub`
1. **Tải:** `ID=$(basename <link> | grep -oE '[0-9]{6,}' | head -1)` (hoặc tự đặt); `D=~/DouyinReup/dub/$ID`
   `"$PY" "$SK/dl.py" "<link>" "$D"` → `$D/video.mp4`.
2. **Bóc lời:** `"$PY" "$SK/dub.py" transcribe "$D/video.mp4"` → `$D/segs.json` (mặc định `--model large-v3`).
3. **DỊCH + PHÂN GIỌNG (BẠN làm tay):** đọc `segs.json`, viết file patch điền `vi` (thời thượng) + sửa `spk`, xuất `$D/segs_vi.json`.
   → **SOI KHUNG HÌNH TRƯỚC** (`ffmpeg -ss T -frames:v 1`) tại các câu hội thoại để biết ai nói với ai (nam/nữ, già/trẻ) → chọn xưng hô + phân giọng cho đúng. Xem mục **XƯNG HÔ** + 2 mục dưới.
4. **Render pre-duck + 3 SRT (MẶC ĐỊNH — KHÔNG lồng giọng):**
   `"$PY" "$SK/dub.py" render "$D/video.mp4" --segs "$D/segs_vi.json" --sidechain --fit-cap 1.5 --no-voice --out dubbed.mp4`
   → **video pre-duck** (tiếng gốc tự nhỏ lúc có lời, to lại lúc im — KHÔNG trộn edge-tts) + **3 SRT**: `dubbed.srt` (gộp) + `dubbed.A.srt` (nhân vật chính) + `dubbed.B.srt` (phụ).
   In `📊 KHỚP %` — câu nào chồng giọng (`over_next>0.15`) thì **rút gọn câu đó** trong segs_vi.json → render lại (TTS cache nên nhanh). Lặp tới ~95%+.
5. **BURN CAPTION + CHE chữ Trung (MẶC ĐỊNH):** `"$PY" "$SK/caption.py" "$D/dubbed.mp4" "$D/segs_vi.json" "$D/final_cap.mp4"`  (→ bước 5b che góc ra `final.mp4`)
   → burn **hộp vàng lời Việt** đè + **che chữ Trung gốc** (mosaic bám từng khung). Chạy TRÊN video pre-duck (bước 4) → clip cuối vừa che vừa có caption. Xem mục CAPTION.
   ⚠️ Render mosaic-từng-vùng **CHẬM ~40–50 phút/clip 6 phút** — đúng look user CHỐT; **ĐỪNG đổi sang mask/blur-mạnh/pixelate-toàn-khung** (user đã chê "xấu"). Track OCR cache ở `<out>.track.json`.
   - **TÁI DÙNG CACHE OCR khi render lại:** chỉ sửa chữ (vd xưng hô) → `cp <out_cũ>.track.json <out_mới>.track.json` rồi chạy caption.py với out mới → **bỏ qua OCR ~40 phút**, chỉ burn lại (~5–10 phút). Pixel video giống nhau nên cache còn đúng.
5b. **CHE cột disclaimer chữ Trung dọc GÓC PHẢI** (kênh này LUÔN có dòng dọc `视频内食物均已吃完拒绝浪费…` ở góc phải trên — cố định, safety-net canh-giữa không phủ). Chạy 1 pass mosaic-góc SAU caption:
   ```
   ffmpeg -i final_cap.mp4 -filter_complex "[0:v]crop=170:560:910:0,scale=iw/16:ih/16,scale=170:560:flags=neighbor[m];[0:v][m]overlay=910:0[v]" -map "[v]" -map 0:a -c:v libx264 -crf 18 -preset veryfast -pix_fmt yuv420p -c:a copy final.mp4
   ```
6. **GIAO (MẶC ĐỊNH):** copy ra `~/Downloads/`: **`final.mp4`** (caption che + pre-duck, **KHÔNG giọng AI**) + **3 SRT**. → User tự lên **CapCut lồng giọng AI** (TTS: track chính = `.A.srt`, track phụ = `.B.srt`; hoặc 1 giọng = bản gộp).
   - *(Hiếm khi)* Muốn dub sẵn edge-tts: bước 4 bỏ `--no-voice` → `dubbed.mp4` có giọng (máy hơn CapCut).

## CAPTION — burn hộp vàng + che chữ Trung (caption.py)
Kênh này **phụ đề Trung nhảy vị trí lung tung** (y 0.4→0.95, có câu ở giữa khung) → không thể đặt cố định. Giải pháp **2 LỚP** (đã chốt với user):
- **Lớp CHE (mosaic) bám từng khung** = *lưới an toàn*: OCR (easyocr) dò vị trí chữ Trung mỗi ~0.33s → mosaic bám theo, che **mọi lúc** (kể cả lúc chuyển câu / caption đặt hụt → **không bao giờ lòi chữ Trung**).
- **Lớp CAPTION (hộp vàng chữ đen bo góc)** đè lên, đặt ở **median** vị trí chữ Trung.
- Lọc để chỉ nhận phụ đề: **canh giữa** (cx 0.36–0.64) + **dẹt ngang** (w/h≥1.15) + đúng vùng → loại chữ trên đồ ăn/tường/menu.
- Timing: kéo dài tới khi chữ Trung **biến mất thật** (bám tracking), cắt trước câu kế → hết sót đuôi.
- **CHẠY XONG PHẢI TỰ SOI:** chụp vài khung (`ffmpeg -ss T -i out.mp4 -frames:v 1 shot.jpg`) rồi Read đánh giá — user yêu cầu bước này.
- Chỉnh style trong `caption.py`: `YELLOW`, `FS` (font size), `PADX/PADY/RAD` (đệm/bo). Hộp **ôm sát chữ Việt** (đừng phình theo chữ Trung — user ghét hộp to).
- Giới hạn còn lại (đã báo user, chấp nhận): cột disclaimer góc phải → xử bằng pass che-góc (bước 5b); **sticker/caption ĐỘNG giữa khung** (vd "您说", "已傻眼") + **chữ trên màn LED/bảng trong bối cảnh quán** (vd "可以啊") vẫn lòi — safety-net đáy+góc không phủ, **báo user, đừng tự che** (che vùng động rất nặng); nặng+chậm (easyocr full clip ~10–15 phút).
- Dịch theo **nghĩa + cảm xúc**, giọng đời/trend TikTok VN. Giữ **năng lượng** nhân vật (hype, cảm thán).
- ⚠️ **ĐỪNG DỊCH "AN TOÀN"/SÁCH VỞ** (user chốt): teen Việt xài luôn từ mượn/lóng → phải TRENDY, không dịch phẳng.
  - **帥哥 = "soái ca"** (KHÔNG dịch "đẹp trai"/"anh đẹp trai" — mất chất). Teen Việt dùng "soái ca" thật.
  - `不爽` (khó chịu/nhìn ghét) = **"ngứa mắt"** (không dịch "khó ưa" cho lành).
  - `炫`/`炫饭` (ăn ngấu nghiến kiểu mukbang) = **"quất / đớp / chiến"**.
  - `牛`(giỏi/đỉnh) = **"đỉnh nóc / đỉnh nóc kịch trần"**; `年糕殺手` = **"chiến thần bánh gạo"**.
- **Cảm thán phải ĐA DẠNG, đừng lặp 1 từ:** luân phiên "Oáa / U là trời / Ối dồi ôi / Trời đất ơi / Mèn ơi / Xỉu". Đừng để "u là trời" xuất hiện 6 lần.
- **GIỮ CÂU VỤN** (cảm thán "Oáa", "Trời ơi", "Măm") cho tự nhiên — đừng bỏ hết (đã test: giữ vụn nghe đời hơn). Chỉ bỏ nếu user yêu cầu bản "thưa".
- Câu quá dài so với khe thời gian → viết **ngắn/punchy** (eval sẽ báo câu nào cần rút).
- **Từ lóng chuẩn (clone từ kênh reup đối thủ — nên xài):**
  - `đớp` = ăn · `thánh đớp / chiến thần` = thánh ăn · `phê` = ngon/đã · `chốt món/chốt đơn`
  - `biến thứ 2` = màn/lượt 2 · `xỉu ngang`, `xỉu up xỉu down` · `cháy túi` = tốn tiền
  - `dữ thần / dữ dội / xịn sò`, `tẹt ga`, `nức nở`, `u là trời`, `chuẩn bài`
  - `soái ca`, `ngứa mắt`, `quất`, `đỉnh nóc`, `ngon nhức nách`, `ăn là ghiền`, `cuốn`, `flex nhẹ`
  - ⚠️ Dùng vừa tay — nhồi slang quá đà thành **cringe**. Ưu tiên tự nhiên, punchy, đúng cảm xúc.
- **KHÔNG bịa số liệu/nội dung.** Whisper large-v3 vẫn nhoè vài câu ở audio ồn → đoán theo NGỮ CẢNH + hình, và nói rõ với user chỗ nào mình suy đoán.

## XƯNG HÔ (anh/chị/em) — SOI KHUNG trước khi dịch (user CHỐT)
Đại từ xưng hô phải đúng vai, đừng dịch phẳng "tôi/anh". **Trước khi điền `vi`, TRÍCH KHUNG HÌNH** (`ffmpeg -ss T -frames:v 1`) tại các câu hội thoại để nhìn mặt người đối diện (nam/nữ, già/trẻ so với nhân vật chính) rồi mới chọn:
- **Nói với KHÁN GIẢ** (cả nhà ơi / các bạn / anh em / 兄弟们/家人们) → nhân vật chính TỰ XƯNG **"tui"** (hoặc "mình"), **KHÔNG dùng "anh"**. (vd 家人们…我千古罪 → "Không thì **tui** mang tội thiên cổ mất!"). Gọi khán giả: "anh em / cả nhà / các sếp (爸爸们)".
- **Nói với MỘT NGƯỜI cụ thể trong khung** → theo tuổi+giới: nhỏ tuổi hơn → **"em"**; lớn hơn nam → **"anh"**, nữ → **"chị"**; tự xưng ngược lại. (vd a Phong→nhân viên nữ trẻ: "Anh đưa **em** 2000 tệ"; cô lớn tuổi→a Phong: "Cái gì vậy **em**?").
- **Nhân viên phục vụ → khách** (nhân vật chính): "anh/chị" + "dạ/ạ" lễ phép.
- Không chắc giới/tuổi người đối diện → soi thêm khung; nữ trưởng thành mà lưỡng lự → "chị" an toàn hơn "em".
- **Clip độc thoại mukbang** (như clip anh gym): gần như chỉ 1 giọng A nói với khán giả → dùng "tui" xuyên suốt, 1 file SRT là đủ. Đừng bịa nhân vật phụ.
- **Gen lại bản đã giao** → TẠO FILE MỚI (segs_vi2/make_vi2/final_v2…), đừng ghi đè bản cũ trừ khi user bảo không cần giữ.

## PHÂN GIỌNG (spk) — nhân vật chính phải NHẤT QUÁN
`VOICE_MAP` trong dub.py (VN edge-tts chỉ 2 giọng → phân biệt thêm bằng pitch):
| spk | ai | giọng |
|---|---|---|
| **A** | **nhân vật chính (vd a Phong) — CỐ ĐỊNH** | NamMinh, `+8%`, `+3Hz` (nam, năng lượng cao) |
| B | nữ (nhân viên/khách nữ) | HoaiMy `+5%` |
| C | nam khác | NamMinh pitch thấp `-8Hz` |
| D | nữ khác | HoaiMy `-6Hz` |
- **Tự phân giọng theo NỘI DUNG hội thoại**, đừng tin diarize tự động (audio quán ồn → hay gộp sai). Nhân vật chính = A xuyên suốt; câu của nhân viên/khách = B/C/D.
- Muốn đổi tông nhân vật chính → sửa dòng `"A"` trong `VOICE_MAP` (dub.py). User đã chốt: **giọng nhanh (`+8%`) nghe hay hơn**.
- ⚠️ **ĐỪNG pitch-hack edge-tts mạnh** (đẩy/hạ pitch ±40Hz+ để đổi tông/giả giọng khác) → nghe **méo, dở tệ**. edge-tts chỉ hay khi để giọng tự nhiên. Muốn chất giọng "xịn" như kênh reup VN (nữ sáng ~180Hz) → dùng **CapCut TTS** (`--no-voice` route) hoặc tích hợp **FPT.AI Ban Mai / Vbee** (cần API key). Kênh đối thủ dùng **2 giọng NỮ** (chính ~180Hz + phụ ~235Hz), không phải giọng nam.

## Cơ chế KHỚP (đã tinh chỉnh — đừng phá)
- **Neo mỗi câu đúng `start` gốc.** Câu tràn sang câu kế → **ép nhanh GIỮ NGUYÊN cao độ (atempo)** tối đa `--fit-cap` (mặc định **1.5**; atempo nên KHÔNG chipmunk như đổi frame-rate). Tràn xa quá → rút chữ.
- **`_trim`:** cắt IM đầu/cuối mỗi clip TTS (edge-tts hay chèn 0.3–0.6s → câu 2 chữ mà dài 1.4s). **Đây là đòn tăng khớp mạnh nhất** (50%→93%).
- **`--sidechain` (duck ĐỘNG):** lúc có giọng Việt → nén tiếng gốc; lúc IM → **tiếng gốc tự nổi lên** (nhai/ồn quán thở). Tự nhiên hơn hẳn duck cố định 12%.
- **Eval:** `over_next` = phần tràn sang câu kế (>0.15s = chồng giọng, LỖI thật). `over_act` (tràn khỏi khe cảnh gốc) phần lớn là nhiễu — bỏ qua nếu không chồng câu kế.
- Cache TTS: `~/DouyinReup/dub/<id>/.tts_cache/` (md5 theo text+giọng). Sửa 1 câu → render lại chỉ đọc lại câu đó.

## Bài học nhịp (từ phân tích kênh đối thủ reup cùng nhân vật)
- Đối thủ chỉ **nói ~45% thời lượng**, im 55% (để tiếng ăn/ồn quán thở). **Đừng dub dày đặc** — sidechain + giữ khoảng lặng làm việc này.
- Clip mukbang dài (6 phút) full-dub kiểu gì cũng dày → nếu user muốn "thưa" có thể (a) bỏ câu vụn, (b) cắt ngắn còn ~3 phút.

## Che chữ Trung / watermark
- **Phụ đề Trung cháy hình:** dùng `caption.py` (mục CAPTION ở trên) — vừa che vừa burn lời Việt.
- **Watermark/@ID Douyin** (nếu có): dùng MCP **douyin-reup** (`remove_watermark`). Clip a Phong đa số KHÔNG có watermark, chỉ có phụ đề.

## Thành thật (nói với user)
- Reup + dub **khó kiếm tiền bền** trên FB/TikTok (nền tảng phạt nội dung tái sử dụng; RPM VN thấp) — làm để TEST là chính.
- Whisper sai vài câu ở audio ồn → mình làm mượt theo ngữ cảnh (báo user).
- Xám pháp lý (bản quyền + ToS) là rủi ro của người vận hành.

## Lệnh nhanh (copy-paste)
```bash
PY=~/DouyinReup/.dubvenv/bin/python ; SK=~/.claude/skills/douyin-dub
D=~/DouyinReup/dub/CLIP1 ; mkdir -p "$D"
"$PY" "$SK/dl.py" "<LINK_DOUYIN>" "$D"                 # -> $D/video.mp4
"$PY" "$SK/dub.py" transcribe "$D/video.mp4"           # -> $D/segs.json   (Claude điền -> segs_vi.json)
"$PY" "$SK/dub.py" render "$D/video.mp4" --segs "$D/segs_vi.json" --sidechain --fit-cap 1.5 --out dubbed.mp4
# HOẶC cho CapCut (giọng đẹp hơn): thêm --no-voice -> ra dubbed.srt + video pre-duck (chồng TTS CapCut lên)
"$PY" "$SK/dub.py" render "$D/video.mp4" --segs "$D/segs_vi.json" --sidechain --fit-cap 1.5 --no-voice --out capcut.mp4
```

