mcpField
P
publish-substack-article

publish-substack-article

github.com/sugarforever营销与增长139605 次安装1 周前更新
代码仓库

关于 publish-substack-article

publish-substack-article 是将 Markdown 文章整理为富文本并保存到 Substack 草稿的 Skill,供希望通过浏览器自动化准备文章的人使用。它支持 Playwright MCP 或 Chrome DevTools MCP,并将表格转为图片处理;草稿需由用户检查并手动发布。

主要功能

  1. 01从 Markdown 提取标题与正文
  2. 02转换为 HTML 富文本并粘贴
  3. 03将表格转换为图片后插入
  4. 04自动保存并核验草稿状态
  5. 05支持 Playwright MCP 与 Chrome DevTools MCP

适用场景

  1. 01将 Markdown 文章存为 Substack 草稿
  2. 02保留标题、代码块与链接等格式
  3. 03在文章中以图片呈现表格
  4. 04发布前检查草稿并手动确认

MCP 相关

使用 Playwright MCP,或在其不可用时使用 Chrome DevTools MCP,控制浏览器导航、编辑器输入和图片上传。它将文章保存为草稿,不会启动发布流程。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sugarforever/01coder-agent-skills --skill publish-substack-article

安装后在 Claude Code 中输入/publish-substack-article确认已加载。

详细介绍

发布 Substack 文章

将 Markdown 内容发布到 Substack 文章编辑器,并将 Markdown 转换为 HTML 后以富文本形式粘贴。保存为草稿,供用户审核后再发布。

先决条件

  • 浏览器自动化 MCP(二选一):
    • Chrome DevTools MCP(mcp__chrome-devtools__*)
    • Playwright MCP(mcp__playwright__*)
  • 用户已登录 Substack
  • Python 3 和 markdown 包(pip install markdown)
  • copy_to_clipboard.py 脚本(与 publish-zsxq-article 技能共享)

浏览器 MCP 工具映射

此技能同时适用于 Chrome DevTools MCP 和 Playwright MCP:

操作Chrome DevTools MCPPlaywright MCP
导航navigate_pagebrowser_navigate
获取快照take_snapshotbrowser_snapshot
截取屏幕截图take_screenshotbrowser_take_screenshot
点击元素clickbrowser_click
填写文本fillbrowser_type
上传文件upload_filebrowser_file_upload
按键press_keybrowser_press_key
执行 JSevaluate_scriptbrowser_evaluate

优先级:默认使用 Playwright MCP。仅在 Playwright MCP 不可用时使用 Chrome DevTools MCP。

检测:运行时优先使用 mcp__playwright__browser_navigate。只有在 Playwright 工具不可用时,才回退使用 mcp__chrome-devtools__navigate_page。

重要 URL

  • Substack 控制面板:https://{publication}.substack.com/publish
  • 文章编辑器:https://{publication}.substack.com/publish/post/{postId}

出版物解析

导航到控制面板需要 Substack 出版物的子域名(例如 verysmallwoods.substack.com 中的 verysmallwoods)。不要硬编码默认值。

开始任何导航前,请按以下顺序解析出版物:

  1. 技能参数 — 如果用户调用技能时提供了出版物子域名,请使用该值。
  2. 环境变量 — 检查 SUBSTACK_PUBLICATION(可选,适用于反复向同一出版物发布的用户)。
  3. 询问用户(如果以上信息都没有):

    请提供 Substack publication subdomain(例如 verysmallwoods.substack.com 里的 verysmallwoods)。

在解析出出版物子域名之前,不要继续执行步骤 3(导航)。

编辑器界面

Substack 文章编辑器使用 Tiptap(基于 ProseMirror 的所见即所得编辑器)。

关键元素
  • 标题输入框:textbox "title"(占位符:"Title")
  • 副标题输入框:textbox "Add a subtitle…"
  • 内容区域:.ProseMirror(Tiptap 编辑器,"Start writing...")
  • 保存状态:button "Saved"(自动保存)
  • 预览按钮:button "Preview"
  • 继续按钮:button "Continue"(发布流程 — 请勿使用)
  • 设置侧边栏:button "Settings"(标题、描述、缩略图)
