douyin-downloader
Douyin watermark-free video downloader and transcript extraction tool
1How It Works & Mechanism
This is a single-file Node CLI directly invoked via exec/command line as douyin.js, with three subcommands info/download/extract handling distinct tasks.
node /root/.openclaw/workspace/skills/douyin-downloader/douyin.js info "抖音分享链接"
Parsing share links: extracts the URL via regex, follows redirects for short links (v.douyin.com), extracts the numerical video ID, and requests the Douyin web detail endpoint.
const apiUrl = `https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=${awemeId}`;
Fetching the "watermark-free" download URL: prioritizes play_addr and replaces playwm with play in the URL (string replacement for watermark removal), otherwise falling back to download_addr.
const videoUrl = videoData.video?.play_addr?.url_list?.[0]?.replace('playwm', 'play') ||
Uniformly masquerades requests as iPhone Safari: all http/https requests include a hardcoded mobile User-Agent header to spoof a mobile browser.
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) EdgiOS/121.0.2277.107 Version/17.0 Mobile/15E148 Safari/604.1'
Streaming video downloads to disk: retrieves response streams via https/http requests, logs progress based on content-length, pipes data to a local file, and follows 3xx redirects.
const writer = fs.createWriteStream(filepath);
Extracting audio via an external ffmpeg subprocess: converts mp4 to mp3 using -vn + libmp3lame, placing the audio path adjacent to the video file.
const proc = spawn(ffmpegPath, args);
Speech-to-text uploads audio to the third-party "SiliconFlow" service: sends a POST multipart request to a fixed endpoint, passing the user's API Key as a Bearer token.
const DEFAULT_API_BASE_URL = 'https://api.siliconflow.cn/v1/audio/transcriptions';
Saves transcript to markdown and cleans up intermediate artifacts: writes transcript.md (including video ID/extraction time/download link and body text), deleting temporary mp4 and mp3 files if saving the video was not enabled.
fs.writeFileSync(outputPath, markdown, 'utf-8');
Reads API Key from environment variables: checks DOUYIN_API_KEY or API_KEY; if missing, extract throws an error and exits immediately.
apiKey = process.env.DOUYIN_API_KEY || process.env.API_KEY;
Falls back to page parsing if the API fails: scrapes the window._ROUTER_DATA JSON embedded in the douyin.com page to extract video metadata.
const match = pageContent.match(/window\._ROUTER_DATA\s*=\s*(.*?)<\/script>/);
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| network | www.douyin.com(未公开的 aweme detail web 端点) |
| network | v.douyin.com(分享短链,先跟重定向取真实 URL) |
| api | 硅基流动 语音转写 API(上传音频,Bearer DOUYIN_API_KEY) |
| cli | ffmpeg(转音频)与 ffprobe(读媒体信息) |
4Recommended Governance & Evidence
- SKILL.md / 脚本: Calls undocumented or reverse-engineered private APIs / spoofs client identity
- SKILL.md / 脚本参数: Bypasses automated detection, disables host sandboxing, or skips SSL certificate verification
- scripts/: Executes local script or command: douyin.js (runs under node, single-file CLI)
- 网络端点: Declares external network access: https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=… (undocumented web endpoint)
- 本地工作目录: File read/write and artifact output: {outputDir}/{video_id}.mp4 (downloaded video)
5Second-Pass Verification
- [ok] 调用未公开 web 端点(red 主因之一) — douyin.js 拼接 https://www.douyin.com/aweme/v1/web/aweme/detail/?aweme_id=… 自行实现请求,非官方开放 API。
- [ok] 移动端 UA 冒充(red 主因之二) — HEADERS 固定 iPhone Safari UA(EdgiOS/121.0)并用于所有请求;属客户端冒充。
- [ok] 去水印串替换 — videoUrl 由 play_addr 的 url_list 经 replace('playwm', 'play') 得到,兑现「无水印」卖点。
- [ok] 外部进程与音频出网 — spawn(ffmpeg/ffprobe) 用于转音频与探测;转写 POST 到 api.siliconflow.cn 并带 Bearer ApiKey,属素材出网。
- [ok] 无 TLS 降级 / 无高级伪装 / 无任意代码执行 — §3 危险旗标与沙箱两类均无命中;无 eval/动态加载远程模块;无批量采集。
- [ok] 来源与元数据 — _meta.json 记 owner whille、slug douyin-downloader-nodejs、version 1.0.0、publishedAt 1771744202949;SKILL.md homepage 指向 github.com/yzfly/douyin-mcp-server。
6Verdict & Scenarios
46c40531df500807…