DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-douyin-watch

Douyin Watch

Let 大肥鱼 live on Douyin: new DMs wake the agent, which can reply to DMs, post comments, reply in comment threads, read notifications, and analyze videos; with frequency limits, deduplication, and post-publication verification.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-douyin-watch@0.4.8
READMECompatibilityVersions

Compatibility and provenance

Douyin Watch is published as dsh-douyin-watch and currently resolves to version 0.4.8. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
11/4/2026

Versions

0.4.8stable
10/28/2026
0.4.7stable
10/28/2026
0.4.6stable
10/28/2026
Show 9 more versionsCollapse versions
0.4.5stable
10/28/2026
0.4.3stable
10/25/2026
0.4.2stable
10/25/2026
0.4.1stable
10/25/2026
0.4.0stable
10/25/2026
0.3.0stable
10/25/2026
0.2.1stable
10/25/2026
0.2.0stable
10/24/2026
0.1.0stable
10/24/2026

Related plugins

Loading related plugins…

Latest
0.4.8
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
448.2 kB
Files
36
Surface
web
License
MIT
Source
npm
Weekly downloads
3,183
Security scan
✓ v0.4.8 scan passed
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in integrations-communication.

Remote Web Ui@linxin666/dsh-remote-web-uiScan-to-pair remote access for the dsh web GUI that shares one official interface: a QR beside the settings button pairs phones and PCs into the same Web GUI (a portrait-touch adaptation layer for phones, full desktop on PCs) through one-time tokens and rRemote Bridge@linxin666/dsh-remote-bridgeDSH remote bridge: the host half serves protocol v1 over one exact /ios/v1 WebSocket route — session roster, history baseline, prompting, live turn increments with tool activity, interrupt, and in-process agent approval — to a device paired by a one-shot Im@xmanrui/dsh-im把微信、飞书、企微、钉钉、QQ、Telegram、WhatsApp、Slack、Discord、Matrix接入DSH。 Connect Telegram, WhatsApp, Slack, Discord, Matrix, WeChat, Feishu, WeCom, DingTalk, and QQ to DSH.Ds Botds-botDS Bot: a team of long-lived Bots for DeepSeek Harness, with Main Bots, Bot-to-Bot messages and group chats

README

dsh-douyin-watch

让 DSH 里的大肥鱼真的活在抖音上:新私信会叫醒它,它能回私信、发评论、回楼中楼、把一条视频的文案和画面整理出来。

不是「只盯着看」的监控器 —— 它能动手,而且动手前会自己核对有没有发出去。


它到底能干什么

能做的事说人话
盯私信有人发私信,叫醒你指定的会话,把内容带进去
回私信按人设回一句,短句优先(长句容易被抖音静默吞掉)
发评论 / 回评在任意视频下评论,或挂到某条评论下面回评(能分辨"回顶层"还是"回楼中楼")
@ 人评论里真 @ 某人(对方会收到通知)
读楼中楼读某条评论下的所有回复,拿到每条回复的 id,才能精确回某一条
读任意视频评论区别人的视频也能读,带评论 id、昵称、时间、回复数
读互动通知谁 @ 了你、谁评论了你、谁点赞、谁关注
分析视频下载 → 语音转文字 → 抽帧拼一张联系表,一条视频看一次就够
分享卡片把视频以分享卡片发给某个人
挑视频从推荐流里挑几条候选(带热度、作者、链接)
自己刷视频可选:到点儿它自己刷推荐流,按你的规则挑出几条(热度/时长/互动都有),叫醒你或私信发给你
自己发评论可选配合上面:挑到合适的视频,自己看一遍(文案 + 画面联系表)再评一句,≤15 字,频率有上限
写日报可选:把这一轮刷到/评了什么写成一份 Markdown,落到你指定的目录
评论自动回可选:自己作品下的评论自动回 / 别人视频下的楼中楼自动回(默认关)

自己刷视频怎么开

  1. 设置页 →「自动刷视频」→ 打开「开启自动刷视频」。
  2. 填时间段(比如 18:30 → 09:00,可以加多段)和「每天最多刷几条」(0 = 不跑)。
  3. 想让它把结果发到私信:打开「结果私信发给我」。
  4. 想留下记录:打开「写日报文件」,再填日报目录(留空 = 当前工作区)。

