用 Electron 写了个自媒体矩阵发布工具,还把它接进了 AI 智能体
6 个主流平台一键发布 + CLI + AI 智能体可编排,顺手聊聊里面的技术选型和踩过的坑。
一、缘起:为什么要造这个轮子
做自媒体的朋友多少都经历过这些:同一条视频,抖音要发、快手要发、视频号要发、B 站要发、百家号/头条也不能落下——一条视频手动上传 6 次,填 6 次标题、选 6 次分类、改 6 次封面。
市面上付费矩阵工具不少,但要么贵、要么有条数限制、要么要把 Cookie 交给别人的云端。于是我开了个头:矩媒 MatrixMedia —— 一个完全跑在本地的开源自媒体发布工具,支持 GUI,也支持 CLI,能被任意 AI 智能体(Claude Code / Cursor / Dify / n8n ...)调度。
仓库地址(开源免费,GPL-2.0):
- GitHub:github.com/hanliang97/…
- Gitee:gitee.com/gzlingyi_0/…
- 📺 教程视频:www.bilibili.com/video/BV1fi…
二、技术栈一览
| 层次 | 选型 | 为什么 |
|---|---|---|
| 桌面容器 | Electron 24 | 需要访问本地文件 + 多 session 管理 cookie,浏览器扩展做不到 |
| 前端 | Vue 2.7 + Element UI + Pinia | 上手快、生态全,桌面端对渲染性能没太高要求 |
| 打包 | webpack 5 + electron-builder | 需要同时出 Windows NSIS / macOS DMG |
| 自动化 | puppeteer-core + puppeteer-in-electron + stealth 插件 | 复用 Electron 自带 Chromium,不用额外拉一套浏览器 |
| CLI | argv 嗅探 + minimist | 无入侵:同一个可执行文件,argv 含 cli 就进 CLI 模式 |
| 登录态 | Electron session.fromPartition('persist:<phone><平台>') | GUI 与 CLI 共用同一 partition,登录一次处处生效 |
| 数据 | 本地 JSON(pushData / accounts) | 桌面工具无需后端,零运维 |
没用 Vue 3 / TypeScript,是因为项目早期就是个 Vue 2 模板,迁移成本换不回明显收益——工具型项目,稳定能跑比用最新语法更重要。
三、核心问题与解法
3.1 六个平台六套脾气:怎么抹平差异?
每个平台的发布页都是独立的 SPA,DOM 结构、上传接口、风控策略全都不一样。最终采用「平台适配器」的写法:每个平台一个模块,实现统一的 login / publish / checkLogin 接口,主流程只跟接口打交道。
踩到的坑里最有意思的几个:
- 视频号:首次发布会弹「原创声明协议」浮层,不点掉后面所有按钮都是灰的——必须在发布流程里主动
querySelector+click。 - 快手:发布按钮绑了一大堆 React 合成事件,用
.click()能点、用dispatchEvent反而不行,最后老老实实走真实 DOM click。 - 小红书:风控最凶,目前只打通了登录态检测,发布还没稳定下来,README 里标了「未测试」。
- 哔哩哔哩:封面必须手动点一下才会触发上传接口,这个暂时只能让用户接管。
3.2 GUI 和 CLI 怎么共享登录态?
Electron 的 session.fromPartition('persist:xxx') 会把 cookie 持久化到用户目录,只要 partition 名字一致,GUI 和 CLI 就能读到同一份 cookie。我用的约定是:
persist:<手机号><平台代号> // 例如 persist:138xxxxxxxxdy
带来的好处:
- CLI 登录只实现了抖音一家(其它平台登录页太复杂),但别的平台在 GUI 登录一次后,
cli publish就能直接用。 - 切账号只是切 partition,不用清数据。
3.3 CLI 入口:一个可执行文件两套形态
Electron 应用默认打开会起主窗口,但作为 CLI 又不能弹窗。做法很简单——在 main.js 最早期嗅探 argv:
// 伪代码
if (process.argv.some(a => a === 'cli')) {
require('./cli').run(process.argv)
return // 不再 createWindow
}
app.whenReady().then(createWindow)
对外契约只有 4 条:
| 约定 | 内容 |
|---|---|
| 入口标记 | argv 含 cli |
| 子命令 | login / publish / accounts / history |
| 退出码 | 0 成功 / 1 异常 / 2 参数错误 / 3 业务失败 |
| 机器可读 | --json 产出稳定 JSON |
看起来土,但任何能调 shell 的平台都能接——这就是下一节的关键。
四、和最新 AI 的结合:把工具变成智能体的"手"
过去一年 AI 工具的范式变化非常明显:从「在 Chat 里跟模型对话」演进到「模型调度一堆外部工具干活」。Claude Code、Cursor Agent、Dify、n8n、LangChain、CrewAI、AutoGen...它们都需要能被调度的外部命令。
矩媒的 CLI 是专门为这类智能体设计的。几个小但关键的点:
4.1 退出码语义化
不是简单的 0/1,而是 0 / 1 / 2 / 3 分别对应成功 / 异常 / 参数错误 / 业务失败。智能体拿到 3 就知道"参数没错、是登录或发布本身挂了",可以触发重新登录流程,而不是盲目重试。
4.2 --json 稳定输出
cli accounts --json 和 cli history --json 产出的是 schema 稳定的 JSON。智能体不需要解析花哨的表格输出,直接喂给模型即可。
4.3 仓库级可发现标记
README 顶部有一行注释:
<!-- openclaw-integrable: id=matrixmedia-cli version=1 platform=electron argv-marker=cli -->
这是给 OpenClaw / Hermes 这类智能体市场看的——任何扫仓库的编排框架都能一眼认出"这是个可接入的 CLI 工具",不用人去写适配层。
4.4 Claude Code 实际参与了开发
这个项目一部分代码(尤其是 cli accounts / cli history 和 README 的 CLI 章节)就是在 Claude Code 里协作写出来的:
- 人类负责需求拍板、评审、合入;
- Claude 负责铺代码、整理文档、生成测试脚本;
- 项目里
.cursor/skills/还有一份给 Cursor / Claude Code 用的 skill 文档,告诉模型"发布视频时应该怎么调 CLI"。
这是一种新的协作方式:你写的工具不仅给人用,还给模型用。 当你把 CLI 契约设计清楚,模型的"手"就多了一只。
4.5 一个真实的自动化例子
在 Dify / n8n 里配一个工作流:
- 触发器:每天 10 点,或 webhook 收到文件路径;
- 预检:
matrixmedia cli accounts --json,过滤出登录态正常的账号; - 发布:对每个账号执行
matrixmedia cli publish -p <平台> -f <视频> -t <标题>; - 回写:
matrixmedia cli history --json -d 1拉最近一天结果,写回飞书/Notion。
整个过程不需要写任何平台专属代码,全是 shell + JSON。
五、几条踩坑后沉淀出的经验
- 桌面工具不要追新。Vue 2 + Element UI 的组合已经够用了,把精力花在"让每个平台稳定发出去"更值钱。
- session partition 命名要想清楚。一旦上线再改,老用户会全体掉登录态。
- 给 AI 设计 CLI 时,把退出码当一等公民。模型没有直觉,只能靠结构化信号判断下一步。
- README 的顶部要留给最重要的东西——教程视频、快速开始链接、AI 可发现标记。
- 别自己藏 Cookie 到云端。桌面工具的卖点之一就是"数据全在本地",一上云就失去了差异化。
六、结语
矩媒不是什么黑科技,本质上就是把一堆平台的发布流程做成适配器 + 提供一层干净的 CLI。但它让我重新体会到一件事:在 AI 智能体时代,一个命令行工具的设计好坏,决定了它能不能被"模型的手"拿起来用。
退出码、JSON 输出、session partition、仓库级标记——这些以前是"可选的工程素养",现在是"AI 工具必备的接口协议"。
项目完全开源免费(GPL-2.0),欢迎来 Issue / PR,也欢迎把它接到你自己的 AI 工作流里。
- GitHub:github.com/hanliang97/…
- 📺 教程视频:www.bilibili.com/video/BV1fi…
如果对你有帮助,点个 star 是对开源最大的鼓励 ⭐