mcpField
P
publish-x-article

publish-x-article

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

关于 publish-x-article

publish-x-article 是将 Markdown 文章整理并发布到 X Articles 编辑器的技能,会按订阅类型处理格式限制,并通过浏览器自动化和剪贴板插入内容。它适用于需要保留文章结构并处理表格、图表等不支持元素的发布流程。

主要功能

  1. 01解析 Markdown 并生成富文本 HTML
  2. 02按订阅类型调整标题与表格
  3. 03将表格和 Mermaid 图转换为图片
  4. 04通过浏览器与剪贴板填充编辑器
  5. 05按区块位置插入图片和分隔线

适用场景

  1. 01将 Markdown 文章整理到 X Articles
  2. 02为 X Premium 用户转换不支持的格式
  3. 03在文章中按原位置插入图片与分隔线

安装

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

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

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

scripts/
copy_to_clipboard.py
parse_markdown.py
table_to_image.py

详细介绍

发布 X 文章

将 Markdown 内容发布到 X(Twitter)文章编辑器,并通过富文本转换保留格式。自动处理 X Premium 的限制,将不受支持的元素转换为图片。

致谢

此技能受 wshuyi/x-article-publisher-skill 启发,并基于该项目构建。感谢原作者奠定了基础。

交互式设置:询问订阅类型

重要:如果尚不清楚用户的 X 订阅类型,请在处理文章前询问用户。

提示用户
Before publishing, I need to know your X subscription type to handle formatting correctly:

1. **X Premium** - Basic tier ($8/month)
2. **X Premium+** - Plus tier ($16/month)

Which subscription do you have? (Premium / Premium+)

面向中文用户:

在发布之前,我需要了解您的 X 订阅类型以正确处理格式:

1. **X Premium** - 基础版 ($8/月)
2. **X Premium+** - 高级版 ($16/月)

您使用的是哪个版本?(Premium / Premium+)
记住答案

用户回答后,在本次会话的剩余时间内记住其订阅类型。除非用户明确表示要更改,否则不要再次询问。

X 订阅功能对比