跑起来之后,每一轮它自己做三件事:拉推荐流 → 硬筛(时长/热度/重复)→ 打分排序,然后把前 N 条(标题、作者、热度、链接)交给你或直接私信。 要不要顺手评论,取决于你怎么配置;评论不是默认行为。

它不做什么(硬边界)

  • 不刷量:评论有硬上限(每小时 / 每天),同一句 7 天内不重复发;超了直接拒发,不会自己绕过。
  • 不群发:一次一个对象。
  • 不改你账号:不换头像、不改资料、不点赞、不批量关注。
  • 不硬闯风控:遇到验证码/异常提示就停手,把现象报给你,由你人工过一次。

三分钟上手

  1. 装:DSH 设置 → 插件 → 添加,或 npm i dsh-douyin-watch 后在插件页装上。
  2. 登一次抖音:设置页 → 维护 →「切有头 + 触发验证」,在弹出的窗口里登录 / 过滑块;登录好后存一次登录态,之后无头也能用。
  3. 开总开关:设置页最上面的「启用插件」。默认只提醒、不自动回。
  4. 接上会话:「私信哨兵」里选一个钉死会话 —— 新私信才会叫醒那个会话。
  5. 想让它自动回私信:打开「主人消息自动回复」,并在「人设」里写一句短人设。

设置页怎么看

  • 运行状态:绿点=在跑;四格分别是「今日评论额度 / 最后读取 / 签名直连 / 最后唤醒」。
  • 私信哨兵:盯谁、多久读一次、要不要自动回。
  • 自动刷视频:可选,按时间段自己挑视频。
  • 人设:一行短人设(每轮都带,越短越省)+ 完整人设(点按钮才注入当前会话)。
  • 公开评论:评论区专用语气、禁止词、字数上限、每小时/每天上限。
  • 评论区自动回:总开关 + 两个细分(自己作品下 / 别人视频下)。
  • 维护:切有头过验证、清缓存(只删可重建的目录,登录态一个字节不动)。

出问题先看这几条

现象多半是什么怎么办
发私信显示成功、对方没收到抖音 IM 侧静默风控一条一句、别连发多段;等一会儿再试
评论发出去没反应被当成机器人降频;同一句会被去重闸拦住
弹「验证码中间页」无头被反爬拦了维护 →「切有头 + 触发验证」,人工过一次再切回
读楼中楼很慢(十几秒)没装签名直连见下方「可选:签名直连」
工具突然消失切换有头/无头导致插件重挂改 cordis.patch.yml 里 reloadNote 的值触发重挂

可选:签名直连(更快,不装也能用)

抖音的楼中楼接口不签名就不返回。插件里那条快路要两样东西:

  • 脚本:_deps\scripts\douyin-signer\signed_get.py(vendored cv-cat/DouYin_Spider 的 a_bogus,感谢原作者)
  • 依赖:pip install --target <_deps>\python curl_cffi cryptography

装了就一两秒读回楼中楼;没装会自动退回「打开页面点开回复」的老路,功能不受影响、只是慢。


以下是给改代码的人看的

下面是踩坑记录和架构说明,装插件的人不用读。

🔴 先看这个(凭据与开关,2026-10-24 加固)

  • douyin_cookie.txt 是密码级凭据:含 HttpOnly sessionid,拿到它 = 拿到这个抖音账号。 位置:DOUYIN_HOME(或 ~/.dsh/douyin-duty、或配置里的 home)。cookie-save.mjs 保存后会 自动收紧权限(Windows icacls /inheritance:r,只留当前用户/SYSTEM/Administrators;其它平台 chmod 600)。 别把它 copy 进仓库、别贴进聊天、别放网盘。
  • 配置接口有守卫:/api/douyin-watch/config 拒绝跨站请求(挡 CSRF),并且写操作只认本机回环—— 局域网/隧道(~/.dsh/mobile-access)或手机上打开设置页可以读,但保存会 403,改设置要回本机改。
  • 自动回复默认关(ownerAutoReply: false):默认只提醒、不替你说话。要自动回,去设置页显式打开。

