by Yht20927
基于 Bridge Framework 的抖音全自动评论管理工具。搜索视频、爬取全量评论(含嵌套回复)、AI 智能回复、运营仪表盘。
# Add to your Claude Code skills
git clone https://github.com/Yht20927/douyin-cliGuides for using ai agents skills like douyin-cli.
See how douyin-cli compares with popular alternatives.
douyin-cli is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by Yht20927. 基于 Bridge Framework 的抖音全自动评论管理工具。搜索视频、爬取全量评论(含嵌套回复)、AI 智能回复、运营仪表盘。. It has 179 GitHub stars.
douyin-cli's catalog security scan is still queued. You can run an instant dependency and prompt-injection check now with the "Scan for vulnerabilities" button above.
Clone the repository with "git clone https://github.com/Yht20927/douyin-cli" and add it to your Claude Code skills directory (see the Installation section above). douyin-cli ships a SKILL.md manifest, so compatible agents can discover and load it automatically.
douyin-cli is primarily written in JavaScript. It is open-source under Yht20927 on GitHub, so you can review or fork the full source.
Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh douyin-cli against similar tools.
No comments yet. Be the first to share your thoughts!
Available after the catalog security scan passes.
⚠️ Third-Party Software Notice
This skill is third-party open-source software developed and hosted independently on GitHub. SkillsLLM is an informational directory and does not control or maintain the underlying repository.
Any security checks, ratings, or warnings displayed by SkillsLLM are automated and limited in scope. They do not constitute a security certification or guarantee that the software is safe, error-free, or free from malicious code, vulnerabilities, compromised dependencies, or prompt-injection risks.
Review the source code, permissions, dependencies, and configuration before installing or running any third-party skill. Use is at your own risk. To the maximum extent permitted by applicable law, SkillsLLM is not liable for losses arising from third-party software.
The deep catalog scan for this skill is still queued. Run an instant dependency check now instead.
本 skill 只描述命令如何调用,不含业务策略。
命令一律在 skill 目录下执行(~/.claude/skills/douyin-cli/ 或 ~/project/douyin-cli/,两份等价):
cd ~/.claude/skills/douyin-cli
19422;配置在 config.json(缺省时 cp config.example.json config.json)。bash scripts/bridge.sh ensure # 幂等地保证 Bridge Server 在线;返回 0 = 在线
node cli.js help # 打印全部命令
浏览器侧需:Tampermonkey 启用 + 已装 scripts/douyin.user.js + 打开并登录 douyin.com 任意页面。
确认油猴已连上:
curl -s http://127.0.0.1:19422/api/status | grep -o '"douyin.com"' || echo OFFLINE
输出 OFFLINE 时刷新 douyin.com 页面 / 检查 Tampermonkey 是否启用 / 重装 scripts/douyin.user.js。重启 server 不会修好油猴未连接。
scripts/bridge.sh stop 只能在首次 start 的目录执行(PID 文件所在侧);server 是常驻的,跨 session 复用,通常不需要 stop。
post / like / delete-comment / 图片上传)由 risk-control 硬强制 40-55 秒随机间隔:调用会阻塞等待后才返回,不要在外面再叠加 sleep。带等待的 Bash 调用把 timeout 设到 120000 以上。--no-throttle 可跳过节流(调试用)。get / search / replies / my / user / download)不内置节流。一个浏览器容器/窗口登录一个账号,油猴脚本探测当前登录 uid 并据此注册连接(channel = douyin.com#<uid>)。服务端按账号分别持有连接,可同时在线多个。
未登录的标签页不会连接:油猴只认 /aweme/v1/web/query/user/ 接口返回的 uid(不走 cookie/localStorage 兜底——UIFID 之类的残留值在同设备多账号下甚至会把两个号算成同一个)。拿不到 uid 就不注册,每 15 秒重试;登录后自动接入。服务端也拒收无账号的连接。
⚠️ 改协议后必须重装油猴脚本:脚本头部没有
@updateURL,Tampermonkey 不会自动更新。旧脚本注册时不带account字段,会被服务端以client_outdated拒掉——表现就是"明明登录了却连不上"。每个浏览器容器/资料都要各自重装scripts/douyin.user.js。服务端会区分两种情况:
client_outdated= 完全没带 account → 脚本太旧,去重装account_required= account 是空串 → 该标签页没探测到登录态,去登录怎么自证脚本是新的:脚本会把注册契约版本(
clientVersion)随注册上报,accounts里能看到。版本对不上时accounts会标scriptOutdated: true,每次调用的横幅也会打一行⚠ … 的油猴脚本不是最新版 … 去 Tampermonkey 重装 scripts/douyin.user.js。这是「脚本太旧」与「新脚本但探测失败」的唯一区分手段——两者在服务端都表现为字段为空。
每次调用都会往 stderr 打一行账号横幅(stdout 的 JSON 不受影响):
$ node cli.js get <aweme_id>
[账号] 在线 2:主号(ACC_A)、ACC_B(读操作按账号轮换)
[账号] 本次由 主号(ACC_A) 服务
{ ...JSON... }
$ node cli.js post <aweme_id> "内容" --account 主号
[账号] 指定 主号(ACC_A)(在线 2:主号(ACC_A)、ACC_B)
{ ...JSON... }
展示名优先级:别名 > 平台昵称 > uid(括号里始终带 uid,它是唯一能被 --account 精确定位的标识)。昵称随注册上报,仅用于展示——不参与 --account 寻址(昵称会改、也可能重名)。
昵称来源(douyin):只读零请求的 localStorage.user_info,且必须与严格探测出的 uid 一致才采用——那份本地数据可能是别的账号或登出残留写下的,uid 对不上就宁可不要昵称,也不能把 A 号的名字挂到 B 号上。拿不到就留空,不影响接入。
/aweme/v1/web/query/user/换哪组参数都只回顶层{id, user_uid, user_uid_type, status_code},没有昵称、也没有user对象——别想从这个接口要昵称或sec_uid。昵称读本地来源(localStorage.user_info,与严格 uid 对齐);sec_uid读/aweme/v1/web/user/profile/self/的user.sec_uid(见下)。
// node cli.js accounts
{ "id": "主号", "account": "1179139456380456", "nickname": "Ya 小九.", "alias": "主号", "online": true }
{ "id": "小号B", "account": "123456789", "nickname": "小号B", "alias": null, "online": true }
无账号在线时会提示 [账号] 无账号在线 — 确认浏览器已登录对应账号并打开站点页面。设 DOUYIN_NO_ACCOUNT_BANNER=1 可关掉横幅。
| 场景 | 行为 |
|---|---|
公共读操作未指定 --account |
服务端按账号轮换(每号独立冷却;刚写过的号排到后面);同一条命令内钉扎——首个子请求选中哪个号,后续分页/子调用都跟着它,避免跨号拼 cursor |
读操作指定 --account |
精确路由到该账号,找不到就报错(不会回退到别的账号) |
写操作 / 读取自身数据(my、dm list、dm listen)未指定 --account,在线账号 > 1 |
直接报错退出,列出可用账号 |
| 同上,在线账号 = 1 | 自动采用该账号(保持单账号时的旧行为) |
为什么
my/dm list与写操作同等待遇:它们返回的是「当前账号自己」的数据,多号下不指定就是「随机挑一个号的作品/私信当成通用结果」,必须显式指定。
node cli.js accounts # 列出账号:id / account / nickname / alias / 在线 / 最近服务时间
node cli.js accounts alias <uid> 主号 # 给账号起别名,之后 --account 主号 即可
node cli.js --account 主号 get <aweme_id> # 用指定账号拉评论
node cli.js search "关键词" --account <uid> # 别名和 uid 都收
node cli.js post <aweme_id> "内容" --account 主号 # 写操作:多账号时必须显式指定
--account 也可用环境变量 DOUYIN_ACCOUNT 提供(campaign 的 daemon 子进程靠它继承身份)。
跨账号的共享与隔离:
comments.replied)与回复语料(reply_corpus)全局共享——任一账号回过的评论,其他账号都不会再回。events)、草稿(drafts)、活动(campaigns)按账号记录。events.account 记的是实际服务该次调用的账号(含按轮换落到的号)。videos)的 is_mine 是归属声明,videos.account 记它属于哪个号(非 is_mine 的视频为 NULL)。log / events / dashboard / profile / videos 也吃 --account:作为过滤条件只看该账号的记录;不指定 = 全部账号。whois / note / corpus / replied / failures / dedup / comment 等只读写本地全局数据的命令与账号无关:--account(含 DOUYIN_ACCOUNT 环境变量)一律忽略,不会因账号离线而报错。不用浏览器也能验一遍服务端契约(起临时 server + 两个假客户端,跑完自动收尾):
node scripts/smoke-accounts.js
node cli.js my # 我的作品(多账号必须 --account:读的是「哪个号」自己的作品)
node cli.js my --count 20
node cli.js my --account 主号 # 多账号下指定是哪个号
# sec_uid 来源:权威来源 = /aweme/v1/web/user/profile/self/ 回包的 user.sec_uid(随会话走,
# 天然是当前账号);接口失败才退回本地来源并做 uid 对齐(CLI 把 --account 落到的号经
# myPosts 第 3 参传入)。取不到就**明确报错**,不再用空 sec_user_id 静默查询。
node cli.js user <sec_user_id> # 任意用户主页作品
node cli.js user <主页URL> # URL 形式亦可
node cli.js user <sec_user_id> --count 18
node cli.js user <sec_user_id> --cursor 1782389806000 # 翻页,用上次返回的 max_cursor
user 输出:
{
"user": { "uid": "2988943290152652", "sec_uid": "MS4wLjAB...", "nickname": "Ya 小九." },
"has_more": 1, "max_cursor": 1783213200000, "min_cursor": 0, "count": 6,
"aweme_list": [{
"aweme_id": "7631450655144736931", "desc": "...", "time": 1776835569,
"duration": 37408, "is_top": true,
"stats": { "plays": 0, "likes": 18600, "comments": 109, "shares": 513, "collects": 1123 },
"cover": "https://..."
}]
}
count 是建议值,实际可能略多(置顶 is_top=true 不占配额);他人作品 plays 恒为 0(接口限制)。isMine=false 落库并记录 author_uid。node cli.js search "周杰伦"
node cli.js search "周杰伦" --offset 10 --count 20
[{ "aweme_id": "7533234103531261243", "desc": "...", "author": "瓶妞Lottie英语",
"uid": "83925411173", "time": 1754007300, "plays": 0 }]
搜索接口不返回播放/点赞数(plays 恒为 0)。
node cli.js get <aweme_id> # 默认 1 页 20 条
node cli.js get <aweme_id> --pages 5
node cli.js get <aweme_id> --count 20
node cli.js get <aweme_id> --all # 全部一级评论
node cli.js get <aweme_id> --all --depth 1 # 含嵌套回复(每条最多 50 条)
node cli.js get <aweme_id> --all --depth 1 --reply-limit 20
node cli.js get <aweme_id> --new # 增量:上次成功 get 之后的新评论
node cli.js get <aweme_id> --new --depth 1
node cli.js get <aweme_id> --since 1780238354 # 增量:create_time > 指定 Unix 秒
--depth 1 递归一层、--depth 2 递归两层。--new 依据审计日志中该视频上次成功 get 的时间戳,无历史时退化为全量。
--depth 1 时每条一级评论带 children:
[{ "cid": "7646...", "text": "一级评论内容", "likes": 1, "replies": 3, "time": 1780238354,
"user": { "nickname": "用户", "uid": "123", "avatar": "https://..." },
"children": [{ "cid": "7647...", "text": "回复内容", "likes": 0, "replies": 0,
"time": 1780239000, "user": { "nickname": "回复者", "uid": "456", "avatar": "https://..." } }] }]
node cli.js replies <cid> <aweme_id>
node cli.js replies <cid> <aweme_id> --count 20 --cursor <ts>
输出格式同 get 的结果项(无 children)。
node cli.js post <aweme_id> "好看!"
node cli.js post <aweme_id> "说得对" --reply-to <cid>
node cli.js post <aweme_id> "@1179139456380456 内容" --reply-to <cid> --at <uid> <sec_uid>
node cli.js post <aweme_id> "回复子回复" --reply-to <cid> --reply-to-reply <rrid>
输出:
{ "cid": "7646...", "text": "好看!", "time": 17802..., "status": "published" }
失败时返回 { "error": "status_code=8" }。文本中的引号会被自动转义。
post 是写操作,受 40-55s 间隔约束并计入风控断路器。
node cli.js post <aweme_id> "这个封面绝了" --image cover.jpg
node cli.js post <aweme_id> "看下我的版本" --reply-to <cid> --image v1.png
node cli.js post <aweme_id> "对比一下" --image a.jpg,b.jpg,c.jpg # 可重复 / 逗号分隔
node cli.js upload-image --image cover.jpg # 只上传不发,返回 uri
{ "cid": "7646...", "text": "这个封面绝了", "status": "published",
"images": [{ "uri": "tos-cn-i-xxx/abc", "width": 240, "height": 180, "format": "jpeg" }],
"image_count": 1 }
upload-image 输出 { "uri": "...", "width": 240, "height": 180, "format": "jpeg", "size": 494 }。
jpg / jpeg / png / webp / gif / bmp / heic,单张 ≤ 10MB。image_count: 0 且带 warning → 服务端回包没带图,图片没挂上,但评论已按纯文本发出。node cli.js like <aweme_id>
node cli.js like <aweme_id> --unlike
{ "aweme_id": "7629735841874726179", "action": "liked", "status": "success", "status_code": 0 }
node cli.js delete-comment <cid>
{ "cid": "7649651851377640192", "status": "deleted", "status_code": 0 }
只能删自己发表的评论。
node cli.js download <aweme_id>
node cli.js download <aweme_id> --audio-only # 仅 BGM
node cli.js download <aweme_id> --out ~/Videos
默认存到 ./downloads/,文件名 <aweme_id>_<作者>_<标题>.mp4;--out 目录不存在会自动创建。默认超时 120s。
{ "awemeId": "...", "title": "...", "author": "...",
"files": [{ "type": "video", "path": "./downloads/xxx.mp4", "size": 12345678 },
{ "type": "audio", "path": "./downloads/xxx_audio.mp3", "size": 1234567 }] }
node cli.js analyze <aweme_id> [--mode text-only|screenshots|video] [--screenshots N] [--all] [--depth N] [--force]
node cli.js suggest <aweme_id> [--auto] [--force] [--fast] [--min-priority N] [--interval ms]
[--mode text-only|screenshots|video] [--screenshots N] [--reply-to <cid>]
analyze 返回 [{ "cid", "sentiment", "category", "priority", "summary" }]。suggest 生成回复建议,--auto 自动发布。comments.replied=1 的 cid;--force 覆盖跳过。config.json 中的 llm.api_key。node cli.js getReply <aweme_id> # 生成视频顶级评论(只输出文本,不发布)
node cli.js getReply <aweme_id> <cid> # 生成对特定评论的回复
node cli.js getReply <aweme_id> --count 3 # 多条候选
node cli.js getReply <aweme_id> --persona <id> # 指定人格
node cli.js getReply <aweme_id> --batch # 对未回复评论批量生成
node cli.js getReply <aweme_id> <cid> --interactive # 生成→编辑→发布
--persona 取值:casual_friend / curious_asker / experienced_sharer / enthusiastic_fan / thoughtful_critic / humor_maker / brief_reactor。
node cli.js draft list [--video <aweme_id>]
node cli.js draft save <aweme_id> "文本" [--reply-to <cid>] [--persona <id>]
node cli.js draft show <draft_id>
node cli.js draft post <draft_id>
node cli.js draft delete <draft_id>
node cli.js dm send <sec_user_id> "私信内容"
node cli.js dm listen [--timeout N]
node cli.js dm list
node cli.js profile <uid> [--account <uid|别名>] # 用户交互历史(事件流;--account 只看该号)
node cli.js whois <uid> # 用户全量画像(评论 + 我的回复 + 标签)
node cli.js note <uid> [--tier vip|normal|blacklist|spam] [--tag T] [--untag T] [--notes "..."] [--clear]
node cli.js events [--tail N] [--video <id>] [--uid <uid>] [--cmd <cmd>] [--status success|error] [--since <ts>] [--json] [--account <uid|别名>]
node cli.js videos [--mine] [--account <uid|别名>] [--limit N] [--json] # 记忆层视频列表(含归属账号)
node cli.js corpus <search|recent|stats> [...] [--limit N] [--video <id>]
node cli.js replied [--json] [--aweme <aweme_id>] [--count]
node cli.js comment <cid> # 查询单条评论实体
node cli.js failures [--limit N] [--recent] [--mitigate <sig> "<缓解措施>"]
node cli.js dedup "<候选文本>" # 是否发过
node cli.js cleanup [--days 90] [--dry-run]
node cli.js preflight # 当前节奏状态(距上次写 / 距下次可写)
node cli.js preflight post # 预检某命令当前是否可执行
node cli.js repo-info [<owner/repo>] [--refresh] [--json] # 默认 Yht20927/douyin-cli;缓存 1h
node cli.js factcheck "<文本>" # 校对文本中的 star 数/仓库名/版本号
node cli.js browse [--max-notes N] [--count N] [--pages N] [--like-chance 0.2] [--fast]
node cli.js dashboard [--video <aweme_id>] [--days 14] [--account <uid|别名>] # 生成本地 HTML 并自动打开
node cli.js log [--tail N] [--video <aweme_id>] [--uid <uid>] [--command <cmd>] [--failed] [--account <uid|别名>]
node cli.js campaign create --name "618新品" --videos v1,v2 --daily-quota 20 [--goal ...] [--per-user-quota N]
node cli.js campaign plan <id> [--pages N] [--min-priority N]
node cli.js campaign run <id> [--limit N] [--daemon] [--no-throttle]
node cli.js campaign pause <id> | resume <id> | stop <id>
node cli.js campaign status <id> | list
run --daemon 以 detached 子进程跑 run,PID 写 storage/campaign-<id>.pid,日志写 logs/campaign-<id>.log。stop 杀 daemon + 清 PID + 置 paused(幂等)。未被执行的 task 保持 pending,下次 run 续跑。
node cli.js accounts # 列出账号(uid / 别名 / 在线 / 最近服务时间)
node cli.js accounts alias <uid> <别名> # 设置别名(写回 config.json)
node cli.js validate-prompts [<template>] # 校验 prompts/ 下模板格式
模板位于 prompts/:analyze.md / suggest.md / comment.md / reply.md / replies-batch.md / partial-reply-strategy.md。修模板后跑 validate-prompts。
| 选项 | 作用 |
|---|---|
--raw |
原始输出 |
--no-log |
本次不写审计日志 |
--no-throttle |
跳过写操作的 40-55s 节流(调试用) |
| 返回 / 症状 | 含义 |
|---|---|
status_code=8 |
评论被拦截(内容过短 / 重复 / 风控) |
status_code=3002121 |
内容级拦截;不触发风控断路器 |
status_code 非 0(like / delete-comment) |
风控或参数错误 |
Bridge Server not running / ECONNREFUSED |
Bridge Server 未启动 → bash scripts/bridge.sh ensure |
No connection for site 'douyin.com' |
油猴未连接:刷新 douyin.com 页面 / 检查 Tampermonkey |
Unauthorized |
config.json 的 bridge.token 不匹配 |
HTML 页面 / 非 JSON / 空响应 |
油猴侧非 JSON 返回,通常需刷新 douyin.com 页面 |
搜索结果 [] |
油猴 bridge 未加载,刷新 douyin.com 页面等自动重连 |
| 多个 douyin 连接 | 存在 iframe 或多 tab,Server 自动选第一个活跃连接 |
post 返回 published 但页面上看不到 |
comment.status:7 审核中,等 1-2 分钟再看 |
| 回复贴纸评论看不到 | 贴纸评论不支持文字回复 |
--new 无历史记录时拉全量 |
首次 --new 等价于 --all |
| 下载无 URL | 视频已删除 / 私密 / 被限流 |
logs/
├── audit.json 操作元数据(sessions → operations → apiCalls)
└── results/
├── get-<aweme_id>-<ts>.json 评论获取完整结果
└── search-<kw>-<ts>.json 搜索结果
get / search / my / replies)落地为独立 JSON;小结果(post / like / delete-comment / download / ping / stop)内联在 audit.json。SQLite 记忆层在 storage/douyin.db(WAL)。注意本 skill 在 ~/.claude/skills/douyin-cli/ 与 ~/project/douyin-cli/ 各有一份,两张库互相独立——跨目录查询会漏数据。
适用版本: v4 · 最后更新: 2026-08-27 · 维护者: Yht20927
抖音评论运营 CLI 工具。基于 Bridge Framework(Bridge Server + 油猴脚本),支持视频搜索、评论获取、AI 人格化回复、ReplyEngine 独立生成、草稿管理、运营仪表盘。
核心亮点:ReplyEngine 评论生成引擎(generateComment / generateReply / generateReplies)+ A-F 六类回复策略 + Anthropic & OpenAI 双 Provider 支持 + Token 用量追踪,让代管自有账号的评论运营全流程自动化。
同一套 Bridge Server + 油猴脚本架构的姊妹项目,欢迎 Star 与交流:
| 项目 | 一句话简介 |
|---|---|
| BossZhipin-cli | BOSS 直聘命令行工具:搜索职位、智能匹配评分、LLM 批量打招呼 |
| xiaohongshu-cli | 小红书评论 CLI:笔记搜索、评论获取、AI 人格化回复、行为模拟 |
| douyin-living | 抖音直播全自动录制 + AI 智能切片系统(录制 → 弹幕 → 语音识别 → 高光剪辑) |
| tiktok-cli | TikTok 评论 CLI:视频搜索、评论获取、AI 回复(参考 douyin-cli 架构) |
| ths-cli | 同花顺行情命令行工具:实时行情、K 线、多因子技术分析 |
| 功能 | 说明 |
|---|---|
| 🔍 视频搜索 | 关键词搜索视频 |
| 💬 评论获取 | 获取评论及嵌套回复,--new 增量拉取 |
| 🖼️ 图片评论 | 发表带图评论/回复(ImageX 上传链路,--image 可多张) |
| 🧠 ReplyEngine | 独立评论生成引擎,3 种模式 + 人格绑定 + 上下文隔离 |
| 🤖 AI 人格化回复 | 7 种人格自动轮换,A-F 六类回复策略,避免"AI 味" |
| 📝 草稿管理 | 回复草稿 save/list/show/post/delete 完整生命周期 |
| 🎭 行为模拟 | 模拟真实浏览(搜索→看视频→点赞),穿插在发布流程中 |
| ⏱️ 随机延迟 | 发布间隔 40-55s 随机 + 疲劳累加,模拟真人节奏 |
| 🎲 请求参数随机化 | browser_version 动态获取、paste_edit_method / enter_from 随机切换 |
| 🛡️ 风控断路器 | 10 分钟内 post 失败 ≥3 次自动暂停 |
| 📥 视频下载 | 下载视频+音频(BGM),支持 ffmpeg 截图多模态分析 |
| 📊 运营仪表盘 | 本地 HTML 可视化,含推广活动卡片 |
| 💾 持久化记忆 | SQLite schema v8(events / users / videos / comments / corpus / failures / campaigns / llm_usage / drafts) |
发表带图评论或回复。--image 可重复,也可用逗号分隔一次传多张:
# 图片评论
node cli.js post <aweme_id> "这个封面做得真好" --image cover.jpg
# 图片回复(回复某条评论)
node cli.js post <aweme_id> "看下我的版本" --reply-to <cid> --image v1.png
# 多张
node cli.js post <aweme_id> "对比一下" --image a.jpg,b.jpg,c.jpg
# 只上传不发(拿 uri 复用 / 调试)
node cli.js upload-image --image cover.jpg
上传链路(scripts/douyin.user.js 内实现,CLI 只负责递数据):
| 步骤 | 接口 | 说明 |
|---|---|---|
| 1 | GET /aweme/v1/web/comment/upload/auth/ |
取 ImageX STS 临时凭证(service_id / upload_domain / 密钥) |
| 2 | GET imagex.bytedanceapi.com/?Action=ApplyImageUpload |
AWS SigV4 签名,换上传地址 + StoreUri |
| 3 | PUT https://<UploadHost>/<StoreUri> |
传字节,带 Content-CRC32 与 X-Storage-U |
| 4 | POST ?Action=CommitImageUpload |
提交,返回 ImageUri / 宽 / 高 / 格式 |
| 5 | POST /aweme/v1/web/comment/publish/ |
文本 + image_uri_list / image_formats / image_widths / image_heights |
要点与限制:
jpg / jpeg / png / webp / gif / bmp / heic(按扩展名校验),单张上限 10MB,超过 4MB 建议先压缩crypto.subtle 做 SHA-256 / HMAC;签名算法对齐抖音前端内置的 ImageX SDK(region cn-north-1、service imagex)image_list 校验图片张数,不符会在结果里给出 warningimage_count: 0 警告,说明图片没挂上npm install
# 1. 复制配置
cp config.example.json config.json
# 编辑 config.json:填入 bridge.token 和 llm.api_key
# 支持 OpenAI 兼容 API 和 Anthropic 原生 Messages API(自动检测切换)
# 2. 启动 Bridge Server
node server.js
# 3. Chrome 安装油猴脚本 scripts/douyin.user.js
# ⚠️ Chrome 用户:需先在 Tampermonkey 中启用"允许访问文件网址"
# 详见下方「疑难排解」→ Chrome 连接问题
# 打开 douyin.com 并登录
# 4. 验证连接
node cli.js my
# 5. 开始使用
node cli.js search "关键词"
node cli.js get <aweme_id> --pages 1 --count 5
node cli.js suggest <aweme_id> --auto
node cli.js getReply <aweme_id> --batch
同一套 Bridge 可同时驱动多个抖音账号(一个浏览器容器/窗口登录一个号)。
核心规则:
site#uid 区分;未登录的标签页不接入。get / search / user …)未指定账号时按账号轮换,且同一条命令内钉扎在同一账号(避免分页 cursor 跨号错乱)。post / like / delete-comment / dm send …)与读取自身数据(my / dm list)在多账号下必须 --account 显式指定,绝不静默改投;指定了未知账号会直接报错并列出可用账号。log / events / profile / dashboard / videos 的 --account 是过滤条件,账号离线也能查历史(不参与路由)。whois / note / corpus / replied / failures / dedup / comment 等只读写本地全局数据的命令与账号无关:--account(含 DOUYIN_ACCOUNT 环境变量)一律忽略,不会因账号离线而报错。# 列出在线账号(uid / 别名 / 昵称 / 最近服务时间)
node cli.js accounts
# 给账号起个好记的别名(之后 --account 可用别名)
node cli.js accounts alias <uid> 主号
# 指定账号(读:只落该号;写/自身数据:多号时必填)
node cli.js my --account 主号
node cli.js post <aweme_id> "内容" --account 主号
# 本地记忆按账号过滤(不用 --account = 全部账号)
node cli.js log --account 主号
node cli.js events --account 主号
node cli.js videos --account 主号 --mine # 该号在记忆层里记录的作品
数据归属:events / videos / drafts / campaigns 记 account,可回答「这件事是哪个号做的」;平台内容表(comments / users / reply_corpus)全局共享(刻意设计:两个自己的号去回同一条评论是明显的异常信号)。
脚本版本:油猴脚本会向服务端上报 clientVersion;脚本落后于当前注册契约时,accounts 与横幅会打 ⚠ 提示去 Tampermonkey 重装 scripts/douyin.user.js。
设计细节与后续计划见
docs/multi-account-roadmap.md。
独立于 suggest 命令的新一代评论生成系统,支持三种模式:
# 评论模式:以普通用户身份生成视频的顶级评论
node cli.js getReply <aweme_id>
node cli.js getReply <aweme_id> --count 3 # 多条候选
node cli.js getReply <aweme_id> --persona casual_friend # 指定人格
# 回复模式:以博主身份回复单条评论
node cli.js getReply <aweme_id> <cid> # 自动加载视频上下文 + 用户画像
node cli.js getReply <aweme_id> <cid> --interactive # 交互式审核(生成→编辑→发布)
# 批量模式:对视频下所有未回复评论批量生成回复
node cli.js getReply <aweme_id> --batch # 自动跳过作者自评
ReplyEngine 架构:
7 种内置人格自动轮换,每条评论风格不同:
| 人格 | 特征 | 示例 |
|---|---|---|
| casual 朋友 | 口语短句,1-2 个 emoji | "哈哈哈这也太真实了😂" |
| 好奇提问型 | 以问句为主,真诚追问 | "这个是在哪里买的呀?" |
| 经验分享型 | "我之前也..." | "我之前试过,确实不错" |
| 热情追捧型 | 感叹号+emoji,情绪化 | "啊啊啊这个绝了!!" |
| 温和探讨型 | "我觉得..."委婉补充 | "说得挺有道理的,不过..." |
| 轻松幽默型 | 玩梗、自嘲、夸张 | "我的手:我会了 我的脑:不你不会" |
| 简短反应型 | 极简,3-15 字 | "真实👍" "马住了" |
使用:
# 生成建议(不发布,看风格)
node cli.js suggest <aweme_id>
# 自动发布(人格轮换 + 随机延迟 + 浏览穿插)
node cli.js suggest <aweme_id> --auto
# ReplyEngine 单条回复(自动绑定人格 + 用户画像注入)
node cli.js getReply <aweme_id> <cid>
模拟真实用户浏览行为,解决"只发不看"的账户不对称检测:
# 随机搜索热门词 → 看 1-2 个视频 → 偶尔点赞评论
node cli.js browse --max-notes 2 --like-chance 0.2
# 指定关键词浏览
node cli.js browse 穿搭 美食 --max-notes 3
suggest --auto 已内置 browse 穿插:每发约 5 条评论自动穿插一次浏览+点赞。
抖音油猴脚本内置多项请求参数随机化:
| 参数 | 随机化策略 |
|---|---|
browser_version |
动态读取 navigator.userAgent(非硬编码) |
paste_edit_method |
90% non_paste / 10% paste |
enter_from |
85% others_homepage / 15% search_result |
previous_page |
85% others_homepage / 15% homepage |
| 命令 | 用途 | 示例 |
|---|---|---|
my |
我的作品列表 | node cli.js my |
user |
查看用户作品信息 | node cli.js user <sec_user_id|主页URL> |
search |
搜索视频 | node cli.js search "关键词" --count 5 |
get |
获取评论 | node cli.js get <id> --pages 1 --count 5 |
replies |
获取回复列表 | node cli.js replies <cid> <aweme_id> |
post |
发表评论/回复 | node cli.js post <id> "内容" --reply-to <cid> |
post --image |
发表图片评论/回复 | node cli.js post <id> "内容" --image cover.jpg |
upload-image |
仅上传图片取 uri(不发评论) | node cli.js upload-image --image cover.jpg |
like |
点赞视频 | node cli.js like <id> |
delete-comment |
删除评论 | node cli.js delete-comment <cid> |
download |
下载视频+音频 | node cli.js download <id> [--audio-only] |
| 命令 | 用途 | 示例 |
|---|---|---|
analyze |
AI 分析评论情感/优先级 | node cli.js analyze <id> |
suggest |
AI 回复建议 + 自动发布 | node cli.js suggest <id> --auto |
getReply |
ReplyEngine 生成评论/回复 | node cli.js getReply <id> [<cid>] [--batch] |
draft |
草稿管理 | node cli.js draft <list|save|show|post|delete> |
browse |
模拟浏览行为 | node cli.js browse --max-notes 2 |
dashboard |
运营仪表盘 HTML | node cli.js dashboard |
| 命令 | 用途 |
|---|---|
replied |
已回复 cid 列表 |
corpus search/recent/stats |
回复语料库 |
failures |
失败模式 top-N(避雷清单) |
dedup |
查重护栏 |
whois |
用户全量画像 |
note |
用户标记(tier/tag/notes) |
comment |
单条评论实体查询 |
profile |
用户交互历史 |
events |
原始事件流 |
videos |
记忆层视频列表(--mine / --account / --json) |
log |
操作日志 |
| 命令 | 用途 |
|---|---|
preflight |
节奏守卫自检 |
repo-info |
GitHub 仓库真实信息(推广事实源) |
factcheck |
推广评论发布前事实校验 |
campaign |
推广引擎(create/plan/run/stop/status) |
validate-prompts |
校验提示词模板格式 |
| 命令 | 用途 |
|---|---|
dm |
私信发送/监听/列表 |
accounts |
多账号:列出在线账号 / accounts alias <uid> <别名> |
cleanup |
清理过期记忆(TTL) |
config.json(从 config.example.json 复制):
{
"bridge": {
"host": "127.0.0.1",
"port": 19422,
"token": "your-bridge-token"
},
"llm": {
"api_key": "sk-...",
"base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini",
"max_tokens": 4096,
"timeout_ms": 60000,
"max_retries": 3
},
"vision": {
"screenshot_count": 4,
"screenshot_width": 1024
}
}
LLM Provider 自动检测:
base_url 含 anthropic.com → Anthropic 原生 Messages APIbase_url 含 xiaomimimo.com → MiMo API(api-key 头)环境变量(优先级更高):
export OPENAI_API_KEY="sk-..."
export OPENAI_BASE_URL="https://..."
export OPENAI_MODEL="gpt-4o-mini"
CLI (cli.js) → HTTP/WS → Bridge Server (:19422) →