davidlam-oss5k downloadsConvert Markdown into polished WeChat articles with live preview, copy, and draft sync.
简体中文 | English
让技术写作回归优雅与纯粹。
一款专为 Obsidian 打造的微信公众号排版增强插件。它不仅仅是一个转换工具,更是您内容创作流中的"数字化妆师"。我们解决了 Obsidian 到微信公众号排版的"最后一公里"问题,让您专注于内容创作,无需为繁琐的格式调整而分心。
只需一键,即可将您的 Markdown 笔记转换为符合微信生态美学、阅读体验极佳的 HTML,无论是代码块、引用、列表还是本地图片,都能完美呈现。
本项目基于开源项目 ai-writing-plugins 进行深度重构与迭代开发。我们致力于打造 Obsidian 生态中体验最好的公众号排版工具。
如果这个插件帮你节省了公众号排版、复制或同步草稿箱的时间,欢迎支持项目继续维护。
相较于原版,我们重写了核心渲染逻辑并新增了大量实用功能,旨在实现真正的**"所见即所得"**:
➗ 完美支持数学公式 (Math Support) ⭐ v2.1 新增
$E=mc^2$ 或 $$...$$,所见即所得。
📊 Mermaid 图表支持
🚀 一键同步到微信草稿箱 (v2.2 增强)
cover,会优先用它做封面;没写就自动用正文第一张图,也可以手动换图。excerpt,会优先用它;没写就自动截取前 45 个字,也可以手动改。{{note}},会自动替换成当前文档名,例如 published/{{note}}_img。
🎛 全新可视化设置面板 (Settings Panel)
| 浅色模式 | 深色模式 |
|---|---|
![]() |
![]() |
🎨 三大专家级主题 (Premade Themes)
note、tip、warning、danger 等;未知类型会自动回退为信息类样式。🖼️ 强大的本地图片支持 (Local Image Support)
![[Wiki Link]] 和 ![]())。⚡️ 实时渲染预览 (Live Preview)
| 手机仿真模式 | 经典全宽模式 |
|---|---|
![]() |
![]() |
💻 Mac 风格代码块与样式还原
AI 编排,配置 Provider、选择布局、切换颜色、查看 schema 校验结果,并导出调试快照。唤起插件
Cmd/Ctrl + P) 搜索并执行 "Open Wechat Converter"。预览与调整
一键复制
Ctrl/Cmd + V 粘贴即可。一键同步到微信草稿箱 ⭐ 新功能
excerptcovercover_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 编排:用于配置 Provider、默认布局、默认颜色和缓存策略AI 编排:用于对当前文章生成和应用版式原文增强型:最接近普通预览,正文连续性更强教程卡片型:更适合步骤拆解、清单、案例说明轻杂志型:更强调留白、图文节奏和编辑感自动配色,也可以在生成前手动指定颜色方案。![]() 1. 配置 Provider 与 布局 |
![]() 2. 生成结果与缓存 |
![]() 3. 应用到预览区 |

AI 编排全局设置(Provider 与 缓存策略管理)
{{note}},会自动替换成当前文档名。/Users/... 或 C:\\... 这类绝对路径)。cover / cover_dir 指向这个已删除目录,插件会自动清空这些失效字段。published/{{note}}_imgpost,实际删除目录是 published/post_img。插件支持在右侧排版 setting panel 中开启或关闭“正文标点标准化”:
setting panel → 正文标点标准化在中文语境下,插件会将常见英文半角标点替换为中文全角标点:
, → ,. → 。: → :? → ?! → !; → ;"..." → “...”(...) → (...)以下内容会尽量保持原样,避免误伤技术文档:
`content`、```ts ... ```https://example.com/a?b=1、[email protected]公式(x+y)、矩阵(A,B)、foo(bar, baz)、f(x, y)Version 2.1 is stable.README.md、tests/foo.test.js、C:\Users\name\demo.md--run、test:coverageNODE_ENV=production2026-03-09 09:15:11、2026/02/13 23:00... / ...... 这类省略号写法会保留原样,不会强制改写。、”这类规则目前没有启用,因为容易误改,后续如果要做,更适合放到 AI 精修能力里。setting panel → 引用 / Callout 样式跟随主题中性灰(推荐)中性灰 模式更适合长文阅读,会明显减弱大面积主题色的存在感。note、tip、warning、danger。微信公众号 API 需要 IP 白名单验证。如果你使用 VPN 或动态 IP,可以通过 Cloudflare Worker 代理解决。
创建 Cloudflare 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);
}
}
};
这个版本比旧示例更适合直接公开在文档里:
appid、secret、access_token 写进日志。GET、POST、UPLOAD,并且只允许访问 https://api.weixin.qq.com/。media,与插件当前行为保持一致。配置微信 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 地址,也不要将其部署为公共服务。
obsidian-wechat-converter.zip 插件包。.obsidian/plugins/ 目录中。最终路径应为:
.../.obsidian/plugins/obsidian-wechat-converter/
main.jsmanifest.jsonstyles.css如果你使用 BRAT 管理插件更新:
DavidLam-oss/obsidian-wechat-converter。说明:当前版本已支持标准三件套运行时,BRAT 更新路径与 Obsidian 插件标准发布方式一致。
欢迎提交 Issue 或 Pull Request!
git checkout -b feature/AmazingFeature)。git commit -m 'Add some AmazingFeature')。git push origin feature/AmazingFeature)。本项目采用 MIT License 开源。
林小卫很行 (DavidLam)
一名热衷于提升生产力的开发者与内容创作者。 如果您在使用过程中有任何问题、建议或发现了 Bug,欢迎随时在 GitHub Issue 区留言反馈。相信工具的力量,让创作更自由。