⚠️ 给新会话的必读(动手改代码前,先把这段看完)

这个插件有很多看起来像 bug、其实是抖音机制的坑。过去已经因为「没搞清楚就乱改」返工了好几次。改任何流程前,先在真实页面上点开对应面板、用浏览器 dump 一次确认现状,再动手。

🔑 账号切换 / 二次验证(最常踩的坑,2026-10-24 血泪总结)

抖音账号一旦切换,或操作频繁,就会弹二次验证;无头模式下视频页还会弹「验证码中间页」反爬。完整解法:

  1. 无头被拦(登出 / 验证码中间页)→ 切到有头模式(改 dsh-browser-playwright.state.json 的 headless: false,或 DSH 设置里开)
  2. 在有头窗口里手动登录 + 完成二次验证 + 发一次评论
  3. 切回无头 → 验证已清,@ 就能正常发了

⚠️ 两个副作用,务必知道:

  • 切有头/无头时,DSH 的 browser 服务会短暂 inactive → 抖音插件的工具被「移除」(GUI 提示「移除 10 个」)。恢复办法:改 cordis.patch.yml 里 - id: douyin-watch 的 reloadNote 值触发重挂载(这是目前唯一不用重启 DSH 就能让工具回来的办法;直接改配置值,别只加注释——注释不触发)。
  • 登录态备份/恢复:douyin_save_login(把当前 cookie 存进 douyin_cookie.txt,含 HttpOnly)→ douyin_relogin(灌回)。换账号后先 save 一次,无头登出时 relogin 即可,不用手动再登。
  1. 改 index.js 必须重启 DSH 才生效。cordis.patch.yml 的配置是 patchReload: live(热重载),但 JS 代码不是——热重载即使重新 import 了模块,工具也会撞 already registered in this scope,等于没生效。所以改代码 → 重启。

  2. 评论区还是老 Draft.js,别误判。 评论编辑器是 .public-DraftEditor-content(点开评论框才渲染,点开前查是 0 个);mention chip 是 douyin_mention_word。看到 editor-kit-container / messageEditorinputArea / messageMsgInputmentionContainer 这些是私信聊天框的组件,不是评论区。不要据此去改评论选择器。

  3. 诊断前注意浏览器有多个 tab。 哨兵 watcher 会自己开 tab 读私信,活动 tab 常在 /chat 和视频页之间跳。browser_* 工具可能落在错误 tab 上,dump 出来的 DOM 不可信。先 browser_tabs 确认在哪个 tab。

  4. @(真 @)必须走原始 CDP。 session.press(ref, '@') 发的事件不带 text 字段,mention 弹层不弹。要用 session.cdp('Input.dispatchKeyEvent', { type:'keyDown', key:'@', code:'Digit2', text:'@', windowsVirtualKeyCode:50, nativeVirtualKeyCode:50 }) + 对应的 keyUp,然后等 ≥1200ms 再回车选人。这条是实测出来的,别改回 press。

  5. 回评(回复某条评论)走接口,不走 UI、不走 @。 就是 POST /aweme/v1/web/comment/publish/ 时 body 里带 reply_id + reply_to_reply_id(都等于对方评论的 cid)。插件里 douyin_comment 的 reply_to 参数就是干这个。@ 和回评是两条完全不同的路。

  6. 工具 output 里永远不要返回 undefined。 返回值会过「lossless JSON」校验,undefined 直接报 value is not lossless JSON。可选字段要么省略、要么给默认值('' / 0)。

  7. render 签名是 render(args, value),第二个参数才是工具返回值。 写成 render: (value) => ... 会拿到输入参数、显示全错(比如 douyin_send 永远显示「发送失败」)。统一用 render: (_args, value) => ...。

  8. 分享卡片和私信同走 IM 通道,会被风控静默丢弃。 从发送方账号看「已发出」,对方账号可能收不到。这是抖音 PC 端风控,插件只能如实报「已执行分享动作、送达未验证」,无法保证送达。


它做什么(watcher)