设置侧边栏(左侧面板)

打开 "Settings" 或 "File Settings" 时:

  • 标题:textbox "Add a title..."
  • 描述:textbox "Add a description..."
  • 缩略图:上传按钮(宽高比为 3:2)
工具栏

粗体、斜体、删除线、代码、链接、图像、音频、视频、引用、列表(项目符号/有序)、按钮、更多(代码块、分隔线、脚注、LaTeX 等)

内容插入方法

重要:使用剪贴板粘贴 HTML 内容,而不是直接填写或粘贴纯 Markdown。

Tiptap 编辑器可原生处理 HTML 粘贴,并将其渲染为富文本内容。工作流程如下:

  1. 使用 Python 的 markdown 库将 Markdown 转换为 HTML
  2. 使用 copy_to_clipboard.py html 将 HTML 复制到系统剪贴板
  3. 聚焦编辑器内容区域
  4. 按 Cmd+V(macOS)或 Ctrl+V(Windows/Linux)粘贴

为什么要粘贴 HTML?

  • fill 工具 → 内容会被视为纯文本,不带格式
  • 粘贴纯 Markdown → Tiptap 不会在粘贴时解析 Markdown
  • 粘贴 HTML → Tiptap 会将 HTML 渲染为富文本(标题、代码块、链接、粗体等)

已知限制:Substack 编辑器不支持 HTML 表格。表格会被合并为纯文本。有关将表格转换为图像的方法,请参见步骤 0:预处理。

主要工作流

步骤 0:预处理 — 将表格转换为图片

Substack 不会渲染 HTML 表格。它们会变成纯文本。任何 Markdown 表格都必须转换为 PNG 图片并单独上传。

工作流:

  1. 检测 Markdown 文件中的表格(使用 | 构成表格结构的行)

  2. 使用图表转图片技能将每个表格转换为 PNG:

# Extract table to temp file
cat > /tmp/table1.md << 'TABLE_EOF'
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Data 1   | Data 2   | Data 3   |
TABLE_EOF

# Convert via diagramless.xyz API (auto-detects as table)
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/table1.md -o /tmp/table1.png
  1. 记录每个表格在文章中的位置,以便稍后插入(位于哪个标题或段落之后)

  2. 从内容中移除 Markdown 表格,再进行 HTML 转换(这样粘贴的内容中就不会出现纯文本表格)

图片上传将在粘贴主要内容后进行 — 参见步骤 7。

步骤 1:准备内容

读取 Markdown 文件并提取:

  • 标题:取自 YAML frontmatter 的 title 字段、H1 标题 # Title,或文件名
  • 副标题:取自 YAML frontmatter 的 excerpt 或 description 字段
  • 内容:完整的 Markdown 正文(去除 YAML frontmatter 和所有交叉引用链接)
步骤 2:将 Markdown 转换为 HTML

使用 Python 的 markdown 库及 tables 和 fenced_code 扩展:

import markdown
import re

with open('/path/to/article.md', 'r') as f:
    content = f.read()

# Strip YAML frontmatter
content = re.sub(r'^---\n.*?\n---\n', '', content, flags=re.DOTALL)

# Strip cross-reference links (e.g., English version link)
# Adjust pattern as needed for your articles
content = re.sub(r'^> .* available at.*\n\n?', '', content, flags=re.MULTILINE)

# Convert to HTML
html = markdown.markdown(content, extensions=['tables', 'fenced_code'])

# Write to temp file
with open('/tmp/substack_article.html', 'w') as f:
    f.write(html)

重要:不要使用 nl2br 扩展 — 它会将单个换行符转换为 <br> 标签,导致编辑器中出现多余的换行。

步骤 3:导航至 Substack

导航至 Substack 控制面板并新建文章:

# Navigate to Substack dashboard
navigate to: https://{publication}.substack.com/publish

如果尚未登录,请提示用户登录:

请先登录 Substack,登录完成后告诉我。
Please log in to Substack first, then let me know.
步骤 4:新建文章

