在 Obsidian 与语雀之间做双向、近实时的笔记同步。文件夹 ↔ 知识库一一映射,映射内的笔记两边自动同步。
Desktop-only Obsidian plugin. 桌面端专用。
语雀对个人用户不提供 webhook,所以两个方向天生不对称:
- 本地 → 语雀:保存后防抖推送(默认 2.5s),几乎即时。
- 语雀 → 本地:只能轮询(默认 5 分钟),因为没有任何东西能主动推给本地插件。
- 文件夹映射驱动:只有落在你配置的映射文件夹(
本地文件夹 ↔ group/book)里的笔记才会同步。映射之外的笔记一律跳过 —— 避免整个 vault 被误传。 - 四象限冲突处理,不是无脑后写覆盖:仅本地改 → 推;仅远端改 → 拉;两边都改 → 按时间戳后写胜(LWW),并把失败方另存为
<名字>.conflict-<loser>.md(宁可多留文件也绝不丢数据);都没改 → 跳过。 - 防循环:写本地文件前先登记路径到抑制集,消费一次
modify事件;推送后把语雀返回的content_updated_at写回状态表,下次轮询不会把自己刚推的再拉回;每次做哈希前先归一化内容(去尾空白、统一换行、剥 frontmatter),吸收 markdown↔lake 往返漂移,杜绝「假冲突」乒乓。 - 备份镜像(可选):把同步内容额外导出成一份纯 markdown 到磁盘任意目录,作兜底。
未上架社区插件市场,先手动安装:
npm install
npm run build # 类型检查 + 打包出 main.js把 main.js、manifest.json、styles.css 复制到 <vault>/.obsidian/plugins/yuque-bridge/,在 Obsidian 里启用即可。
npm run dev 为 esbuild watch 模式;npm test 跑 vitest 单测。
在设置页填:
| 项 | 说明 |
|---|---|
| X-Auth-Token | 语雀个人 token(超级会员),设置 → Token 处生成 |
| 文件夹映射 | 本地文件夹 ↔ group/book,可多条;映射内笔记双向同步 |
| 轮询间隔 / 推送防抖 | 默认 5 分钟 / 2.5 秒 |
| 图片上传(可选) | off / 语雀图床 / PicGo-Server / 自定义 HTTP 图床 |
| 登录 Cookie(可选) | 语雀图床与下载附件需要;设置页有「登录语雀自动获取」按钮,约 30 天过期 |
| 命令 | 作用 |
|---|---|
| 同步当前笔记 | 立刻推/拉当前文件 |
| 立即全量同步 | 对账所有映射文件夹 |
| 为当前笔记设置知识库 | 交互式选一个 group/book 写入 |
| 本地整理 | 清重复、按语雀目录树重排本地文件 |
| 清理已删除文档 | 把语雀端已删的文档移入回收站(可恢复) |
| 导出镜像 | 手动导出一份纯 markdown 备份 |
- 图片走语雀图床/附件下载依赖网页登录 Cookie(语雀无官方 v2 上传接口),语雀改版可能失效;失败时自动降级为保留本地链接,不阻塞正文同步。
- 「登录获取 Cookie」按钮依赖 Electron
BrowserWindow,部分 Obsidian 版本可能不可用,可退回手动粘贴。 - 删除同步偏保守(移回收站而非硬删),优先不丢数据。
Bidirectional, near-real-time note sync between Obsidian and Yuque. Map a vault folder to a Yuque knowledge base; notes inside sync both ways.
Why near-real-time: Yuque gives individuals no webhook, so the directions are asymmetric — local→Yuque pushes on save (debounced ~2.5s), Yuque→local is poll-only (default 5 min).
Design highlights:
- Folder-mapping opt-in — only notes inside a configured
folder ↔ group/bookmapping sync; everything else is skipped, so the whole vault is never uploaded by accident. - Four-quadrant conflict handling — local-only→push, remote-only→pull, both-changed→last-write-wins by timestamp and save the loser as
<name>.conflict-<loser>.md(never discard a conflicting copy), neither→skip. - Anti-loop — suppression set consumes the self-triggered
modifyevent; the pushedcontent_updated_atis written back so polling won't re-pull your own push; content is normalized before hashing to absorb markdown↔lake round-trip drift.
Install: npm install && npm run build, then copy main.js, manifest.json, styles.css into <vault>/.obsidian/plugins/yuque-bridge/. Desktop-only.
Configure: Yuque personal X-Auth-Token, one or more folder ↔ group/book mappings, optional image host and web-login cookie (the settings page can fetch the cookie via a login window; expires ~30 days).
MIT