每 N 秒(可配):打开抖音私信页 → 读「<对端>」会话
    → 有新消息 → followup 到**钉死的那条会话**(没开着就 resume 恢复)
    → agent 用 douyin_send 回过去

两种绑定模式(2026-10-24 起):

模式怎么工作什么时候用
sessionId(推荐)先找活着的该会话 agent;没有就 ctx.agents.resume({ resumeSessionId }) 恢复它,再 followup就想固定一条会话,DSH 重启/换目录/会话没打开都不影响
targetCwd(老)靠 agent/created + 枚举,逮 cwd 匹配的 agent只在不填 sessionId 时兜底;目录不存在就永远空转(踩过)

⚠️ enabled 现在立即生效(改完就停/起哨兵);以前它只在挂载时读一次,设置里拨动是假开关。

设置页顶部有「运行状态」卡片(每 5 秒刷新,不用看日志):绿点=运行中 / 灰点=已停止 / 红点=出错,并显示「最后读取(N 条)」「最后唤醒」和最近一条错误。数据来自 /api/douyin-watch/config 响应里的 status(index.js 的 runtime 打点)。

⚠️ watched / runtime / stateOf / pinnedAgents 这些 const 必须声明在 enabled=false 的提前 return 之前——放后面会让它们停在 TDZ,接口直接 400、设置页永远「加载中…」(2026-10-24 踩过)。

🔴 home / cfgFile 必须在 patch 里写死:同一个 DSH 会同时加载 web / desktop 两个 profile 的实例。不写死就会出现「设置页改的文件 ≠ 哨兵读的文件」——症状是:改了没用、重启后配置像丢了。两侧共用一个文件后,再由 watcher.lock(30 秒心跳)保证只有一个实例在盯;没拿到锁的实例只保留设置接口,并且持锁实例每轮读一次配置文件,所以从哪个实例的设置页改都能生效。

resume 的模型路由(2026-10-24 血泪坑)

ctx.agents.resume({ resumeSessionId }) 不传 agentOptions 时,DSH 用空 {} 建 agent → agent.options.provider/model 都是 undefined。而预设人设是严格插值的模板 You are a coding agent powered by the {{model}} model.,所以那一轮连系统提示词组装都过不去:

prompt variable "{{model}}" has no value for this assembly (section "deployment:persona-prefix")

现象是:唤醒消息投递成功、turn 开始,但第 1 步就 turn/end error,没有 request/header(请求根本没发)。 (GUI 自己恢复会话时是 api-session 的 installModelSelection 在补这个变量;ACP/headless 则显式传 agentOptions,所以只有裸 ctx.agents.resume 会踩。)

插件在 resume 的 setup 里补了两处(installRouteForResumedAgent,见 index.js):

补哪里作用
system-prompt/assemble填 {{provider}} / {{model}} 变量,人设能渲染
agent/request空路由会报 agent "…" has no provider/model,这里补成会话自己的路由

路由解析顺序:会话待生效的 model/selection → 最近一次已发出的请求路由 → agent.options → 部署默认模型。 全都解析不到时不投递唤醒(只记一行日志),避免再炸一轮。日志里会写 已恢复会话 … (… 模型路由=deepseek-account/deepseek-flash),可据此确认补上了。

另外 ensurePinnedAgent 现在会先等 ≤1.2s 看有没有 GUI 正在创建/恢复的活 agent,避免抢在它前面多 resume 一份。

裸 resume 不会挂 preset(2026-10-24 血泪坑 ㉑)

ctx.agents.resume() 只恢复「会话 + agent」,preset 的组成(工具/提示词/技能)不在它里面。 GUI 打开会话走的是 api-session 的 composeAgent(),它做两件事:

const presets = ctx.get('agentPresets')
const id = (await presets.resolve(session.header.agentPreset)).id   // 会话头里记录的 preset
// 然后在 setup 里:
await presets.mount(agentCtx, id)

插件以前是裸 resume → 恢复出来的 agent 没有 preset 的插件树 → 会话里没有 pwsh / read / edit, 表现是:唤醒消息投递成功、turn 开始,但模型没工具可用(只能干看着)。 现在 installPresetForResumedAgent 在同一个 setup 里补上这一步(preset id 取会话头的 agentPreset,解析失败退回部署默认)。日志会写:

已给恢复出的 agent 挂上 preset=standard(工具/提示词按该 preset 组成)

读私信为什么必须 --force-chat(2026-10-24 血泪坑 ㉒)

tools/chat-read-once.mjs 老规矩是「只在非抖音页面上才导航」,本意是不抢用户正在看的视频页。 但首页 /「验证码中间页」也算 douyin.com —— 于是页面卡在那儿时:

  • 哨兵不导航 → 读 DOM 读到 0 条 → 返回 messages: []
  • 看起来和「没有新消息」一模一样:设置页「运行中 · 最后读取 0 条」,永不标已读、永不唤醒

现在哨兵调用时带 --force-chat:只要当前不在 /chat 就主动导航过去(工具操作期间哨兵是 pauseWatcher() 暂停的,所以不会抢 @/分享用的视频页)。另外脚本在读到 0 条时会多看一眼页面状态, 把原因写进 note、进日志和设置页的错误行,例如:

读私信受阻:页面停在「验证码中间页」,需要人工在有头窗口里过验证码(切 --headless=off 让用户手动过)
  • 用 targetCwd 钉死要叫醒的会话工作目录(多开会话时只有这一个被叫醒)。
  • 调用任何抖音工具时,watcher 会 pauseWatcher() / resumeWatcher() 自动暂停/恢复,避免和工具抢浏览器页面。

9 个工具

工具作用关键点
douyin_read读「<对端>」会话最近消息(带 sid + 已读 + 卡片 itemId)只读
douyin_send发一条文字私信 + 回读校验delivered 来自真回读(「我发的」消息里多出这条);read 恒 false(页面读不到已读)。短消息(≤10 字)通过率高
douyin_comment发顶层评论,或回评(传 reply_to)接口直发,不 @ 人,不弹验证
douyin_comment_at发评论并真 @ 主人(text_extra 接口直发)需要 user_id + sec_uid + type:0 + start/end 四件套,缺一个服务端就把 @ 剥掉
douyin_comment_delete删自己发的评论服务端校验是否本人
douyin_notice_read读互动通知(谁 @/评/赞/关注)只读,不标已读;type=31 是回评通知
douyin_share把视频以「分享卡片」发给主人页面内 hover 分享面板 → 点好友;送达受风控影响
douyin_pick刷推荐流取候选视频返回标题/热度/作者/时长/链接
douyin_analyze视频 → 文案 + 画面联系表详情接口取直链 → faster-whisper 转写 + 抽帧;收到分享卡片时自动跑;没人声时返回 no_speech:true 并照常给联系表;也支持 --video <本地文件>

公开评论的三道闸(lib/outbound-guard.mjs)

douyin_comment / douyin_comment_at 发出去之前,全部在本地过一遍,拦下来就不发、并把原因原样返回:

闸默认说明
字数≤ 60 字公开评论越短越安全(设置页可改)
禁止词亲,客服腔,欢迎关注,家人们,已读,感谢您的支持AI 最容易顺嘴说的客服腔
站外引导网址 / 裸域名 / 手机号 / 微信 / QQ / 邮箱 / 二维码公开评论区最容易被判营销
去重同一句 7 天内不许重发台账 comment-ledger.jsonl,key = 视频 + 对端 + 归一化文本
频次6 条/小时、30 条/天防批量刷评;只有真拿到 cid 才记账,失败不占额度

评论区自动回(可选,默认关)

打开后挂在私信轮询里一起跑(不新增定时器,避免两个循环抢 9334 浏览器):

每 commentScanMinutes(默认 10)分钟
  ├─ 自己作品下的评论:**读评论列表**(tools/work-comments.mjs)
  │    /aweme/v1/web/comment/list/ 拿 cid/昵称/正文/时间
  │    /aweme/v1/web/comment/list/reply/ 逐条探"我回过没有"(作者 uid 比对)
  │    —— 以服务端为准,不靠通知、也不靠 reply_comment(它经常是 undefined)
  ├─ 作品发布超过 commentWorkMaxAgeDays(默认 7)天的整条跳过(0 = 不限)
  └─ 通知:只补「别人回复了我的评论」(type 31)+ @你(45)
       顺带把 type 35/46 的作品 id 记进 my-works.json
  → pickReplyTargets():丢掉无 cid、自己发的、已回过、超时限(默认 48h)的
  → 还有剩 → followup 叫醒 agent,把 cid + 链接 + 公开评论语气一起给它
  → agent 逐条 douyin_comment({ reply_to }) 回评(过上面三道闸)

