deepseek自动刷抖音的dsh插件,能读评论,@你的账号,点赞视频和发布视频
40.5/100
综合分
13
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/31 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add kdcadmin/dsh_douyin_tools该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · tool
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 3 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包dsh-douyin-life(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=22 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/28 20:43:59
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 256 处,展示前 75 条)
- 读取本地文件index.js:71
local = JSON.parse(readFileSync(join(PLUGIN_DIR, 'package.json'), 'utf8')).version || '' - 请求外部主机api.github.comindex.js:77
const res = await fetch('https://api.github.com/repos/kdcadmin/dsh_douyin_tools/contents/package.json', { - 发起网络请求index.js:77
const res = await fetch('https://api.github.com/repos/kdcadmin/dsh_douyin_tools/contents/package.json', { - 写入本地文件index.js:267
try { mkdirSync(outDir, { recursive: true }) } catch { } - 写入本地文件index.js:272
try { appendFileSync(logFile, line + '\n', 'utf8') } catch { } - 读取本地文件index.js:277
const st = statSync(logFile) - 写入本地文件index.js:279
try { renameSync(logFile, logFile + '.1') } catch { } - 读取本地文件index.js:552
if (existsSync(v)) return { command: v, args: [], via: 'venv' } - 读取本地文件index.js:574
const hasCaptchaFlag = () => { try { return existsSync(captchaFlagFile) } catch { return false } } - 读取本地文件index.js:577
const hasLoginBrowserFlag = () => { try { return existsSync(loginBrowserFlagFile) } catch { return false } } - 读取本地文件index.js:578
const mcpKeyNow = () => { const p = pythonNow(); return `${p.command}|${p.args.join(' ')}|${scriptPath}|${cfg.cdpUrl}|${(hasCaptchaFlag() || hasLoginB - 写入本地文件index.js:587
try { mkdirSync(join(stateDir, '.tmp'), { recursive: true }) } catch { } - 写入本地文件index.js:627
writeFileSync(dmSentFile, JSON.stringify({ items: items.slice(-300) }, null, 1), 'utf8') - 写入本地文件index.js:1001
try { writeFileSync(temp, [...new Set(ids)].join('\n') + (ids.length ? '\n' : ''), 'utf8'); renameSync(temp, replyIndexFile) } - 删除本地文件index.js:1002
finally { try { rmSync(temp, { force: true }) } catch {} } - 发起网络请求index.js:1516
const res = await fetch(base + '/json/version', { signal: AbortSignal.timeout(timeoutMs) }) - 执行外部命令来自配置/变量index.js:1577
const child = spawn(exe.path, args, { detached: true, stdio: 'ignore', windowsHide: false }) - 发起网络请求index.js:1628
const res = await fetch(url, { ...init, signal: AbortSignal.timeout(timeoutMs) }) - 删除本地文件index.js:1967
try { rmSync(join(stateDir, 'headless-overlay.yml'), { force: true }) } catch {} - 执行外部命令来自配置/变量index.js:2023
const child = spawn(dsh.command, args, { - 发起网络请求index.js:2160
const res = await fetch(a.base + '/chat/completions', { - 发起网络请求index.js:2193
const res = await fetch(String(url), { signal: AbortSignal.timeout(8000) }) - 删除本地文件index.js:3486
rmSync(full, { force: true }) - 删除本地文件index.js:3513
try { if (existsSync(mine)) { rmSync(mine, { force: true }); n += 1 } } catch { keep.push(it); continue } - 删除本地文件递归index.js:3535
for (const f of readdirSync(cache)) { try { rmSync(join(cache, f), { recursive: true, force: true }); n += 1 } catch { } } - 删除本地文件index.js:3840
try { writeFileSync(probe, String(Date.now()), 'utf8'); return true } catch { return false } finally { try { rmSync(probe, { force: true }) } catch {} - 发起网络请求client.js:26
const jget = async (p) => asJson(await fetch(API + p, { credentials: 'same-origin' })) - 发起网络请求client.js:27
const jpost = async (p, body) => asJson(await fetch(API + p, { - 写入剪贴板client.js:966
h('button', { 'data-dy-btn': '', onClick: () => { try { navigator.clipboard && navigator.clipboard.writeText(String(st.report || '')); setMsg('报告路径已复制 - 发起网络请求client.js:1044
fetch('/api/douyin-duty/log', { - 发起网络请求client.js:1102
fetch('/api/douyin-duty/log', { method: 'POST', credentials: 'same-origin', - 发起网络请求client.js:1280
fetch('/api/douyin-duty/memory', { credentials: 'same-origin' }) - 发起网络请求client.js:1289
const r = await fetch('/api/douyin-duty/persona', { - 读取本地文件lib/hostdeps.mjs:41
for (const n of readdirSync(join(npm, '@deepseek-ai'))) { - 读取本地文件lib/hostdeps.mjs:54
for (const p of readdirSync(join(dshHome, 'profiles'))) { - 读取本地文件lib/hostdeps.mjs:69
if (!existsSync(pkgFile)) return null - 读取本地文件lib/hostdeps.mjs:70
const pkg = JSON.parse(readFileSync(pkgFile, 'utf8')) - 读取本地文件lib/hostdeps.mjs:77
return existsSync(file) ? pathToFileURL(file).href : null - 写入本地文件lib/actions.mjs:26
mkdirSync(dir) - 写入本地文件lib/actions.mjs:27
try { writeFileSync(owner, JSON.stringify({ pid: process.pid }), { mode: 0o600 }) } - 删除本地文件lib/actions.mjs:28
catch (e) { try { rmdirSync(dir) } catch {}; throw e } - 读取本地文件lib/actions.mjs:33
const pid = JSON.parse(readFileSync(owner, 'utf8')).pid - 删除本地文件lib/actions.mjs:36
if (err.code === 'ESRCH') { unlinkSync(owner); rmdirSync(dir); continue } - 删除本地文件lib/actions.mjs:36
if (err.code === 'ESRCH') { unlinkSync(owner); rmdirSync(dir); continue } - 删除本地文件lib/actions.mjs:46
if (acquired) { try { unlinkSync(owner); rmdirSync(dir) } catch {} } - 删除本地文件lib/actions.mjs:46
if (acquired) { try { unlinkSync(owner); rmdirSync(dir) } catch {} } - 执行外部命令来自配置/变量lib/process.mjs:4
const proc = spawn(command, args, { cwd, env, shell: false, windowsHide: true, stdio: ['ignore','pipe','pipe'] }) - 读取本地文件lib/dsh-cli.mjs:10
if (!existsSync(executable) || !existsSync(join(root,'app.asar')) || !existsSync(shim)) continue - 读取本地文件lib/dsh-cli.mjs:11
const text = readFileSync(shim,'utf8') - 读取本地文件lib/mcp.mjs:17
const PKG = (() => { try { return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) } catch { return {} } })() - 执行外部命令来自配置/变量lib/mcp.mjs:40
this.proc = spawn(command, args, { - 写入本地文件lib/state.mjs:49
try { mkdirSync(dir, { recursive: true }) } catch { } - 读取本地文件lib/state.mjs:54
try { return JSON.parse(readFileSync(file, 'utf8')) } catch { return fallback } - 写入本地文件lib/state.mjs:60
writeFileSync(temp, JSON.stringify(value, null, 2), { encoding: 'utf8', mode: 0o600 }) - 写入本地文件lib/state.mjs:61
renameSync(temp, file) - 删除本地文件lib/state.mjs:62
} finally { try { unlinkSync(temp) } catch {} } - 读取本地文件lib/state.mjs:81
if (!existsSync(from)) { log(`缺文件:${from}(Python MCP 还没放进来,先跳过)`); return { copied: false, reason: 'missing-vendor' } } - 读取本地文件lib/state.mjs:82
const incoming = readFileSync(from, 'utf8') - 读取本地文件lib/state.mjs:83
if (!existsSync(to)) { - 写入本地文件lib/state.mjs:84
copyFileSync(from, to) - 写入本地文件lib/state.mjs:85
writeFileSync(hashFile, sha(incoming)) - 读取本地文件lib/state.mjs:89
const onDisk = readFileSync(to, 'utf8') - 写入本地文件lib/state.mjs:90
if (onDisk === incoming) { writeFileSync(hashFile, sha(incoming)); return { copied: false, reason: 'same' } } - 读取本地文件lib/state.mjs:91
const previous = existsSync(hashFile) ? readFileSync(hashFile, 'utf8').trim() : '' - 读取本地文件selfcheck.mjs:94
check('视频理解原型 run.py 在包内', existsSync(join(pluginDir, 'video-understanding-lab', 'run.py')), - 读取本地文件selfcheck.mjs:99
const yml = readFileSync(join(pluginDir, 'cordis.patch.yml'), 'utf8') - 读取本地文件selfcheck.mjs:108
const src = readFileSync(join(pluginDir, 'index.js'), 'utf8') - 读取本地文件selfcheck.mjs:231
check('家目录建出来了', existsSync(homeDir), homeDir) - 读取本地文件selfcheck.mjs:232
check('config.json 落了盘', existsSync(join(homeDir, 'config.json'))) - 读取本地文件selfcheck.mjs:233
check('duty.md 从 prompts/ 铺过来了', existsSync(join(homeDir, 'duty.md'))) - 写入本地文件selfcheck.mjs:265
mkdirSync(fakeComfy, { recursive: true }) - 写入本地文件selfcheck.mjs:266
writeFileSync(join(fakeComfy, 'old.mp4'), '') - 写入本地文件selfcheck.mjs:268
writeFileSync(join(fakeComfy, 'newest.mp4'), '') - 写入本地文件selfcheck.mjs:286
writeFileSync(fakeCli, - 删除本地文件递归selfcheck.mjs:383
try { rmSync(home, { recursive: true, force: true }) } catch { }
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
涉及外部主机:api.github.com
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/dsh-tools给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
README
由 DeepSeek 最新模型翻译生成dsh-douyin-life(刷抖音)
封面
DSH 插件。每天替使用者刷抖音:刷推荐流 → 看片(转写)→ 读评论 → 挑片写日报,顺手做点赞、评论(可 @ 你)、转发视频给你(附一句话 + 一个对味表情包)、续火花、回私信(含陌生人);需要发片时,也可以把本地渲染好的成片发到抖音(本地可选配置,不绑定任何渲染工具)。
登录:设置页点「浏览器登录」→ 直接弹出带界面的 Chrome 打开抖音登录页,在里面扫码或收短信验证码,登录成功后自动切回后台无头运行(也可以继续用「截图登录」拿二维码)。
装法:从插件市场 / npm 装,或把源码目录 link 进 profile。设置页有「刷抖音」一页(日常 / 刷视频 / 互动 / 私信 / 表情包 / 高级 六个 tab),左侧还有「记忆」页(插件自带记忆 + 人设,不依赖任何记忆插件)。
接口契约见 SPEC.md。发布说明见 PUBLISH.md。
装完先让 agent 做的 5 步(写给模型看的)
这段是给 agent 的执行清单:不跑完这几步,插件「装了但用不了」。按顺序做,别跳。
1. 装 Python 依赖(MCP) —— 插件自带 Python MCP,依赖在 vendor/douyin-mcp/requirements.txt(mcp<2、playwright、faster-whisper 等)。
展开完整文档(README 剩余 1 节)
dsh-douyin-life(刷抖音)
封面
DSH 插件。每天替使用者刷抖音:刷推荐流 → 看片(转写)→ 读评论 → 挑片写日报,顺手做点赞、评论(可 @ 你)、转发视频给你(附一句话 + 一个对味表情包)、续火花、回私信(含陌生人);需要发片时,也可以把本地渲染好的成片发到抖音(本地可选配置,不绑定任何渲染工具)。
登录:设置页点「浏览器登录」→ 直接弹出带界面的 Chrome 打开抖音登录页,在里面扫码或收短信验证码,登录成功后自动切回后台无头运行(也可以继续用「截图登录」拿二维码)。
装法:从插件市场 / npm 装,或把源码目录 link 进 profile。设置页有「刷抖音」一页(日常 / 刷视频 / 互动 / 私信 / 表情包 / 高级 六个 tab),左侧还有「记忆」页(插件自带记忆 + 人设,不依赖任何记忆插件)。
接口契约见 SPEC.md。发布说明见 PUBLISH.md。
装完先让 agent 做的 5 步(写给模型看的)
这段是给 agent 的执行清单:不跑完这几步,插件「装了但用不了」。按顺序做,别跳。
1. 装 Python 依赖(MCP) —— 插件自带 Python MCP,依赖在 vendor/douyin-mcp/requirements.txt(mcp<2、playwright、faster-whisper 等)。
设置页「高级」有一键装(建 venv → 装依赖 → 自检);命令行等价:
python -m venv <家>/.venv
<家>/.venv/Scripts/python -m pip install -r vendor/douyin-mcp/requirements.txt
然后把设置里的 pythonPath 指到 <家>/.venv/Scripts/python.exe。
2. 确认 Chrome —— 用本机已装的 Chrome(插件用 channel=chrome 拉起持久 profile,不额外下载浏览器);没有 Chrome 先装。
3. 登录 —— 让主人点设置页「浏览器登录」(会弹带界面 Chrome,扫码 / 短信验证码都在窗口里完成,成功后自动切回无头);也可以用 dy_login_start 出二维码。
4. 配模型 / 出片目录 —— DSH 里把模型配成能用的(默认 deepseek-account / deepseek-flash);headlessModel 留空=跟随默认模型。要发本地成片才填成片目录(默认空,不填只影响发片)。
5. 自检 + 闸门 —— 跑 dy_selfcheck,ok:true 再用;autoLike / autoComment / autoPublish / autoReply 默认全关,主人明确要才打开。
第一次用:把这份交给你的 agent
装好后别自己在设置页瞎点。把下面这句发给你的 AI:
读一下 dsh-douyin-life 的 docs/AGENT_ONBOARDING.md(在你本机 DSH 的插件目录 node_modules/dsh-douyin-life/docs/ 里),按它把登录、记忆/人设、私信和表情包配好。
那份文档是写给 agent 看的:Chrome 怎么检测/安装/自动打开、扫码和短信验证码怎么登、默认记忆/人设怎么用(不用装记忆插件)、收藏表情包怎么巡检、没有收藏时怎么用关键字兜底、哪些写动作默认关着不许碰、出问题怎么排查。
0.2.1 修复版(2026-10-27)
这次是本地源码修复,未发布 npm、未代替你重启宿主。完整结果见 修复报告,历史问题见 审查记录。
- 所有写动作经过宿主的授权、额度、串行锁及持久化动作记录;未确认回执返回 unknown,保留额度且不自动重发。
- headless 的 Python 工具通过带临时凭证的回环代理调用宿主,复用浏览器与账本。当前桌面 CLI 可自动发现,不再依赖旧安装路径,也不强制放开沙箱。
- 选择数量来自结构化 picks;日报关闭或被编辑不再改变额度。state.count 表示轮数,pickedToday 表示挑片数。
- 新安装默认关闭普通评论和私信回复;已有显式设置保留。私信需要稳定的对方、会话、新入站消息标识。
- 本机模式使用转写摘录模板;自由人设只用于模型模式。本机自动投稿与 @豆包暂未接线,界面明确标注;草稿转正式发布由使用者在创作者中心完成。
- 本轮没有向真实抖音账号发送测试内容。DOM 选择器、消息 ID、平台回执仍需重载后的真机验收。
开发回归:源码目录运行 npm test。回环代理测试用 npm run test:proxy、npm run test:headless;真实 MCP、模型、CLI 验证命令见修复报告。测试不依赖真实账号。
界面
设置页在 DSH → 设置 → 刷抖音,六个 tab:日常 / 刷视频 / 互动 / 私信 / 表情包 / 高级。
记忆和人设是插件自带的,不依赖任何记忆插件:默认记忆写在 <家>/memory/YYYY-MM.md,人设是 <家>/persona.md(+ personaPrompt),下一轮开头会带上最近记忆。
需要的话可以接入你自己的记忆系统(见 docs/AGENT_ONBOARDING.md 的「记忆与人设」一节);不接也完全不影响使用。
日常
日常
刷视频
刷视频
互动
互动上
互动下
私信
私信
表情包
表情包
高级
高级上
高级下
1. 装
npm 上还没有这个包,dsh plugin add dsh-douyin-life 会 404。
用插件目录的绝对路径装,装完重启一次 dsh。
dsh plugin --profile desktop add link:<插件目录的绝对路径>
首次启用后:先 dy_chrome_open 拉起一个带调试端口的 Chrome(默认 http://127.0.0.1:9222),首次在里面扫码 / 验证码登录;连不上就退回插件自己的 profile,用 dy_login_start 出二维码 PNG 扫码。完整步骤见 docs/AGENT_ONBOARDING.md。
登录态只落在本机,不上传任何地方。
「高级」页可以一键把运行环境装好:装主依赖(建 venv) → 装 mcp<2 + playwright(用系统 Chrome,不下载浏览器)→ 环境自检。
2. 家目录
%USERPROFILE%\.dsh\douyin-duty\(或 $DSH_HOME/douyin-duty/)
| 文件 / 目录 | 说明 |
| config.json | 插件自己那份配置(面板/工具写) |
| state.json | {day,count,picked,loggedIn,windows,winTries,commentFails,...} |
| duty.log | 一行一件事(每次工具调用、每轮结果都有一行) |
| out/YYYY-MM-DD.md | 每轮日报(按 ### <视频id> 记) |
| ledger.json | 账本:回过的评论 cid、发过的评论、转发过的视频、私信次数 |
| memory/YYYY-MM.md | 默认记忆(视频观察、私信对话、续火花…) |
| dm-log/YYYY-MM-DD.json | 私信聊天记录(谁、说了什么、回没回) |
| .need-captcha | 验证码标记:有它时浏览器切「带界面」 |
| replied-cids.txt / replied-users.txt | 去重索引(评论 cid / 已回过的用户) |
| thumbs/ | 缩略图(卡片用,30 天自动清) |
| media/ | 看片时抽的音轨 + 转写缓存 .json(音轨每天清,json 留着省得重下) |
| duty.md | 值班章程(用户改过就保留,新版落 duty.md.new) |
| persona.md | 人设(personaPrompt 也在这里) |
| mcp_server.py | Python MCP(从 vendor/ 铺过来) |
| browser/ | Playwright 持久化 profile(登录态在这里) |
| .venv/ | Python 依赖环境(pythonPath 指过来) |
| headless-overlay.yml | 跑一轮时临时叠给 headless 的补丁 |
⚠️ 凭证 / 登录态 / 报告一律落在家里,绝不写进插件包(装进 node_modules 后只读、升级会覆盖)。
3. 工具(35 个 dy_)
读 / 看
| 工具 | 干什么 |
| dy_status | 今天跑没跑、挑了几条、额度、窗口、登录态、CDP、报告路径 |
| dy_config | 读 / 改配置(不给 patch 就是读) |
| dy_whoami | 抖音登录的是谁 |
| dy_feed | 刷推荐流(打开精选→点推荐→拦 /module/feed/),不搜索 |
| dy_hot / dy_hot_videos | 热榜 / 某热点下的视频(不用登录) |
| dy_search | 关键词搜视频 |
| dy_video | 单条视频信息(标题/作者/时长/点赞) |
| dy_comments | 评论(接口优先,图文作品直接 DOM 抠;不编数据) |
| dy_my_posts / dy_my_videos | 我自己发的作品(按天过滤)/ 投稿账本 |
| dy_thumb | 给视频截缩略图 |
| dy_remember | 往 <家>/memory/YYYY-MM.md 记一行 |
动手(都有闸门)
| 工具 | 干什么 | 闸门 |
| dy_like | 点赞 / 取消 | autoLike 或 force: true |
| dy_comment | 发评论 / 回复(可 mention 真人 @;图文作品用 reply_index 按序号回) | autoComment+mentionName / autoCommentPlain,或 force: true |
| dy_share | 转发视频给某人(悬停出分享面板→点那行的「分享」),随后同一会话发「一句话 + 一个表情包」 | 名字在「可以主动发消息的人」里,或 force: true |
| dy_chat_send | 私信发一句(续火花用) | 同上 |
| dy_chat_sticker | 私信发表情包(关键词联想,可 flip 换一批) | 同上 |
| dy_dm_inbox | 只读私信收件箱(谁发的、内容预览) | — |
| dy_dm_poll | 手动跑一次后台秒回巡检(有新的就回一句) | dmAutoReply |
| dy_dm_round | 旧的「看一遍私信回一句」:模板短句 + 每日额度 | dmReply |
| dy_reply_round | 回我自己视频下的新评论 | autoReply |
| dy_reply | 回复某一条指定评论 | autoReply |
| dy_publish | 投稿(video_path 或 latest: true);自动勾「内容由 AI 生成」,默认存草稿 | autoPublish 或 force: true |
维护
| 工具 | 干什么 |
| dy_run | 立刻跑一轮(默认本机直跑,不 spawn headless;mode: "headless" 才起子会话) |
| dy_selfcheck | 真跑一次环境自检(家目录 / Python / MCP + 一次登录检查) |
| dy_cleanup | 立刻清一次:临时垃圾、老缩略图、老日报、日志轮转、媒体音轨、浏览器 Cache |
| dy_chrome_open | 拉起「本人已登录的 Chrome」并开 CDP 端口(之后所有动作都走它) |
| dy_login_start / dy_login_poll | 扫码登录 |
| dy_login_sms / dy_login_sms_submit | 短信验证码登录 |
4. 一轮到底做了什么
谷时窗口(或手动「现在跑一轮」) └─ dy_feed 刷一屏推荐(不搜索) └─ 按时长筛:> 划走阈值 直接跳过;> 跳着看阈值 标记 skim └─ 打分排序 → 一轮只挑「一次挑几条」 └─ 动作轮转(保证一轮里既有转发也有评论,一条视频只做一件事):
· 评论 @ 你 (每天限额 commentPerDay)
· 普通评论(不@) (每天限额 plainCommentPerDay)
· 转发给某人 (每天限额 sharePerDay → 分享 + 一句话 + 一个表情包,同一会话)
· 只点赞 └─ 要「动手」的那几条先真看片:dy_watch 抽音轨 → faster-whisper 转写 └─ 写日报 out/YYYY-MM-DD.md(### <视频id> + 标题/作者/数据/为什么) └─ 动作结果(成功/失败原因)也写进日报,不假装成功
同一巡检定时器(每隔多少分钟看一次评论和私信,默认 30 分钟、±20% 抖动)到点会:
1. 续火花(每天 1 次)
2. 看私信 → 谁发来新消息就回一句(每人 1 条/天、合计 5 条/天)
3. 看评论 → 回我自己视频下的新评论(回评论看几天内的作品,默认 3 天)
5. 看片(转写)
- 页面 currentSrc 或详情接口提供可信 HTTPS 媒体地址;未知时长/长视频不整条下载,短片下载有 64MB 上限。
- ffmpeg 输出 16kHz 单声道 PCM16。短片截取、长片分段共享 watchSeconds 总预算,返回 actual sampledRanges 和 partial。
- 音轨在独立临时目录内生成、合并、转写,任务结束清理。Whisper worker 最多运行 180 秒,超时和取消都会终止进程。
- 缓存路径为 media/<id>.<秒数>.v2.json,读取时校验 schema 与模型。DOUYIN_WHISPER_MODEL 可选择 tiny/base/small;HF_ENDPOINT 可覆盖镜像,模型缓存放在家目录 models。
- 默认 watchBeforeAct 开启时,转写失败就跳过依赖内容的评论/转发,不会假装看完。partial=true 的文案明确写采样。
- 真实 ffmpeg 与缓存 base 模型的本地静音测试已通过;真实抖音取流、页面选择器和发布回执仍需重载后验收。
6. 设置字段(六个 tab)
日常
| 字段 | 默认 | 说明 |
| perDay | 5 | 每天最多挑几条(0 = 不自动刷) |
| peakValley / noon / night | true | 谷时自动刷总开关 / 中午 12–14 / 夜间 00:30–08:30 |
| pickPerRound | 2 | 一次挑几条(别一口气刷完) |
| skipOverMin | 60 | 超过多少分钟就划走 |
| skimOverMin | 5 | 超过多少分钟就跳着看(评论/附言会写明) |
偏好
| 字段 | 默认 | 说明 |
| keywords | [] | 关注关键词(空 = 用章程默认) |
| reportLevel | full | full / brief / off |
| personaPrompt | '' | 模型模式人设;本机模式使用转写摘录模板 |
| memory | true | 是否写记忆 |
互动
| 字段 | 默认 | 说明 |
| autoReply | false | 自动回我自己视频下的评论 |
| replyPerRun / replyPerDay | 3 / 10 | 每次回几条 / 每天最多 |
| replyRandom | true | 随机挑(关 = 按顺序) |
| replyOncePerUser | false | 同一个人只回一次 |
| replyIntervalMin | 30 | 每隔多少分钟看一次评论和私信(±20% 抖动) |
| replyVideoIds | '' | 要回的自己的视频 id(一次性/长期看 replyOneShot) |
| replyWorksDays | 3 | 回评论看几天内的作品 |
| skipLive | true | 遇到直播就跳过 |
| autoLike | false | 自动点赞 |
| autoComment + mentionName | false / '' | 评论并 @ 你 |
| commentPerDay | 10 | 每天最多几条 @ 评论 |
| autoCommentPlain / plainCommentPerDay | false / 10 | 自动评论(不 @ 人)/ 每天最多几条 |
| shareToNick / sharePerDay | '' / 10 | 转发给谁 / 每天最多转发几条(与评论互斥) |
| shareNote | '' | 转发时附带的一句话(空 = 按看片内容/类型自动生成) |
| msgAllowTo | '' | 可以主动发消息的人(昵称逗号分隔;空 = 谁都不主动发) |
| dmReplyOnlyTo | '' | 只回谁的私信(昵称,逗号分隔,可多人;空 = 谁发来都回) |
| dmReply | false | 自动回陌生人私信(模板短句) |
| dmAutoReply / dmAutoIntervalSec | true / 15 | 后台秒回白名单私信 / 多少秒看一次 |
| dmReplyPerContact / dmReplyPerDay | 1 / 5 | 每个联系人每天回几条 / 每天合计 |
| streakNick / streakPerDay | '' / 1 | 续火花发给谁 / 每天几次 |
| askDoubao | false | 保留配置;当前不执行,等授权接线 |
| autoPublish / publishPerDay | false / 1 | 允许手动工具与 headless 投稿 / 每天最多提交几次;本机轮次不自动投稿 |
| publishTitle / publishTags | '' | 标题模板({date} 会替换)/ 默认话题 |
| publishDraft | true | 投稿默认存草稿 |
高级
| 字段 | 默认 | 说明 |
| localRound | true | 「跑一轮」用本机直跑(不 spawn headless) |
| watchBeforeAct / watchSeconds | true / 90 | 动手前先真看片 / 总取样秒数预算 |
| autoClean | true | 每天自动清理一次 |
| pythonPath | python | 显式解释器 / uv → 家目录 .venv → PATH python |
| cdpUrl / cdpPort / chromePath | 9222 / 9222 / '' | 复用「本人已登录的 Chrome」 |
| headlessProfile / headlessModel / overlayMcp / workspace | headless / '' / true / '' | 起子会话时的参数 |
| dshBin | '' | dsh 的 bin.js(空 = 自动探测,含 app.asar 路径) |
每个字段都带 .extra('volatile', true)(否则 settings.update() 报 has no volatile fields)。
新增字段必须同时改四处:Config(schema)、DEFAULTS、clampPatch、client.js 的 load/save,少一处就是「填了没用」——selfcheck.mjs 有断言盯着这件事。
7. HTTP(设置页用)
| 方法 | 路径 | 说明 |
| GET | /api/douyin-duty/status | 状态(config / windows / nextWindow / gates / cdp / doing) |
| GET / POST | /api/douyin-duty/config | 读 / 写配置 |
| POST | /api/douyin-duty/run | 立刻跑一轮(默认本机直跑;返回 picked / actions / error) |
| GET | /api/douyin-duty/thumb?id= | 缩略图(没有就现截) |
| GET | /api/douyin-duty/watched | 刷过的视频(按日期分组,卡片用) |
| GET | /api/douyin-duty/report/latest | 最近一份日报 |
| POST | /api/douyin-duty/login/qr · /login/poll | 扫码登录 |
8. 环境问题怎么降级
| 情况 | 表现 |
| headless 子进程写系统 Temp 被拒(EPERM mkdtemp) | 插件把 TEMP/TMP/TMPDIR 指到 <家>/.tmp;MCP 子进程也带同样变量 |
| 沙箱不让子进程开命名管道(Playwright WinError 5) | headless 经回环代理调用宿主浏览器;回环连接也被限制时明确失败,改用本机模式或配置宿主允许的连接 |
| Chrome 没带调试端口 | dy_status.cdp.ok=false + 提示;dy_chrome_open 拉起来 |
| MCP 起不来 / Python 缺 | 工具返回 {ok:false, error, hint},不抛异常 |
| 抖音没登录 | {ok:false, needLogin:true, hint} |
| 评论发不出去 | 回读确认不到就报失败;连续失败 2 次当轮停止评论(点赞/转发照做) |
加载路径每一步都包 try/catch:插件加载失败比少个功能糟得多。
9. 自检
node selfcheck.mjs # 55 条断言:宿主能加载 / 工具齐(35 个)/ 路由通 / 结构对 / 闸门默认关
10. 最近更新(增量说明 · 2026-10-25 ~ 10-26)
只做补充说明,前面章节的结构和内容没动。
节奏:谷时那一轮并入巡检定时器(只有一个间隔参数)
改成共用 replyIntervalMin(默认 30 分钟,±20% 抖动 → 实际 24~36 分钟)。到点依次做:
谷时窗口内 → 刷一轮(一次挑几条)→ 续火花(每天 1 次)→ 看私信 → 看评论
不再有单独的「每 60 秒查一次表」谷时定时器;不在窗口/额度满时 windowTick() 自己跳过,不会多刷。
设置页那一行也改名为 「每隔多少分钟巡检一次」。
私信:只回指定的人 + 按人设说话
- 新增 dmReplyOnlyTo(设置里叫 「只回谁的私信(可填多个)」):昵称逗号分隔,可填一个或多个;留空 = 谁发来都回。
- 回复不再是那四句硬编码(收到啦[憨笑] 之类),改成人设短句库:问候 / 被夸 / 被凶 / 提问 / 表情 / 晚安 / 兜底 七类,每类 3~4 句随机,单句 ≤20 字、带表情、不写客服话。
- 限额不变:每个联系人每天 1 条、合计每天 10 条(dmReplyPerContact / dmReplyPerDay)。
图文作品:只读不回
图文(note)作品的评论接口不抛数据,靠 DOM 抠;页面上「回复」不是可点元素,所以评论只读、不回复,并在结果里写明理由、不占额度。视频作品正常回复。
稳定性(都是实测踩出来的)
- _goto 容忍抖音常见的 ERR_ABORTED / 连接被重置:重试 2 次,最后用 commit 兜底;
- 共用 Chrome 时会泄漏标签页(实测堆到 39 个)→ 每次动作前 _sweep_tabs 收掉多余标签;
- 私信发送改成最小实现(原内联 JS 里有 const 重复声明,会抛 Assignment to constant variable.);
- 定时器里 maybeClean / dmRound 曾因块级作用域报 is not defined,现在统一「先声明后赋值 + typeof 防御」。
配置字段的两条老规矩(又踩了一次)
新增字段必须同时改四处:Config(schema) / DEFAULTS / clampPatch / client.js 的 load&save。
少写 schema 会这样:设置页保存时弹「已存到插件自己那份(宿主设置层没写成)」,日志里是 Config field "xxx" is not volatile —— 本地照常生效,但设置页刷新会回到旧值。
补充:0.2.1 修复验证(2026-10-27 重启后)
只补充本次修复,不改前面已有说明。
- 重启后自检通过:mode=profile、已登录、搜索正常、ffmpeg + whisper 模型就绪、video-understanding-lab 在位。
- 新装默认走自有 profile(cdpUrl 空);显式 CDP 连不上自动退回;想复用日常 Chrome 才 dy_chrome_open。
- 看片:lab 随包发布;watchSeconds 真正截断(partial=true);缺 lab 时明确报错并跳过依赖看片的互动。
- 私信:只有平台确认的发送才记「已回复」;没回执标 unknown、最多重试一次;秒回按 dmReplyOnlyTo 在 msgAllowTo 内再筛。
- 记忆页:没装可选记忆插件时显示本地「原始记录 + 人设」,不再 404。
- 配置保存失败以本地为准;perDay=0 只停自动刷,手动可跑;多实例端口按家目录派生(DOUYIN_PROFILE_PORT);requirements 补 pillow。
- 验收边界:只读/离线已验;点赞/评论/私信/发布未做真实账号验收,别对外说「全部通过」。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
kdcadmin/dsh_douyin_tools
deepseek自动刷抖音的dsh插件,能读评论,@你的账号,点赞视频和发布视频
相关插件 · 工具 / 效率
破甲管控台kingcharleslzy-ai/dsh-purge
dsh-purge Community · DeepSeek Harness 社区维护版:宿主兼容、状态诊断、提示词管理、更新与本机备份回滚。基于小杨 / YuJunZhiXue 的 dsh-purge。
★ 4,173已汉化DeepSeek 客户端
74.4
网文长卷lingfengQAQ/webnovel-writer
基于 Claude Code 的长篇网文辅助创作系统,解决 AI 写作中的「遗忘」和「幻觉」问题,支持 200…
★ 7,636已汉化DSH
72.2
多智能体协作HKUDS/AutoSwarm
AutoSwarm: Unify Your Agents. Unify Your Context (Codex · Claude Code · DeepSeek Harness · Muse · Grok · WorkBuddy· nanobot · and more)
★ 2,349已汉化DSH
71.6
Vox 拼贴视频生成Alisa0808/vox-director
🎬 Vox Director拼贴动效导演
★ 2,129已汉化DSH
71.4
Agent 演化引擎Q00/ouroboros
智能体 OS:智能体自己变聪明,我们只守住底线:面试准入、分阶段评估、带预算的进化循环。MCP 服务器,14 种运行时:Claude Code、Codex CLI、Gemini CLI、OpenCode、Copilot、Kiro 等。
★ 6,308已汉化DSH
71.3
智能体运行框架路由HarnessRouter/harnessrouter
智能体运行框架的统一接口。
★ 3,897已汉化DSH
71.2
这是你的仓库?认领条目