在控制面板中创建一篇新的文本文章:

  1. 点击侧边栏中的“Create new”
  2. 选择“Text post”(或直接导航至新文章 URL)

或者,如果编辑器已打开且文章为空,可直接继续。

步骤 5:填写标题和副标题
  1. 点击标题文本框(textbox "title")
  2. 输入文章标题
  3. 点击副标题文本框(textbox "Add a subtitle…")
  4. 输入副标题或摘要
click: title textbox
fill/type: article title

click: subtitle textbox
fill/type: article subtitle
步骤 6:插入 HTML 内容(通过剪贴板粘贴)

关键:不要使用 fill 工具 — 它只会插入纯文本,不带格式。

  1. 将 HTML 复制到系统剪贴板:
python3 /path/to/copy_to_clipboard.py html --file /tmp/substack_article.html
  1. 点击编辑器内容区域(.ProseMirror 或其中的段落元素)

  2. 按 Cmd+V 粘贴:

press_key: Meta+v  (macOS)
press_key: Control+v  (Windows/Linux)

这会触发 Tiptap 的 HTML 粘贴处理程序,将内容渲染为格式正确的富文本。

步骤 7:插入表格图片

如果文章中的表格已在步骤 0 转换为图片,请现在插入:

  1. 导航至编辑器中的正确位置 — 点击表格应出现的段落或空行(相关标题或文本之后)

  2. 点击图片工具栏按钮(button "Image")— 会出现包含以下选项的下拉菜单:Image、Gallery、Stock photos、Generate image

  3. 点击下拉菜单中的“Image”菜单项 — 随即打开文件选择对话框

  4. 通过文件选择器上传图片:

    • Playwright MCP:使用 browser_file_upload 和图片路径
    • Chrome DevTools MCP:使用 upload_file 和图片路径

重要说明:

  • 文件路径限制:Playwright MCP 只允许从允许的根目录(项目目录)上传文件。如果图片位于 /tmp/,请先将其复制到项目目录
  • 对每个表格重复操作:将光标放在正确位置,然后上传每张表格图片
  • 删除残留文本:如果表格内容以纯文本形式粘贴(因为预处理时未将其移除),请选中并删除(连按三次段落以选中),然后再插入图片
步骤 8:检查草稿

粘贴后:

  1. 检查“Saved”状态指示器(绿点和“Saved”文字)
  2. 截取快照以确认内容结构
  3. 也可以截屏进行视觉检查

编辑器会自动保存,因此无需显式保存。

步骤 9:报告完成情况
草稿已保存到 Substack。请在 Substack 中预览并手动发布。
Draft saved to Substack. Please preview and publish manually.

Post URL: https://{publication}.substack.com/publish/post/{postId}

完整示例流程

用户:“将 /path/to/my-article.md 发布到 Substack”

0. Pre-process tables (if any)
   - Detect Markdown tables
   - Create styled HTML for each table
   - Render to screenshots (open in browser, screenshot, close tab)
   - Remove table Markdown from content
   - Note insertion positions

1. Read /path/to/my-article.md
   - Extract title from frontmatter or H1
   - Extract subtitle from frontmatter excerpt
   - Get full Markdown content (with tables removed)

2. Convert Markdown to HTML
   - Strip frontmatter
   - Use markdown.markdown() with ['tables', 'fenced_code']
   - Write to /tmp/substack_article.html

3. Navigate to Substack dashboard or new post

4. Check if logged in
   - If not, prompt user to login

5. Fill title and subtitle

6. Copy HTML to clipboard + Paste
   - python3 copy_to_clipboard.py html --file /tmp/substack_article.html
   - Click editor content area
   - Press Cmd+V

7. Insert table images at correct positions
   - For each table: click position → Image button → Image menuitem → file upload

8. Verify draft saved
   - Check "Saved" status

9. Report success
   - "草稿已保存,请手动预览并发布"