「作品发布多久就不回」和「评论多久以内才回」是两个不同门槛: 前者按作品发布时间算(老视频下面冒出来的新评论也不回),后者按评论时间算。

同一批 40 分钟内不重复催;commentMaxPerRound(默认 3)限制一次丢几条。

不回的几种情况(都写在 pickReplyTargets 里,不是靠 agent 记):

情况判定
只有 @、没有内容"@某人"、[表情]@某人 → 回“在呢”就像客服机器人
机器人 / 平台客服号commentSkipNicks(默认 豆包,抖音求真)按昵称命中
发了但服务端查不到台账里有、子评论里却没有 → 线程不可见,不再重试(豆包那种“假成功”)
自己发的 / 已回过 / 超时 / 作品太旧见上

也可以随时手动批量看:工具 douyin_work_comments(只读,返回每条评论的 cid 和"是否已回")。


关键机制速查

@(真 @)—— douyin_comment_at

点开 #comment-input-container → 点 .public-DraftEditor-content(聚焦)
→ CDP Input.dispatchKeyEvent 打 @(带 text:'@')
→ 等 1200ms
→ CDP Enter 选第一个候选
→ 检查 .public-DraftEditor-content 的 innerHTML 里有 douyin_mention_word
→ 补正文 → 点红色箭头(FE2C55)发布

回评 —— douyin_comment 传 reply_to

先 douyin_notice_read() 拿对方回评的 cid(type=31 条目)
→ douyin_comment(text=…, reply_to=<cid>, url=/video/<aweme_id>)
→ 内部 POST comment/publish,body 带 reply_id + reply_to_reply_id = <cid>
→ 挂到对方评论下面,不另开新楼

通知结构(douyin_notice_read 解析)

type=31(回评/评论通知)的结构是:

notice_list_v2[].comment.comment = {
  cid:     对方评论的 id(回评 reply_to 用它)
  text:    评论内容
  aweme_id:所在视频
  user:    { nickname, uid }
}

解析时循环里 blk = it[keys[m]],当 keys[m]==='comment' 时 blk = it.comment,所以取 cc = blk.comment 就是上面那个对象。别写成 blk.comment.comment(多取一层,结果是 undefined)。


本机私有配置(不进仓库)

个人标识和运行态都放在 $HOME(默认 ~/.dsh/douyin-duty,或 DOUYIN_HOME 指定的目录),仓库里一个都不留(见 .gitignore):

文件内容为什么要隔离
peer.json{ "nick": "示例好友", "sec_uid": "MS4wLjABAAAA…" }sec_uid 是账号唯一标识,公开出去等于把账号挂出来。chat-read-once.mjs 按 --to/--to-id → 环境变量 → peer.json 的优先级取值
douyin_cookie.txt含 HttpOnly sessionid 的完整 cookie密码级凭据,泄露即账号被接管
watch-config.json设置页写的那份个人偏好(会话 id、间隔、自动回复开关)
watch-known.json / watcher.lock / runtime.json去重状态 / 单实例锁 / CDP 端口纯运行态

配置(profile 的 cordis.patch.yml → - id: douyin-watch)

键默认说明
enabledtrue总开关
chatUrlhttps://www.douyin.com/chat私信页
peer空要盯的会话昵称(也可放在 $HOME/peer.json)
intervalSeconds30轮询间隔
maxWakeText3一次唤醒最多带几条正文
owner空主人昵称(私信/分享的收件人)
onlyNewesttrue只盯最新创建的会话
sessionId空钉死会话(推荐):只往这条会话投递;它没开着会自动 ctx.agents.resume() 恢复。留空才按 targetCwd 找
targetCwd空只叫醒这个工作目录的会话(sessionId 为空时才生效)
ownerAutoReplyfalse主人消息是否自动回;false=只提醒。默认关:自动替你说话必须显式打开
commentUrl默认视频douyin_comment/comment_at 不传 url 时用
strangerPolicynotify非主人消息策略

