README file from
Github简体中文 | English
📝 微信公众号排版转换器 (WeChat Converter)
让技术写作回归优雅与纯粹。
一款专为 Obsidian 打造的微信公众号排版增强插件。它不仅仅是一个转换工具,更是您内容创作流中的"数字化妆师"。我们解决了 Obsidian 到微信公众号排版的"最后一公里"问题,让您专注于内容创作,无需为繁琐的格式调整而分心。
只需一键,即可将您的 Markdown 笔记转换为符合微信生态美学、阅读体验极佳的 HTML,无论是代码块、引用、列表还是本地图片,都能完美呈现。
本项目基于开源项目 ai-writing-plugins 进行深度重构与迭代开发。我们致力于打造 Obsidian 生态中体验最好的公众号排版工具。
如果这个插件帮你节省了公众号排版、复制或同步草稿箱的时间,欢迎支持项目继续维护。
💡 核心升级点 (Key Highlights)
相较于原版,我们重写了核心渲染逻辑并新增了大量实用功能,旨在实现真正的**"所见即所得"**:
-
➗ 完美支持数学公式 (Math Support) ⭐ v2.1 新增
- LaTeX 全面支持:直接书写
$E=mc^2$或$$...$$,所见即所得。 - 纯矢量 SVG 渲染:采用独家无缓存技术,将公式转为独立的 SVG 矢量图,无论放大多少倍都清晰锐利。
- 抗清洗:完美抵抗微信公众号的样式清洗,不再出现乱码或被吞掉的情况。
- LaTeX 全面支持:直接书写
-
📊 Mermaid 图表支持
- 沿用 Obsidian 原生渲染:在 Obsidian 里能正常显示的 Mermaid 图表,会在插件预览中继续显示。
- 导出自动转 PNG:复制到公众号或同步到草稿箱时,会自动将 Mermaid 图表栅格化为 PNG,避免 SVG 过长导致微信拦截。
- 保留图表原色:导出时不会套用数学公式的改色逻辑,尽量保持 Mermaid 主题与连线配色。
-
🚀 一键同步到微信草稿箱 (v2.2 增强)
- 极速并发上传:图片上传速度提升 300%,支持多线程并发处理,大图文章秒传。
- 智能重试机制:自动处理网络抖动与 Token 过期,全程零人工干预,稳如泰山。
- 实时进度反馈:新增精确的上传进度条 (e.g., "3/12"),让等待不再焦虑。
- 安全防重:严格的幂等性设计,杜绝因网络超时产生的重复草稿。
- 告别复制粘贴:直接将文章同步到微信公众号后台草稿箱,图片自动上传。
- 智能封面处理:如果你的文档头部信息(frontmatter)里写了
cover,会优先用它做封面;没写就自动用正文第一张图,也可以手动换图。 - 智能摘要辅助:如果 frontmatter 里写了
excerpt,会优先用它;没写就自动截取前 45 个字,也可以手动改。 - 同步后自动清理(可选):发送成功后,可以自动删除你在设置里指定的目录(默认关闭)。
- 目录支持变量:清理目录支持
{{note}},会自动替换成当前文档名,例如published/{{note}}_img。 - 可回收:支持优先移动到系统回收站,误删可恢复。
- 多账号管理:支持最多 5 个公众号账号配置,快速切换同步。
- 账号级发布默认值:可为每个公众号账号单独设置默认原文链接、留言开关和“仅粉丝可留言”。
- Cloudflare 代理支持:解决 IP 白名单频繁变化问题,查看部署指南。
-
🎛 全新可视化设置面板 (Settings Panel)
- 告别繁琐的代码修改!我们内置了直观的设置面板,让您可以实时调整字体、字号、主题色等参数,一切尽在掌握。
-
🎨 三大专家级主题 (Premade Themes)
- 内置 简约 (Simple)、经典 (Classic)、优雅 (Elegant) 三款精心设计的主题,覆盖从技术博客到人文随笔的各种场景。
- 引用块支持更克制的中性灰样式,减少大面积主题色对正文阅读的干扰。
- Callout 支持按语义类型高亮,如
note、tip、warning、danger等;未知类型会自动回退为信息类样式。
-
🖼️ 强大的本地图片支持 (Local Image Support)
- 打破图床限制:完美支持 Obsidian 的本地图片引用(包括
![[Wiki Link]]和![]())。 - 头像上传:支持直接上传本地图片作为作者头像,插件会自动转码为 Base64。
- 强大的本地图片支持:无论是相对路径、绝对路径还是 WikiLink,都能自动识别并压缩。
- GIF 动图支持:针对 GIF 格式特别优化,自动绕过压缩流程,完美保留完整动画帧。
- 图片左右滑动查看:多张图片可以组织成横向滑动图片块,适合步骤截图、对比图、长图拆分和敏感图片提示。
- 温馨提示:建议图片(尤其是 GIF)保持在 10MB 以内,以获得最佳的处理速度和公众号兼容性。超过 10MB 时插件会弹出提醒。
- 打破图床限制:完美支持 Obsidian 的本地图片引用(包括
-
⚡️ 实时渲染预览 (Live Preview)
- 右侧预览区实现了毫秒级响应的实时渲染。您在左侧 Markdown 编辑的每一个字符,都会即时反馈在右侧的公众号预览视图中。
- 📱 双模预览 (Dual Mode Preview) ⭐ v2.2 新增
- 手机仿真模式 (默认):提供逼真的 iPhone X 边框与刘海屏效果,支持深色模式适配,还原最真实的读者视角。
- 经典全宽模式:在设置中一键切换回无边框全屏预览,利用屏幕每一寸空间。
- ↕️ 双向同步滚动 (Bidirectional Sync):无论是在左侧编辑还是右侧浏览,另一侧都会如影随形,精准对齐。
-
💻 Mac 风格代码块与样式还原
- 重新设计了代码块样式,支持 macOS 窗口风格及行号显示。
- 1:1 完美还原:我们在 Obsidian 预览区看到的样式(包括间距、颜色、边框、阴影),复制到微信后台后将分毫不差。
- 宽表格横向滑动:列数较多或内容较长的表格会自动保持可左右滑动,避免在手机端被强行压缩或截断。
🆕 v2.7.0 新增了什么
- AI 编排进入主工作流:现在可以直接在转换器顶部打开
AI 编排,配置 Provider、选择布局、切换颜色、查看 schema 校验结果,并导出调试快照。 - AI 编排缓存更好用:按布局家族保留最新结果,重新打开面板后可以直接应用缓存;生成失败时也会尽量保留上一版成功结果。
- 颜色选择更灵活:AI 编排可以自动推荐颜色,也可以在生成前手动选择颜色;生成后切换颜色会复用当前布局结构,不需要完整重新生成。
- Mermaid 导出更稳:在 Obsidian 预览里继续保留 Mermaid 图表,复制到公众号或同步草稿时自动转成 PNG,减少微信吞图或拦截 SVG 的概率。
- 多账号发布默认值:每个公众号账号都可以单独保存原文链接、留言开关和“仅粉丝可留言”,减少每次同步前的重复设置。
- 引用 / Callout 风格更克制:新增中性灰引用模式,常见 Callout 会按语义类型自动着色,未知类型统一回退为信息类样式。
📖 使用方法
-
唤起插件
- 点击 Obsidian 左侧边栏的 🪄 图标 (WeChat Converter)。
- 或使用命令面板 (
Cmd/Ctrl + P) 搜索并执行 "Open Wechat Converter"。
-
预览与调整
- 插件会自动加载当前激活的笔记内容。
- 在右侧面板中,您可以实时预览排版效果。
-
一键复制
- 确认预览效果满意后,点击底部的 [📋 复制到公众号] 按钮。
- 提示"已复制"后,直接在微信公众号后台编辑器中
Ctrl/Cmd + V粘贴即可。
-
一键同步到微信草稿箱 ⭐ 新功能
- 先在插件设置里填好公众号账号(AppID / AppSecret)。
- 点击 [🚀 一键同步],选择账号后即可发送。
- 每个公众号账号都可以单独配置发布默认值:
- 默认原文链接
- 默认开启留言
- 默认仅粉丝可留言
- 默认值读取规则:
- 摘要优先读
excerpt - 封面优先读
cover cover_dir用于同步成功后的“自动清理目录”判断,不作为封面图来源- 如果没有,就自动回退到插件默认逻辑(摘要自动截取、封面取正文首图)
- 摘要优先读
- 你在弹窗里手动上传封面、手动改摘要,始终优先于自动值。
- 发送成功后,文章会出现在公众号后台草稿箱。
横向滑动内容
宽表格左右滑动
当 Markdown 表格列数较多、单元格内容较长,或在手机预览中超过正文宽度时,插件会自动给表格加上横向滚动容器。你不需要额外写语法,正常写 Markdown 表格即可:
| 指标 | 第一季度 | 第二季度 | 第三季度 | 第四季度 | 备注 |
| --- | --- | --- | --- | --- | --- |
| 转化率 | 12.4% | 15.8% | 18.1% | 21.6% | 适合保留完整列宽 |
预览、复制到公众号、同步到草稿箱时,超宽表格都会尽量保持“左右滑动查看”,避免被压成很窄的列。
图片左右滑动
如果你想让多张图片横向排列,并在预览或微信公众号里左右滑动查看,可以使用 Obsidian Callout 写法:
> [!image-swipe] 左右滑动查看图片
> ![[步骤一.png]]
> ![[步骤二.png]]
> 
如果第一屏需要先展示敏感图片提示,可以使用:
> [!image-sensitive] 此类图片可能引发不适,向左滑动查看
> ![[图片一.png]]
> ![[图片二.png]]
也可以先选中多行图片语法,再打开命令面板 (Cmd/Ctrl + P) 运行 插入图片块 或 插入敏感图片块,插件会自动帮你包裹成对应的 Callout。
AI 编排(实验功能)
- 入口有两处:
- 插件设置里的
AI 编排:用于配置 Provider、默认布局、默认颜色和缓存策略 - 转换器顶部工具栏里的
AI 编排:用于对当前文章生成和应用版式
- 插件设置里的
- 当前支持 3 类 Provider 接口:
- OpenAI 兼容接口
- Gemini 兼容格式
- Anthropic 兼容格式
- 内置 3 套布局家族:
原文增强型:最接近普通预览,正文连续性更强教程卡片型:更适合步骤拆解、清单、案例说明轻杂志型:更强调留白、图文节奏和编辑感
- 可以选择
自动配色,也可以在生成前手动指定颜色方案。 - 生成后可以继续手动切换颜色方案,复用当前布局结构,不必每次都重新生成。
- 每个布局家族会保留当前文章最新的一份缓存;重新打开侧边栏后,可以直接应用匹配当前文章的缓存结果。
- 面板里可以直接看:
- schema 校验提醒
- 布局 JSON
- 错误详情
- 复制给 AI 的排查 Prompt
- 当前 JSON 或错误详情
- 如果重新生成失败,上一版成功结果仍然可以保留,方便你继续预览和比较。
同步后自动清理(可选)
- 入口:插件设置 → 高级设置
- 默认是关闭的。
- 只有“发送到微信草稿箱成功”后,才会触发清理。
- 清理的是你在设置里填的目录(删目录,不是删单个文件)。
- 目录支持
{{note}},会自动替换成当前文档名。 - 清理目录请填写 vault 内相对路径(不要填
/Users/...或C:\\...这类绝对路径)。 - 清理成功后,如果文档里的
cover/cover_dir指向这个已删除目录,插件会自动清空这些失效字段。 - 建议开启“使用系统回收站”,这样删错也能找回。
- 示例:
published/{{note}}_img
如果当前文档名是post,实际删除目录是published/post_img。
Mermaid 图表导出说明
- 在 Obsidian 预览里能正常显示的 Mermaid 图表,会尽量在插件预览里继续保持可见。
- 当你执行“复制到公众号”或“一键同步到草稿箱”时,插件会自动把 Mermaid 图表栅格化为 PNG。
- 这样做的目的不是改变样式,而是为了减少微信公众号对长 SVG、复杂 SVG 的清洗和拦截问题。
- 导出链路会尽量保留 Mermaid 原本的颜色,不会套用数学公式那一套 SVG 清理逻辑。
✍️ 中文标点标准化规则
插件支持在右侧排版 setting panel 中开启或关闭“正文标点标准化”:
- 入口:右侧排版
setting panel→正文标点标准化 - 作用范围:仅作用于预览 / 复制 / 同步结果
- 不会修改原始 Markdown 文件
已支持的替换规则
在中文语境下,插件会将常见英文半角标点替换为中文全角标点:
,→,.→。:→:?→?!→!;→;"..."→“...”(...)→(...)
已保护的场景
以下内容会尽量保持原样,避免误伤技术文档:
- 行内代码与代码块,例如
`content`、```ts ... ``` - URL 与邮箱,例如
https://example.com/a?b=1、[email protected] - 常见技术性括号表达式、数学记号、函数/调用语法,例如
公式(x+y)、矩阵(A,B)、foo(bar, baz)、f(x, y) - 英文原句与数字小数点,例如
Version 2.1 is stable. - 文件名、相对路径、Windows 路径,例如
README.md、tests/foo.test.js、C:\Users\name\demo.md - 命令行参数与脚本名,例如
--run、test:coverage - 环境变量赋值,例如
NODE_ENV=production - 日期时间,例如
2026-03-09 09:15:11、2026/02/13 23:00 - Markdown 结构本身,例如表格分隔符、代码围栏、链接语法等
当前边界
- 这是规则驱动的标准化能力,不依赖模型。
- 它适合做“发布前质检”和“统一格式”,不适合做语义判断。
- 像
.../......这类省略号写法会保留原样,不会强制改写。 - 像“并列词语之间把逗号改成顿号
、”这类规则目前没有启用,因为容易误改,后续如果要做,更适合放到 AI 精修能力里。
🎨 引用与 Callout 样式
- 入口:右侧排版
setting panel→ 引用 / Callout 样式 - 现在支持两种整体模式:
跟随主题中性灰(推荐)
中性灰模式更适合长文阅读,会明显减弱大面积主题色的存在感。- Callout 会按语义类型自动着色,例如
note、tip、warning、danger。 - 对于插件还不认识的 Callout 类型,会统一回退为信息类样式,而不是随机继承当前主题色。
🔧 代理设置(解决 IP 白名单问题)
微信公众号 API 需要 IP 白名单验证。如果你使用 VPN 或动态 IP,可以通过 Cloudflare Worker 代理解决。
部署步骤
-
创建 Cloudflare Worker
- 登录 Cloudflare Dashboard
- 左侧菜单选择 Workers & Pages → Create Application → Create Worker
- 命名(如
wechat-proxy)并点击 Deploy
-
编辑 Worker 代码
点击 Edit code,替换为以下代码:
export default { async fetch(request, env) { const MAX_UPLOAD_BYTES = 10 * 1024 * 1024; const ALLOWED_METHODS = new Set(['GET', 'POST', 'UPLOAD']); const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type', }; const jsonResponse = (payload, status = 200) => new Response(JSON.stringify(payload), { status, headers: { ...corsHeaders, 'Content-Type': 'application/json; charset=utf-8', }, }); const isAllowedWechatUrl = (rawUrl) => { try { const parsed = new URL(rawUrl); return parsed.protocol === 'https:' && parsed.hostname === 'api.weixin.qq.com'; } catch { return false; } }; const toUint8Array = (base64) => { const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; }; // 处理 CORS 预检请求 if (request.method === 'OPTIONS') { return new Response(null, { headers: corsHeaders }); } if (request.method !== 'POST') { return jsonResponse({ error: 'Method Not Allowed' }, 405); } try { const body = await request.json(); const { url, method = 'GET', data, fileData, fileName, mimeType } = body; const normalizedMethod = String(method || 'GET').toUpperCase(); // 安全校验:只允许访问微信 API if (typeof url !== 'string' || !isAllowedWechatUrl(url)) { return jsonResponse({ error: 'Invalid URL. Only https://api.weixin.qq.com/ is allowed.' }, 400); } if (!ALLOWED_METHODS.has(normalizedMethod)) { return jsonResponse({ error: 'Invalid method. Only GET, POST, and UPLOAD are allowed.' }, 400); } let response; if (normalizedMethod === 'UPLOAD') { if (typeof fileData !== 'string' || fileData.length === 0) { return jsonResponse({ error: 'Missing fileData for upload.' }, 400); } const approxBytes = Math.floor(fileData.length * 3 / 4); if (approxBytes > MAX_UPLOAD_BYTES) { return jsonResponse({ error: 'Upload too large. Maximum size is 10 MB.' }, 413); } const safeMimeType = typeof mimeType === 'string' && mimeType.startsWith('image/') ? mimeType : 'application/octet-stream'; const safeFileName = typeof fileName === 'string' && /^[\w.\-]+$/.test(fileName) ? fileName : 'image'; // 文件上传处理:Base64 -> Binary -> FormData const bytes = toUint8Array(fileData); const formData = new FormData(); formData.append('media', new Blob([bytes], { type: safeMimeType }), safeFileName); response = await fetch(url, { method: 'POST', body: formData }); } else { // 普通 JSON 请求 const opts = { method: normalizedMethod }; if (normalizedMethod === 'POST') { opts.headers = { 'Content-Type': 'application/json' }; if (data !== undefined) opts.body = JSON.stringify(data); } response = await fetch(url, opts); } const responseText = await response.text(); let result; try { result = responseText ? JSON.parse(responseText) : {}; } catch { return jsonResponse({ error: 'Upstream returned a non-JSON response.' }, 502); } return jsonResponse(result, response.status); } catch (error) { return jsonResponse({ error: 'Proxy request failed.' }, 500); } } };这个版本比旧示例更适合直接公开在文档里:
- 不记录请求 URL,避免把
appid、secret、access_token写进日志。 - 不回显原始请求体和异常堆栈,减少敏感信息暴露。
- 只允许
GET、POST、UPLOAD,并且只允许访问https://api.weixin.qq.com/。 - 上传大小限制为 10 MB,避免异常大文件拖垮 Worker。
- 上传字段固定为
media,与插件当前行为保持一致。
- 不记录请求 URL,避免把
-
配置微信 IP 白名单
将 Cloudflare 出口 IP 添加到微信公众号白名单(官方 IP 列表):
173.245.48.0/20, 103.21.244.0/22, 103.22.200.0/22, 103.31.4.0/22 141.101.64.0/18, 108.162.192.0/18, 190.93.240.0/20, 188.114.96.0/20 197.234.240.0/22, 198.41.128.0/17, 162.158.0.0/15, 104.16.0.0/13 104.24.0.0/14, 172.64.0.0/13, 131.0.72.0/22 -
插件配置
在插件设置 → 高级设置 → API 代理地址 中填入你的 Worker URL:
https://wechat-proxy.your-account.workers.dev该代理仅建议自用,请不要公开分享 Worker 地址,也不要将其部署为公共服务。
🚀 安装
- 从 GitHub Releases 下载最新的
obsidian-wechat-converter.zip插件包。 - 解压并将其中的文件夹放入 Obsidian vault 的
.obsidian/plugins/目录中。最终路径应为:
.../.obsidian/plugins/obsidian-wechat-converter/ - 确保文件夹内至少包含以下文件(三件套运行时):
main.jsmanifest.jsonstyles.css
- 重启 Obsidian 或在设置中刷新插件列表,并启用插件。
BRAT 安装/更新
如果你使用 BRAT 管理插件更新:
- 安装并启用 BRAT 插件。
- 在 BRAT 中添加仓库:
DavidLam-oss/obsidian-wechat-converter。 - 安装后执行一次冒烟检查:
- 打开转换面板
- 预览渲染
- 复制到公众号
- (可选)一键同步到草稿箱
说明:当前版本已支持标准三件套运行时,BRAT 更新路径与 Obsidian 插件标准发布方式一致。
🤝 贡献 (Contributing)
欢迎提交 Issue 或 Pull Request!
- Fork 本仓库。
- 创建您的特性分支 (
git checkout -b feature/AmazingFeature)。 - 提交您的更改 (
git commit -m 'Add some AmazingFeature')。 - 推送到分支 (
git push origin feature/AmazingFeature)。 - 开启一个 Pull Request。
📄 许可证
本项目采用 MIT License 开源。
👨💻 作者
林小卫很行 (DavidLam)
一名热衷于提升生产力的开发者与内容创作者。 如果您在使用过程中有任何问题、建议或发现了 Bug,欢迎随时在 GitHub Issue 区留言反馈。相信工具的力量,让创作更自由。