抖音发布助手(douyin-upload)

SkillWeb & browsing

Lets your agent publish videos or image-text posts to Douyin using a logged-in browser session.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the 抖音发布助手(douyin-upload) skill

About this capability

Publishes video or image-text content to Douyin (creator.douyin.com). Built on Playwright with a persistent login state, it runs headless. The flow and selectors are ported from the open-source implementation douyin-upload-mcp-skill (including the HD publishing entry, tab switching, handling transco

What this skill tells your AI

The instructions your AI receives, as published by zju-real/easel in skills/openclaw/skill-douyin-upload/SKILL.md and read by ahel’s review.

在用户确认后,调用 douyin_publish.py 完成视频/图文发布

运行方式(Playwright,headless 可用)

统一走 ../../shared/scripts/douyin_publish.py(CWD=项目根)。Playwright + 持久化登录态驱动 抖音创作者后台,headless 即可发布——替代了旧的 CDP/puppeteer/MCP Node 死栈(需真实 Chrome, 本环境跑不了,已删除)。

依赖说明
playwright + chromium本环境已装(douyin_publish.py check 验证)
已扫码登录login 抠二维码成 PNG(默认 outputs/_login/douyin.png,Web「账号」页可扫)→ cookie 持久化到 ~/.easel-browser-profiles/DouyinProfile
干净网络 IP抖音对机房/代理 IP 更易触发风控短信墙(登录与发布都可能弹)。短信墙可过——脚本支持验证码回填(见「短信验证码处理」),无需家宽 IP;仍建议尽量用干净 IP 降低触发频率

能力范围

  • 现做:视频发布、图文发布、扫码登录、发布前预检(plan)。
  • 话题:写进作品简介的 #话题(抖音自动联想成话题)。
  • 视频发布含:上传等转码(≤5min)+ 选 AI 推荐封面。

风险提示

抖音自动化发布存在被平台风控/限流风险。默认提醒用测试号、小流量、人工复核。脚本已内置反检测 (--disable-blink-features=AutomationControlled + 逐字符输入 + zh-CN);风险不可完全消除。

执行流程

check(环境就绪?)
  → 未登录 → login(抠二维码,Web 账号页扫 或 CLI 扫)
  → plan(dry-run 预检:标题长度/媒体路径/步骤)— 给用户确认最终标题、简介、媒体
  → 发布前人设检查(见下)
  → publish / publish-video --exec(首次建议 --headed 校验选择器,OK 后 headless 复跑)
  → 【若弹短信墙】问用户验证码 → 回填 → 脚本自动过墙(见「短信验证码处理」)
  → 成功校验(脚本内置:发布后**读回创作者中心作品列表对账**——标题+时间窗对上该作品才算 success)
  → 发布后留痕(见下)

短信验证码处理(对话页发布必读)

抖音发布点「发布」后可能弹风控短信墙(提示『接收短信验证码』)。脚本已内置完整过墙能力(_handle_publish_sms:下发验证码 → 轮询码文件 → 填码提交,最多等 300s,可多次重输),但对话页里 agent 必须主动把验证码递进去——否则脚本会空等 300s 超时失败。

要码有两种姿势,先探测本部署支持哪种

printenv EASEL_ASKUSER_CARDS   # "1"=支持选项卡片(OpenClaw 2026.9.x);"0"/空=不支持(如 2026.6.11)
  • =="1" → 走 A. 卡片模式(同轮弹卡、当场拿码,体验最好)。
  • =="0" 或空 → 走 B. 文字等待模式(发文字要码 → 结束本轮 → 用户下一条消息回码 → 你写码文件)。2026.6.11 必须用这条,卡片在这版桥接不了、弹了也收不到答案。

无论哪种,前两步(后台启动 + 轮询)完全一样。

第 1 步:后台脱离启动发布(关键:必须能跨对话轮存活)

务必带 --status-file--sms-code-file(路径放 outputs/_login/ 下),并用 setsid+&+日志重定向把进程脱离当前 shell——否则本轮结束、openclaw 进程退出时会把它一起杀掉,文字等待模式就跨不了轮:

mkdir -p outputs/_login
setsid python skills/shared/scripts/douyin_publish.py publish-video --exec --no-proxy \
  --title "标题" --content "简介" --video /abs/v.mp4 --tags "旅行,攻略" \
  --status-file outputs/_login/douyin.publish.json \
  --sms-code-file outputs/_login/douyin.code \
  > outputs/_login/douyin.publish.log 2>&1 &

第 2 步:轮询状态

每 2–3 秒查一次,用短命令——别一次性长睡眠干等,墙一出现你才能立刻反应:

sleep 3; cat outputs/_login/douyin.publish.json

状态机(JSON 字段 state):starting→可能 sms_requiredverifyingsuccess/errorsuccess 只在发布后读回创作者中心作品列表、对账通过才写入,message 里带核验到的作品 id 与状态;读回没对上落 error,message 区分三种:登录态失效(需重新登录)/ 列表暂未见本次内容(需到内容管理页人工核对)/ 读回通道异常。

读到 state=="sms_required"(含『正在发送验证码』阶段——看到就立即要码,不必等短信到)后,按探测结果分流:

A. 卡片模式(EASEL_ASKUSER_CARDS==1)

马上调用 ask_user 工具弹【验证码卡片】要码——不要用普通文字消息(卡片自带「自行输入…」填空,用户填完提交你直接拿到数字)。参数模板(options 必需 2–4 个;验证码本身走卡片自带的自由输入):

{"questions":[{"id":"sms_code","header":"发布验证","question":"抖音发布触发短信验证:请把手机收到的 6 位验证码填进来(点「自行输入…」后输入数字)。","options":[{"label":"重新发送验证码"},{"label":"取消本次发布"}]}],"timeoutSeconds":300}

用户提交后按答案分流:纯数字(4–8 位) → 写码文件(见下);「重新发送验证码」 → 建重发信号文件后立刻再弹一张卡(问题改为「已重发——把新收到的验证码填进来」);「取消本次发布」 → 告知脚本会自行超时退出。整轮不结束,卡片答完接着轮询到 success/error

B. 文字等待模式(EASEL_ASKUSER_CARDS==0 或空,如 2026.6.11)

后台进程已用 setsid 脱离、会一直等码(≤300s),所以你可以放心结束本轮、把要码交给下一轮:

  1. 发一条普通文字消息告诉用户:抖音发布触发短信验证,请把手机收到的 6 位验证码直接发给你;若没收到可回「重发」。然后结束本轮(不要在本轮里 sleep 干等,用户此刻还没输码,Bash 白卡)。
  2. 用户下一条消息就是验证码(同一会话,你能看到发布上下文)。按内容分流:
    • 纯数字(4–8 位) → 写码文件(见下),然后立即恢复轮询(后台进程还活着,cat 状态文件即可);
    • 含「重发/没收到/重新发送」→ 建重发信号文件(见下),告诉用户已请求重发、收到新码再发你,本轮再结束等下一轮;
    • 「取消」→ 建取消/等超时,告知用户本次发布将退出。
  3. 恢复轮询后若又回到 sms_required(码错/重发),重复本流程:再发文字要码 → 结束本轮 → 下轮收码。

跨轮要点:别每轮都重新起发布进程——第 1 步只在最开始跑一次。后续轮里先 cat outputs/_login/douyin.publish.json 看它是否还在 sms_required/verifying,在就只写码/轮询,不要重复 publish。

写码文件 / 重发信号(两种模式通用)

纯数字写进码文件(一次性消费,脚本读走即删):

printf '%s' "123456" > outputs/_login/douyin.code

请求重发(脚本收到信号会在墙上点「重新发送」再下发验证码,一次性):

touch outputs/_login/douyin.code.resend

继续轮询直到 success/error。码错会退回 sms_required,可再要一次重写。

要点:验证码文件内容是纯数字(4–8 位);全程保持"后台脚本 + 短轮询"模式——绝不要同步前台阻塞跑发布(不带 &)再想中途问用户(Bash 会一直卡住直到脚本退出)。发布页(Web「发布中心」)已用同一套文件协议自动弹原生输入框,与对话页无关、无需 agent 介入,任何版本都能用。

速度要点(决定成败):墙出现 → 脚本识别(≤15s)→ 你读到 sms_required数秒内要码(卡片模式弹卡 / 文字模式发消息,别先长篇解释)→ 拿到码 → 立即写码文件(一条 printf 的事,不拖)。任何环节拖 30 秒以上,用户手机上的验证码就可能过期要重发。文字模式跨轮无妨(后台等 300s),但你自己收到码后别拖着不写。

发布前人设检查(有 Profile 时)

按 AGENTS.md「发布前人设一致性检查」:先 skill-persona-check 比对内容×画像,评分喂 python skills/shared/scripts/persona_gate.py check --score 85——低于 80 分时警告并给修改建议, 但不阻断发布;用户已明确要发布就继续执行。

发布后留痕

python skills/shared/scripts/persona_gate.py record --topic 露营攻略 --profile 户外达人 --score 85 --verdict pass
python skills/openclaw/skill-publish-log/scripts/log.py record --platform 抖音 --title "周末露营攻略" --profile 户外达人 --persona-score 85 --persona-verdict pass --skill-source skill-douyin-upload

必做约束

  • 发布前必须让用户确认最终标题、简介、媒体(先跑 plan)。
  • 图文发布必须有图片,视频发布必须有视频(二选一)。
  • 标题 ≤ 30 字(脚本校验,超限拦下)。
  • 文件路径必须绝对路径(脚本解析并校验存在)。
  • 首次或疑似改版:先 --headed 观察,校验通过再 headless。
  • 定位失败改 douyin_publish.py 顶部 SELECTORS 字典(单点集中,每条标了参考源)。

命令样例

python skills/shared/scripts/douyin_publish.py check
python skills/shared/scripts/douyin_publish.py login                     # 抠二维码扫码
python skills/shared/scripts/douyin_publish.py plan --title T --video /abs/v.mp4 --tags "旅行,攻略"
python skills/shared/scripts/douyin_publish.py publish-video --exec --headed \
  --title "标题" --content "简介" --video /abs/v.mp4 --tags "旅行,攻略"
python skills/shared/scripts/douyin_publish.py publish --exec --headed \
  --title "标题" --content "简介" --images /abs/a.jpg,/abs/b.jpg

Signals

GitHub stars
1k
Forks
171
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
skill-douyin-upload
Source
github.com/zju-real/easel