改配置热重载生效,不用重启(patchReload: live)。改代码才要重启。


环境要求(对外分发必看,2026-10-24)

依赖必须?说明
Node.js(DSH 自带)✅所有工具都是 .mjs,用 cfg.nodeBin(默认 process.execPath)执行
Chrome / Edge / Chromium✅9334 无头实例;lib/chrome.mjs 自动找,找不到可用 DOUYIN_BROWSER 指定
抖音登录态✅在 9334 里登一次,douyin_save_login 存 cookie,之后 douyin_relogin 恢复
Python + curl_cffi⚠️ 仅「签名直连」需要(可选)取候选 / 读通知仍是页面内同源请求(feed-pick.mjs / notice-read.mjs),不依赖 Python。但读楼中楼(/comment/list/reply/)不签名就不返回,所以 2026-10-28 起加了一条可选快路:_deps\scripts\douyin-signer\signed_get.py(vendored cv-cat/DouYin_Spider 的 a_bogus)自己算签名直连,需要 curl_cffi + cryptography。不装也能用:tools/comment-thread.mjs 会自动退回「打开页面点开回复」的老路,只是慢十几秒。

已知限制 / 风控

  • 私信 / 分享卡片会被风控静默丢:发出方看着成功、接收方收不到(8101 / IM 静默丢弃)。无绕过手段,只能低频 + 短文本(实测 ≤10 字通过率高)。
  • 换账号 / 操作频繁会弹「二次验证」:无头下视频页还会弹「验证码中间页」(滑块)。解法见上方「🔑 账号切换 / 二次验证」。已给 9334 Chrome 加了反检测(--disable-blink-features=AutomationControlled + stealth 脚本),滑块基本不弹,但风控强时仍可能弹。
  • @ 在无头下偶尔要重试:编辑器焦点会飘,comment-mention-ui.mjs 已带重试循环,但做不到 100% 一把过。失败时重跑一次即可。
  • 删评论要靠「回评拿 cid」绕路:评论列表接口按热门返回,自己的新评论(0 赞)沉底分页拿不到 cid。让主人回一条,从通知的 parent_id 拿自己的 cid 再删。
  • 只盯 peer 一个会话;多会话列表还没做。
  • 语音/图片等非文字消息只显示占位符。
  • 无头 UA 会被抖音静默拒:HeadlessChrome/151 打 /tab/feed、/notice 得到的是 200 + 空 body。走页面内请求前必须先用 Network.setUserAgentOverride 去掉 Headless 标记(feed-pick.mjs / notice-read.mjs 已内置;版本号用浏览器真实的,别硬写)。
  • 页面内请求必须 pauseWatcher():哨兵会把页面导航回 /chat,一旦导航,页面里的 fetch 永远不 resolve —— 表现是"卡住不动",既不报错也不超时。

架构(2026-10-24 定稿)

单浏览器:所有工具都走 9334 Chrome(chrome.mjs 通过 CDP 拉起,永远无头),不依赖 DSH 的 browser 服务。所以切 DSH 浏览器有头/无头不会再「移除工具」。

  • 读私信(哨兵)→ chat-read-once.mjs
  • @ → comment-mention-ui.mjs(CDP 真 @)
  • 评论/回评 → comment-api.mjs;删评 → comment-delete.mjs;通知 → notice-read.mjs
  • 发私信 → im-send.mjs;分享卡片 → card-share.mjs;刷候选 → feed-pick.mjs
  • 登录备份/恢复 → cookie-save.mjs / cookie-load.mjs;关闭时停靠页面 → park.mjs