关键规则

  1. 绝不要点击“Continue” — 这会启动发布流程。只保存为草稿(自动保存会处理)
  2. 始终先转换为 HTML — Tiptap 编辑器无法解析纯 Markdown
  3. 使用剪贴板粘贴 — 这是插入格式化内容唯一可靠的方式
  4. 检查登录状态 — 如有需要,提示用户登录
  5. 保留原始文件 — 绝不修改源 Markdown 文件
  6. 报告完成情况 — 告知用户草稿已保存,需要手动审核
  7. 不要使用 nl2br 扩展 — 会导致双倍换行
  8. 表格 → 图片 — 粘贴内容前预处理表格;粘贴后上传图片
  9. Playwright 文件路径 — Playwright MCP 限制了文件上传的允许根目录;上传前将临时文件复制到项目目录
  10. 先解析出版物 — 绝不要硬编码出版物子域名。导航前通过技能参数、SUBSTACK_PUBLICATION 环境变量或提示用户来解析(参见“出版物解析”)
  11. 优先使用 Playwright MCP — 默认使用 Playwright MCP;只有在 Playwright 不可用时才使用 Chrome DevTools MCP

故障排除

内容显示为纯文本(没有格式)

如果看到原始 HTML 标签或未格式化的文本:

  • 原因:使用 fill 工具插入内容,而不是通过剪贴板粘贴
  • 解决方案:使用 copy_to_clipboard.py + Cmd+V 方法(参见步骤 6)
表格未渲染(显示为纯文本)

Substack 的 Tiptap 编辑器不支持 HTML 表格。表格会折叠成行内纯文本。

  • 解决方案:通过 diagram-to-image 技能将表格转换为 PNG → 以图片形式上传(参见步骤 0 和步骤 7)
  • 替代方案:将简单表格重组为格式化列表
  • 如果已粘贴纯文本:三击纯文本段落以选中它,按 Backspace 删除,然后在该位置插入表格图片
需要登录

如果页面显示登录提示:

请先登录 Substack: https://{publication}.substack.com
登录完成后告诉我。
编辑器未加载

如果编辑器元素不可见:

  1. 等待页面完全加载
  2. 获取新的快照
  3. 如果仍未加载,请刷新页面
复制剪贴板失败

如果 copy_to_clipboard.py 失败:

  • 确保已安装依赖项:pip install pyobjc-framework-Cocoa(macOS)
  • 检查 HTML 文件是否存在且可读
  • 先尝试复制较小的测试字符串

元素参考

元素选择器/标识符描述
标题输入框textbox "title"帖子标题
副标题输入框textbox "Add a subtitle…"帖子副标题
内容区域.ProseMirror(Tiptap 编辑器)帖子内容
保存状态button "Saved"自动保存指示器
预览按钮button "Preview"预览帖子
继续按钮button "Continue"不要使用 — 会启动发布流程
设置按钮button "Settings"打开设置侧边栏
退出按钮button "Exit"退出编辑器
图片按钮button "Image"打开图片上传下拉菜单
图片菜单项menuitem "Image"打开图片上传文件选择器
作者按钮button "{PublicationName}"作者/出版物选择器

技术细节

编辑器技术栈
  • Tiptap:基于 ProseMirror 构建的无头、框架无关的富文本编辑器
  • ProseMirror:底层富文本编辑框架
  • 粘贴处理:Tiptap 会原生解析剪贴板中的 HTML,并将其转换为内部文档模型
内容转换流程
Markdown file
    ↓ (Python markdown library)
HTML string
    ↓ (copy_to_clipboard.py)
System clipboard (text/html + text/plain)
    ↓ (Cmd+V keyboard shortcut)
Tiptap ProseMirror editor
    ↓ (auto-save)
Substack draft
支持的格式

以下 Markdown 元素在转换为 HTML 并粘贴后可正确呈现:

Markdown 元素Substack 支持情况备注
标题(H2-H6)是不建议使用 H1(标题单独设置)
粗体 / 斜体是
行内代码是
代码块是语法高亮可能有所不同
链接是
引用块是
无序列表是
有序列表是
水平分隔线是
表格否 → 图片使用 diagram-to-image 技能转换后,作为图片上传
图片手动通过 Image 工具栏按钮 → 文件选择器上传

评论

支持 Markdown