wechat-channels-video
Skill34 starsChanged 11 days agoMITView on GitHub
Publish a WeChat Channels video draft with Ego Lite via ego-browser — login-check first (sessions expire fast), upload video, fill description/short title/topics/location/cover, save draft only. Soft-fails if Channels is logged out and tells the human to scan QR inside Ego. Personal use. Use when the user asks to post to 视频号 / Channels assistant.
In this repository10 other files it gives its agents.
- douyin-videoSkill
- instagram-saved-downloadSkill
- kuaishou-videoSkill
- pinterest-downloadSkill
- teambition-egoSkill
- __SKILL_ID__Skill
- wechat-article-egoSkill
- xiaohongshu-egoSkill
- x-postSkill
- youtube-videoSkill
The file
Files
wechat-channels-video
用 Ego Lite 会话在 视频号助手 保存视频草稿。不点「发表」(扫码发表留给人)。
Save a WeChat Channels draft through Ego Lite. Never click Publish — QR publish is human-only.
先装 Ego
先装 Ego Lite,保证 ego-browser 在 PATH。缺失则 soft-fail / 告知用户去装,不要硬调浏览器。
每次发布前:登录闸门(必做)
视频号登录态过期很快。Agent 在上传或填表之前必须跑:
node scripts/check-login.mjs
# 需要把窗口留给人扫码时:
node scripts/check-login.mjs --keep| 退出码 | 含义 | Agent 做什么 |
0 | 已登录 | 把 login_tip 告诉用户,继续流程 |
2 | 未登录 / 无 ego-browser | 展示 how_to_login / how_to_login_zh,停。请人在 Ego 扫码后再跑 check-login |
1 | 其它错误 | 报告 JSON error,不要假装已发布 |
详见 references/login.md。不要另做 cookie-healthcheck 技能。
输入(通用,无本机产品路径)
调用方提供视频与文案字段,见 references/inputs.md。本技能不写死任何 ~/… 业务目录。
最少需要:本机 video 路径、description、short_title。可选:tags、cover、位置/原创/活动。
CLI 薄脚本(稳定部分)
ego-browser nodejs 不转发 shell argv;check-login 已用临时 entry + ego-browser nodejs -e 包好。
# 仓库根目录
node skills/wechat-channels-video/scripts/check-login.mjs
node skills/wechat-channels-video/scripts/check-login.mjs --keep
node skills/wechat-channels-video/scripts/serve-file.mjs --file /absolute/path/to/video.mp4 --port 18765
# 已安装的技能目录里也可以用相对路径
node scripts/check-login.mjs
node scripts/serve-file.mjs --file /absolute/path/to/video.mp4 --port 18765- check-login:唯一登录硬闸门;结束默认
finish({ keep: [] })(--keep除外)。 - serve-file:给页面
fetch用的本机 CORS 文件服务;打印{ url, bytes, port },SIGINT 结束。大视频不要 base64。
不把整段发表 UI 打成一个巨型脚本:wujie、坐标点击、封面 waitForFileChooser 需要 Agent 看 snapshot/截图。脚本负责可判定的登录与传文件;表单仍按下面 Agent 步骤。
ego-browser API 速查
每次 ego-browser nodejs 是新进程;TaskSpace / Page 跨调用持久,JS 变量不持久。
| API | 说明 |
taskSpace(name|id) | 一个用户目标一个 space;记下 spaceId 复用 |
task.page("p1") | 首屏用 goto 复用,别乱开页 |
page.snapshot() | 观察(能看穿 open shadow);点击在 wujie 内常被拦截 |
page.evaluate(fn, arg) | 只收一个 JSON 可序列化参数(长文案走这里) |
page.mouse.click(x, y) | wujie 内弹层常用 |
page.waitForFileChooser() | 封面唯一稳妥上传路径 |
task.handOff() | 交给人扫码发表 / 当面登录 |
task.finish({ keep: [] }) | 收尾关 space;需人接着看时用 handOff,不要长期占机器 |
关键:snapshot 看得见 wujie shadow;ref/text 点击会报 intercepts pointer events。wujie 内动作用 evaluate 里 .click() 或坐标 mouse.click。不要改用无障碍 snapshot 的 ref 兜底(channelsClickMethod().refClick === false)。那条兜底是别的站点的做法,视频号这里点不到。
Agent 流程(登录通过之后)
0. 路由到发表页
不要直接 goto /platform/post/create(懒加载白屏)。走 UI:
首页 → 左栏「内容管理」→「视频」→ 右侧「发表视频」
就绪:wujie 内文案出现「视频描述」「短标题」,且有隐藏 input[type=file][accept*="video"] 与「保存草稿」。
const state = await page.evaluate(() => {
const app = document.querySelector('wujie-app');
if (!app?.shadowRoot) return { wujie: false };
const t = app.shadowRoot.textContent || '';
return {
wujie: true,
hasDesc: t.includes('视频描述'),
hasShort: t.includes('短标题'),
hasUpload: !!app.shadowRoot.querySelector('input[type=file][accept*="video"]'),
hasSave: t.includes('保存草稿'),
};
});1. 上传视频
先起 serve-file(端口默认 18765),再在页面里 fetch + DataTransfer 注入隐藏 file input(视频组件未做 isTrusted 加固;封面做了):
const r = await page.evaluate(async (p) => {
const root = document.querySelector('wujie-app').shadowRoot;
const input = root.querySelector('input[type=file][accept*="video"]');
const resp = await fetch(p.url);
const dt = new DataTransfer();
dt.items.add(new File([await resp.blob()], p.name, { type: 'video/mp4' }));
input.files = dt.files;
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
return 'injected ' + dt.files[0].size;
}, { url: 'http://127.0.0.1:18765/video.mp4', name: 'video.mp4' });验证只看 DOM,并且有次数上限。把每次探测交给 scripts/lib/pure.mjs 的 uploadProbeDecision / wujieProbeDecision(ego 脚本里 await import("<本技能目录>/scripts/lib/pure.mjs"))。不要另写一套更松的判断。
- 文案出现「上传失败 / 上传出错 / 上传异常」,或
failed: true:action: "stop",立刻停。 - 进度是
100/100%,或上传完成后百分比已经消失、但可见<video>和「转发」「赞」「评论」同时在(hasPreview: true),并且stableCount >= 2:action: "proceed"。样式表里的100%和隐藏节点不算。 - 还没稳定:
action: "retry"。最多8次(CHANNELS_UPLOAD_WAIT_LIMIT)。用尽仍不满足就是stop,原因是timeout。 wujie为 null /wujie: false:wujieProbeDecision,最多8次。不要刷新。用尽就是stop/unresolved。
performance resource 抓不到上传 POST,不要拿它当成功。action 不是 proceed 时不要填表,也不要点「保存草稿」。上传中途不要填表。
1.5 检查点:上传确认后才存草稿
uploadProbeDecision 返回 proceed 之后,用 maySaveCheckpoint 再确认一次,然后才点「保存草稿」。retry 就继续等;stop(超时、失败、看不清)停在这次点击之前。不要把没确认的上传存成草稿。检查点只为了避免稍后翻车重传大文件。描述还没写,所以这一下不查描述回读。
2. 描述 + 话题
描述是 .input-editor(非 contenteditable)。execCommand;文案从 evaluate 第二参数传入:
await page.evaluate((p) => {
const ed = document.querySelector('wujie-app').shadowRoot.querySelector('.input-editor');
ed.focus();
document.execCommand('selectAll', false, null);
document.execCommand('delete', false, null);
document.execCommand('insertText', false, p.desc);
}, { desc });
await page.evaluate((p) => {
const ed = document.querySelector('wujie-app').shadowRoot.querySelector('.input-editor');
ed.focus();
document.execCommand('insertParagraph');
document.execCommand('insertText', false, p.tags);
ed.blur();
}, { tags });写完立刻回读 .input-editor 的 innerText。不要改读别的字段来凑合。读不到编辑器就当作 { ok: false }。把回读和期望交给 descriptionReadbackOk(read, { desc, tags })。
- 期望文本是描述;有话题时再接一个换行和话题。
- 比较前会把连续换行收成一个,并去掉首尾空白,避免
insertParagraph多出来的空行被当成不一致。 ok !== true(mismatch、empty-readback、unresolved、missing-expected)时 停止,不要点「保存草稿」。不要靠肉眼当成已经写上。
3. 短标题
真 <input>,必须 native setter;验证读 input.value(innerText 不含 input 值)。
服务端硬限制(实测多期,触发即红字警告,保存被拒):
- ≤16 字:超长直接拒(17 字实测被拒)。
- 符号白名单:只有书名号、引号、冒号、加号、问号、百分号、摄氏度。
- 全角逗号「,」→ 换空格(如「烂推荐看够了,自己搭一个」→「烂推荐看够了 自己搭一个」)。
- 小数点会触发「特殊字符」警告:版本号里的
6.1这类写法要改说法规避。 |、#、@都不行:自带标题里的分隔符取主句(如「标题文字|栏目#066」→「标题文字」)。
填完后检查输入框下方有没有红字警告;有就改写后再保存。
4. 位置
默认常带城市。稳妥:mouse.click 打开 → snapshot/截图 → 点「不显示位置」→ 回读字段确认。evaluate 坐标可能点到隐藏层。
5. 保存草稿(终点)
不要自己点「保存草稿」。唯一支持的保存是:
node skills/wechat-channels-video/scripts/save-draft.mjs --desc "描述" --tags "#话题" --yes
node skills/wechat-channels-video/scripts/save-draft.mjs --desc "描述" --tags "#话题" --cover /absolute/path/to/cover.jpg --yes脚本会重新读取描述、上传状态和封面预览,交给 maySaveDraft。没有 --yes 不点。描述不一致、上传没完成或失败、指定封面没换上、读不到编辑器,都在点击之前退出。脚本不点「发表」。
点保存之后的成功信号不变:「已保存」+ 底部按钮变灰。再 goto 草稿箱核对。草稿箱可见前不要离开编辑器。草稿箱核对发生在保存成功之后,不能用来补一张没通过回读的草稿。
可选:声明原创、活动搜索(native setter 写搜索词;搜不到就「不参与活动」)。
声明原创
真 checkbox(授权钥匙串行)。勾选后弹协议层:勾「我已阅读并同意…」→ 点层内「声明原创」确认按钮。两步都要坐标点击并回读 input[type=checkbox].checked 确认。
活动搜索弹层
- 打开弹层点「不参与活动」字段;弹层可能不弹(点击被吞),探测
input[placeholder*="搜索活动"]失败就重试 2–3 次。 - 搜索词用 native setter + input/change 事件(
keyboard.insertText间歇性失效);二次搜索前先清空——native setter 是覆盖,但焦点点击后残留词会被追加成「AI科普AI科普」。 - 列表渲染后截图引导点击:弹层行序和 y 坐标每期都可能变(还见过偏移一行的渲染 bug),按截图上的可见坐标点,点完回读活动字段确认选中项。点错行(相邻活动)若主题也合适可接受,不必强改。
- 视口尺寸变化会让「滚到顶部再点开」的既有坐标失效——每次都要重新探测触发器坐标。
6. 封面(可选)
唯一稳妥:waitForFileChooser() + 可信点击「上传封面」+ chooser.setFiles(<绝对路径>)。合成 input.files / OS 文件框方案已实测失败。不要改用无障碍树 ref 去点「上传封面」或「保存草稿」。
换封面之后,每次探测交给 coverPreviewDecision,最多 12 次(CHANNELS_COVER_WAIT_LIMIT):
- 按钮还在转圈,或文案仍是「上传中」:继续等;次数用尽则
stop,原因spinning。 previewChanged !== true:可见封面图(.cover-img)还没换掉页面记下的第一帧。隐藏的.cover提示图不算。用尽次数则stop/unresolved。revertedToDefault: true:预览退回默认帧,立刻stop,原因reverted。- 不转圈且
previewChanged: true:proceed。 - 这次没传封面:
requested: false,结果是skip,不挡后面的保存判断。
stop 或仍是 retry 时不要点「保存草稿」。
7. 收尾
- 停掉
serve-file(释放端口)。 - 需要人发表:草稿箱
handOff()。 - 否则
finish({ keep: [] }),不要长期占 space。
避坑清单
- wujie shadow:查询从
wujie-app.shadowRoot起。 - 直链 create 白屏:必须 UI 路径进入发表页。
- wujie 内 ref/text 点击被拦截 → evaluate 或坐标点击。不要抄无障碍 snapshot ref 兜底。
- 长文案只经 evaluate 参数传入。
- 描述用 execCommand;短标题用 native setter。
- 位置两段式坐标 + 回读验证。
- 封面只能 waitForFileChooser。预览未确认或退回默认帧时,停在保存之前。
- 上传验证只看 DOM,最多 8 次。未
proceed就不存检查点草稿。 - 描述必须回读。不一致或读不到,停在保存之前。草稿落盘前不导航离开。保存成功后仍以草稿箱为准。
- 登录页「加载失败」是红鲱鱼;handOff 让人扫码。
- 每次发布前 check-login;exit 2 必须停。
- 发表是人工终点;本技能只到草稿。
- 短标题 ≤16 字 + 符号白名单(见 §3);触发红字就改写,别硬保存。
- 原创两段式(勾选 + 协议层确认),活动弹层截图引导 + 回读(见 §5);「已保存」标签偶尔错过时机,草稿箱核对是最终事实。
测试
npm testnpm test 锁住 scripts/lib/pure.mjs 里的回读、有界等待、封面预览和「不点发表」。它不登录、不上传、不保存草稿。页面步骤仍由 Agent 按上面的闸门执行;单测没有代替实页验收。
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