文件

  • index.js —— 插件本体(watcher + 14 个工具)
  • cordis.patch.yml —— 挂载声明(bundle patch)
  • locale/*.json、icon.svg —— 插件列表里的中文名/描述/图标
  • tools/*.mjs —— 动作脚本(纯 Node;媒体链路靠 media-urls.mjs 截直链 + 技能里的 ffmpeg/whisper)
  • tools/comment-thread.mjs —— 楼中楼:先试签名直连(_deps\scripts\douyin-signer\signed_get.py),拿不到再点开页面收响应,最后兜底读 DOM
  • tools/video-thread.mjs —— 读任意视频(含别人的)评论区:顶层评论 + 可选楼中楼(楼中楼委托给上一个脚本)
  • tools/*.py —— 已弃用,仅历史参考

维护:清浏览器缓存(2026-10-24 加)

设置页「维护 → 清理浏览器缓存」= POST /api/douyin-watch/cleanup → ools/clean-cache.mjs。

  • 只删白名单目录:Default/Cache、Default/Code Cache、*GPUCache、*ShaderCache、Service Worker、component_crx_cache、Safe Browsing、CertificateRevocation、WasmTtsEngine(删了 Chrome 会重建)
  • 绝不碰:Default/Network/Cookies、Preferences、Local State、Default/Local Storage、Default/IndexedDB —— 脚本清完会再自检一遍这些文件是否还在,丢了直接报错
  • 先 Browser.close 再删(不然 EPERM),并等 CDP 端口真的死掉;删不掉的目录会二次重试
  • 顺带清 $HOME/inbox 里 7 天前的聊天图片(表情/封面)
  • 实测:profile 608.7 MB → 40.4 MB;清完浏览器自动重启,30 秒内恢复读取

人设(2026-10-24 加,省上下文设计)

两个字段,成本完全不同:

字段何时进上下文建议长度成本
personaShort每次唤醒都带一行≤60 字每轮几十 token
personaFull只在点「注入到当前会话」时进一次会话历史≤300 字一次性,之后靠记忆

为什么这么做:人设全文一旦进了会话,之后每轮请求都会带着它(上下文累积)。所以既不每轮拼进 prompt,也不自动注入——只在换会话 / 换人设时手动点一次。QQ 那类桥接插件的做法是「每 30 回合灌一次完整风格」,我们用「钉死会话 + 注入一次」更省。

接口:POST /api/douyin-watch/persona/inject → 优先 agent.inject()(只加上下文、不唤醒),老版本 DSH 没有 inject 就退化成 followup()(会多跑一轮),返回值里的 via 会告诉你走了哪条。

  • 清缓存会短暂断读:clean-cache.mjs 先关浏览器再删(否则 EPERM),重启后有概率撞「验证码中间页」,那 30–60 秒读不到私信,期间的消息会推迟到下一轮唤醒。看着像装死,其实没丢;碰上就切有头过验证。

更新日志

0.4.5(2026-10-28)

  • 签名直连读数据:新增可选快路 _deps\scripts\douyin-signer\signed_get.py(vendored cv-cat/DouYin_Spider 的 a_bogus)。 覆盖评论列表、楼中楼、搜索、通知;视频详情/作品列表仍被 Argus 拦(要 uifid + x-secsdk 第二层签名),继续走页面。 没装/没依赖时全部自动退回原路,功能不受影响。
  • 新工具 douyin_video_comments:读任意视频(含别人的)评论区,可选连楼中楼;楼中楼由 tools/comment-thread.mjs 负责, 三条路依次降级:签名直连 → 点开页面收响应 → 从已渲染节点挖 cid。
  • 评论发送更保守:发布接口回 200 但没给 cid 时,不再判失败 —— 先用签名直连把列表读回来按「文字 + 15 分钟内」核对, 找到就补回 cid;核不到也先记账锁句,7 天内同一句发不出去(防重复评论事故)。
  • 媒体链路修好:media-urls.mjs 补上音轨(music.play_url)、码率选择优先 H.264。 以前抽不到帧/没有声音,就是因为直链只有画面、音轨在另一条地址。
  • 评论区自动回拆两类:commentAutoReplyWork(自己作品下,默认开)/ commentAutoReplyOthers(别人视频下,默认关)。
  • 设置页:吸顶快捷跳转(按卡片固定锚点)、状态卡改四格(今日额度 / 最后读取 / 签名直连 / 最后唤醒)、 「已记住作品:N 个」、结尾「去 GitHub 点个星」。