功能X PremiumX Premium+
H1 标题(#)仅标题仅标题
H2 标题(##)支持支持
H3 及更深层级标题(### 等)不支持支持
Markdown 表格不支持支持
Mermaid 图表不支持不支持(X 不支持)
代码块引用块引用块
粗体、斜体、链接支持支持
列表支持支持
引用块支持支持
图片支持支持
根据订阅类型进行预处理

X Premium(基础版):

  • 将 H3 及更深层级标题转换为 H2 或粗体
  • 将表格转换为 PNG 图片
  • 将 Mermaid 图表转换为 PNG 图片

X Premium+(高级版):

  • 保留 H3 及更深层级标题
  • 保留表格(原生渲染)
  • 将 Mermaid 图表转换为 PNG 图片(仍不受支持)

前提条件

  • 用于浏览器自动化的 Playwright MCP
  • 用户已使用 Premium 订阅登录 X
  • Python 3.9+ 及依赖项:
    • macOS:pip install Pillow pyobjc-framework-Cocoa markdown
    • Windows:pip install Pillow pywin32 clip-util markdown
  • diagram-to-image 技能(通过 diagramless.xyz API 将表格/Mermaid 转换为 PNG)

脚本

位于 ~/.claude/skills/publish-x-article/scripts/:

parse_markdown.py

解析 Markdown 并提取结构化数据:

python parse_markdown.py <markdown_file> [--output json|html] [--html-only]

返回包含以下内容的 JSON:title、cover_image、content_images(包含用于定位的 block_index)、html、total_blocks

copy_to_clipboard.py

将图片或 HTML 复制到系统剪贴板:

# Copy image (with optional compression)
python copy_to_clipboard.py image /path/to/image.jpg [--quality 80]

# Copy HTML for rich text paste
python copy_to_clipboard.py html --file /path/to/content.html
diagram-to-image.mjs(来自 diagram-to-image 技能)

通过 diagramless.xyz API 将 Mermaid 图表和 Markdown 表格转换为 PNG 图片:

node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/table.md -o /tmp/table.png
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/diagram.mmd -o /tmp/diagram.png --theme ocean

预处理:处理不受支持的元素

发布前,扫描 Markdown 中不受支持的元素,并将其转换为图片。

步骤 0:分析内容是否有限制元素
# Check the markdown file for unsupported elements
cat /path/to/article.md

查找:

  1. 深层级标题(H3+):###、#### 等。
  2. Markdown 表格:包含 | 字符且构成表格结构的行
  3. Mermaid 代码块: ```mermaid
将不受支持的元素转换为图片
1. Markdown 表格 → PNG

检测到表格时:

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

# 2. Convert to image via diagramless.xyz API
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/table.md -o /tmp/table-001.png

# 3. Replace table in markdown with image reference
# ![Table description](/tmp/table-001.png)
2. Mermaid 图表 → PNG

检测到 Mermaid 代码块时:

# 1. Extract mermaid to temp file
cat > /tmp/diagram.mmd << 'MERMAID_EOF'
flowchart TD
    A[Start] --> B[Process]
    B --> C[End]
MERMAID_EOF

# 2. Convert to image via diagramless.xyz API
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/diagram.mmd -o /tmp/diagram-001.png

# 3. Replace mermaid block in markdown with image reference
# ![Diagram description](/tmp/diagram-001.png)
3. 深层标题(H3+)→ 简化结构

**目标:**在符合 X Premium 仅支持 H2 的限制下,保留文章的逻辑结构和可读性。

AI 指南:

当你在 Premium 用户的文章中遇到 H3、H4 或更深层级的标题时,请思考作者的意图:

  • 如果标题在某个章节下引出一个独立子主题,将其转换为段落开头的粗体文本。这样既能保留视觉层级,又不会破坏 X 的格式。

  • **如果某个 H3 实际上是主要章节,**可以考虑将其提升为 H2,但前提是这样做不会让结构变得扁平、缺乏意义。文章仍应保持逻辑流畅。

  • 如果存在深层级结构(H2 → H3 → H4),请有选择地简化:

    • 保留 H2
    • 将 H3 转换为粗体段落
    • 将 H4 转换为斜体,或自然地并入段落
  • **保留含义优先于保留结构。**像 ### Why This Matters 这样的标题可以改成粗体引导语:**这为什么重要?**,后面接正文。请自行判断。

  • **阅读正文。**如果 H3 标题只是“示例”或“注意”,将其处理为引用块或行内强调,可能比单独一行粗体文字更合适。

目标不是机械转换,而是在尊重作者意图的同时,让文章在 X 上读起来自然。

预处理工作流

发布前,请通读文章并为其在 X 上发布做好准备:

  1. 了解文章结构——先阅读文章。主要章节有哪些?作者如何用标题组织思路?

  2. 处理表格和 Mermaid 图表——这些内容需要转换为图片。提取每个表格和图表,将其转换为 PNG,并记录插入位置。

  3. 根据订阅等级调整标题:

    • 对于 Premium+ 用户:保留原有标题(支持 H3+)
    • 对于 Premium 用户:妥善调整 H3+ 标题,同时保留文章的流畅度和原意(参见上述指南)
  4. 创建修改后的 Markdown——将调整后的版本保存到临时文件,以便解析。

目标是让文章在 X 上读起来自然,而不是机械地转换文档。

主要工作流

策略:“先文后图后分割线”

对于包含图片和分割线的文章,先粘贴所有文本内容,再根据 block_index 在正确位置插入图片和分割线。

  1. 预处理:将表格/Mermaid 图表转换为图片,简化深层标题
  2. 使用 Python 脚本解析修改后的 Markdown → 获取标题、图片、分割线(均含 block_index)和 HTML
  3. 打开 X Articles 编辑器
  4. 上传封面图片(第一张图片)
  5. 填写标题
  6. 将 HTML 复制到剪贴板(Python)→ 使用 Cmd+V 粘贴
  7. 在 block_index 指定的位置插入正文图片
  8. 在 block_index 指定的位置插入分割线(通过“插入 > 分割线”菜单)
  9. 保存为草稿(切勿自动发布)

高效执行原则

目标:最大限度减少操作之间的等待时间,实现流畅的自动化体验。

1. 避免不必要的 browser_snapshot

大多数浏览器操作(click、type、press_key 等)都会在返回结果中包含页面状态。不要在每次操作后单独调用 browser_snapshot,直接使用操作返回的页面状态即可。

❌ 错误做法:
browser_click → browser_snapshot → 分析 → browser_click → browser_snapshot → ...

✅ 正确做法:
browser_click → 从返回结果中获取页面状态 → browser_click → ...
2. 避免不必要的 browser_wait_for

只在以下情况使用 browser_wait_for:

  • 等待图片上传完成(textGone="正在上传媒体")
  • 等待页面初始加载(极少数情况)

不要使用 browser_wait_for 等待按钮或输入框出现——页面加载完成后它们会立即可用。

3. 并行执行独立操作

当两个操作互不依赖时,可以在同一条消息中并行调用多个工具:

✅ 可以并行:
- 填写标题 (browser_type) + 复制HTML到剪贴板 (Bash)
- 解析Markdown生成JSON + 生成HTML文件

❌ 不能并行(有依赖):
- 必须先点击create才能上传封面图
- 必须先粘贴内容才能插入图片
4. 连续执行浏览器操作

每个浏览器操作返回的页面状态都包含所有所需的元素引用。直接使用这些引用进行下一步操作:

# 理想流程(每步直接执行,不额外等待):
browser_navigate → 从返回状态找create按钮 → browser_click(create)
→ 从返回状态找上传按钮 → browser_click(上传) → browser_file_upload
→ 从返回状态找应用按钮 → browser_click(应用)
→ 从返回状态找标题框 → browser_type(标题)
→ 点击编辑器 → browser_press_key(Meta+v)
→ ...
5. 提前完成准备工作

开始浏览器操作前,先完成所有准备工作:

  1. 扫描不支持的元素(表格、Mermaid、深层标题)
  2. 将表格/Mermaid 转换为图片
  3. 解析 Markdown 并获取 JSON 数据
  4. 在 /tmp/ 中生成 HTML 文件
  5. 记录 title、cover_image、content_images 等信息

这样,在浏览器操作阶段就可以连续执行,无需中途停下来处理数据。

步骤 0:阅读并调整文章

**首先,阅读文章。**了解文章主题、结构,以及作者想要传达的内容。

保留原文

**重要提示:**切勿修改用户的原始文件。如果需要调整:

  1. 将调整后的版本另存为副本(例如 /tmp/article_adapted.md,或与原文件放在一起并命名为 article_for_x.md)
  2. 告知用户修改了什么,以及两个文件的位置:
    I've adapted your article for X Premium. Here's what changed:
    - Converted 2 tables to images
    - Restructured 3 H3 headers to bold text for better flow
    
    Original preserved: /path/to/article.md
    Adapted version: /path/to/article_for_x.md
    
  3. 使用调整后的副本进行发布

这样可以确保用户能够查看修改内容,并保留原始作品。

根据订阅方案进行调整
对于 Premium 用户(Basic Tier)

请考虑:

  • 有表格吗?→ 将每个表格转换为 PNG 图片
  • 有 mermaid 图表吗?→ 将每个图表转换为 PNG 图片
  • 有 H3 及更高级别的标题吗?→ 根据需要重新组织(参见上面的标题指南)

创建一个经过修改的 Markdown 版本,使其符合 Premium 的限制,同时保持易读性。

对于 Premium+ 用户

请考虑:

  • 有 mermaid 图表吗?→ 转换为 PNG(所有等级目前都不支持)
  • 表格和 H3 及更高级别的标题可以保留原样
将元素转换为图片
# Tables → PNG (auto-detected as table)
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/table-1.md -o /tmp/table-1.png

# Mermaid → PNG (auto-detected as mermaid)
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/diagram-1.mmd -o /tmp/diagram-1.png

在 Markdown 中将这些元素替换为图片引用,并放在原元素所在的位置。

步骤 1:解析 Markdown(Python)

使用 parse_markdown.py 提取所有结构化数据:

python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /path/to/modified_article.md

JSON 输出:

{
  "title": "Article Title",
  "cover_image": "/path/to/first-image.jpg",
  "content_images": [
    {"path": "/tmp/table-1.png", "block_index": 5, "after_text": "context..."},
    {"path": "/tmp/mermaid-1.png", "block_index": 12, "after_text": "another context..."}
  ],
  "dividers": [
    {"block_index": 7, "after_text": "context before divider..."},
    {"block_index": 15, "after_text": "another context..."}
  ],
  "html": "<p>Content...</p><h2>Section</h2>...",
  "total_blocks": 45
}

主要字段:

  • block_index:应在此索引处的块元素之后插入图片/分隔线(从 0 开始计数)
  • total_blocks:HTML 中块元素的总数
  • after_text:仅供参考/调试,不用于定位
  • dividers:分隔线位置数组(必须通过 X 菜单插入 Markdown ---,不能使用 HTML <hr>)

将 HTML 保存到临时文件,以供剪贴板使用:

python parse_markdown.py modified_article.md --html-only > /tmp/article_html.html

步骤 2:打开 X Articles 编辑器

browser_navigate: https://x.com/compose/articles

**重要:**页面加载后会显示草稿列表,而不是编辑器。需要:

  1. 等待页面加载完成:使用 browser_snapshot 检查页面状态
  2. 立即点击 “create” 按钮:不要等待“添加标题”等编辑器元素;只有点击 create 后这些元素才会出现
  3. 等待编辑器加载:点击 create 后,等待编辑器元素出现
# 1. 导航到页面
browser_navigate: https://x.com/compose/articles

# 2. 获取页面快照,找到 create 按钮
browser_snapshot

# 3. 点击 create 按钮(通常 ref 类似 "create" 或带有 create 标签)
browser_click: element="create button", ref=<create_button_ref>

# 4. 现在编辑器应该打开了,可以继续上传封面图等操作

**注意:**不要使用 browser_wait_for text="添加标题" 等待页面加载,因为此文本只有点击 create 后才会出现,否则会导致超时。

如果需要登录,请提示用户手动登录。

步骤 3:上传封面图片

  1. 点击“添加照片或视频”按钮
  2. 使用 browser_file_upload 上传封面图片(路径来自 JSON 输出)
  3. 确认图片已上传

步骤 4:填写标题

  • 查找占位符为“添加标题”的文本框
  • 使用 browser_type 输入标题(来自 JSON 输出)

步骤 5:粘贴文本内容(Python 剪贴板)

使用 Python 将 HTML 复制到系统剪贴板,然后粘贴:

# Copy HTML to clipboard
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html

然后在浏览器中:

browser_click on editor textbox
browser_press_key: Meta+v

这样可以保留所有富文本格式(H2、粗体、链接、列表)。

步骤 6:插入内容图片(按块索引定位)

**关键改进:**使用 block_index 精确定位,而非依赖文字匹配。

定位原理

粘贴 HTML 后,编辑器中的内容由一系列块元素(段落、标题、引用等)构成。每张图片的 block_index 表示应在第 N 个块元素之后插入该图片。

操作步骤
  1. 获取所有块元素:使用 browser_snapshot 获取编辑器内容,找到文本框下的所有子元素
  2. 按索引定位:根据 block_index 点击对应的块元素
  3. 粘贴图片:将图片复制到剪贴板后粘贴

对于每张内容图片(来自 content_images 数组):

# 1. Copy image to clipboard (with compression)
python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py image /path/to/img.jpg --quality 85
# 2. Click the block element at block_index
# Example: if block_index=5, click the 6th block element (0-indexed)
browser_click on the element at position block_index in the editor

# 3. Paste image
browser_press_key: Meta+v

# 4. Wait for upload (use short time, returns immediately when done)
browser_wait_for textGone="正在上传媒体" time=2
反向插入

**注意:**每插入一张图片后,后续图片的实际位置都会偏移。建议按 block_index 从大到小的顺序插入图片。

如果有 3 张图片,block_index 分别为 5、12、27:

  1. 先插入 block_index=27 的图片
  2. 再插入 block_index=12 的图片
  3. 最后插入 block_index=5 的图片

步骤 6.5:插入分隔线(通过菜单)

**重要:**Markdown 中的 --- 分隔线不能通过粘贴 HTML <hr> 标签插入(X Articles 会忽略它)。必须通过 X Articles 的 Insert 菜单插入。

为什么需要特殊处理

X Articles 有自己的原生分隔线元素,只能通过 Insert > Divider 菜单插入。HTML <hr> 标签会被完全忽略。

操作步骤

对于每条分隔线(来自 dividers 数组),按 block_index 从大到小的顺序插入:

# 1. Click the block element at block_index position
browser_click on the element at position block_index in the editor

# 2. Open Insert menu
browser_click on "Insert" button (Add Media button)

# 3. Click Divider menu item
browser_click on "Divider" menuitem

# Divider is inserted at cursor position
反向插入

与图片一样,按 block_index 从大到小的顺序插入分隔线,避免位置偏移。

图片与分隔线的插入顺序

建议先插入所有图片,再插入所有分隔线。两者都按 block_index 从大到小的顺序插入:

  1. 插入所有图片(从最大 block_index 开始)
  2. 插入所有分隔线(从最大 block_index 开始)

步骤 7:保存草稿

  1. 确认内容已粘贴(查看字数指示器)
  2. 草稿会自动保存;如有需要,也可以点击 Save 按钮
  3. 点击“预览”以确认格式
  4. 报告:“草稿已保存。请检查并手动发布。”

关键规则

  1. 绝不发布——只保存草稿
  2. 先预处理——解析前转换表格、mermaid 和深层标题
  3. 第一张图片作为封面——将第一张图片上传为封面图片
  4. 富文本转换——粘贴前始终将 Markdown 转换为 HTML
  5. 使用剪贴板 API——通过剪贴板粘贴,以正确保留格式
  6. 按区块索引定位——使用 block_index 精确放置图片和分隔线
  7. 按逆序插入——按照从最大到最小的 block_index 顺序插入图片和分隔线
  8. 处理 H1 标题——H1 仅用作标题,不包含在正文中
  9. 通过菜单插入分隔线——Markdown --- 必须通过 Insert > Divider 菜单插入(HTML <hr> 会被忽略)

支持的格式(预处理后)

元素支持情况备注
H2 (##)原生支持章节标题
粗体 (**)原生支持强调
斜体 (*)原生支持强调
链接 ([](url))原生支持超链接
有序列表原生支持1. 2. 3.
无序列表原生支持- 项目符号
引用块 (>)原生支持引用文本
代码块转换→ 引用块
表格转换→ PNG 图片
Mermaid转换→ PNG 图片
H3 及更深层级标题转换→ H2 或粗体
分隔线 (---)通过菜单插入→ Insert > Divider

示例流程

用户:“将 /path/to/article.md 发布到 X”

# Step 0: Analyze content
# Found: 1 table, 1 mermaid diagram, 2 H3 headers

# Step 0.1: Convert table to image
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/table-1.md -o /tmp/table-1.png

# Step 0.2: Convert mermaid to image
node ~/.claude/skills/diagram-to-image/scripts/diagram-to-image.mjs /tmp/mermaid-1.mmd -o /tmp/mermaid-1.png

# Step 0.3: Create modified markdown with image refs and flattened headers
# Save to /tmp/article_modified.md

# Step 1: Parse modified markdown
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md > /tmp/article.json
python ~/.claude/skills/publish-x-article/scripts/parse_markdown.py /tmp/article_modified.md --html-only > /tmp/article_html.html
  1. 导航到 https://x.com/compose/articles
  2. 点击创建,上传封面图片(仅封面使用 browser_file_upload)
  3. 填写标题(来自 JSON:title)
  4. 复制并粘贴 HTML:
    python ~/.claude/skills/publish-x-article/scripts/copy_to_clipboard.py html --file /tmp/article_html.html
    
    然后:browser_press_key Meta+v
  5. 对每张正文图片(包括转换后的表格/mermaid PNG),按照 block_index 的逆序操作:
    python copy_to_clipboard.py image /path/to/img.jpg --quality 85
    
    • 点击 block_index 位置的区块元素
    • browser_press_key Meta+v
    • 等待上传完成
  6. 在预览中检查
  7. “草稿已保存。请检查并手动发布。”

最佳实践

为什么用 block_index 而非文字匹配?
  1. 精确定位:不依赖文字内容,即使多处文字相似也能正确定位
  2. 可靠性:索引是确定性的,不会因为文字相似而混淆
  3. 便于调试:仍保留 after_text 供人工核验
为什么用 Python 而非浏览器内 JavaScript?
  1. 本地处理更可靠:Python 直接操作系统剪贴板,不受浏览器沙盒限制
  2. 图片压缩:上传前压缩图片(--quality 85),减少上传时间
  3. 代码复用:脚本固定不变,无需每次重新编写转换逻辑
  4. 便于调试:脚本可单独测试,问题易于定位
等待策略

关键理解:browser_wait_for 的 textGone 参数会在文字消失时立即返回,time 只是最大等待时间,不是固定等待时间。

# 正确用法:短 time 值,条件满足立即返回
browser_wait_for textGone="正在上传媒体" time=2

# 错误用法:固定长时间等待
browser_wait_for time=5  # 无条件等待5秒,浪费时间
封面图 vs 正文图片
  • 封面图:使用 browser_file_upload(因为有专门的上传按钮)
  • 正文图片:使用 Python 剪贴板 + 粘贴(效率更高)

故障排除

表格渲染不正确
  • 确保已安装 Pillow:pip install pillow
  • 检查表格 Markdown 语法是否有效
Mermaid 转换失败
  • 检查 diagramless.xyz 是否可访问
  • 检查 mermaid 语法是否有效
  • 尝试指定类型:--type mermaid
深层标题仍然显示
  • 手动将 ### 展平为 ## 或 **bold**
  • 重新运行预处理
图片上传超时
  • 使用 --quality 70 压缩图片
  • 使用更短的 browser_wait_for time=2

评论

支持 Markdown