Files
ATRI-NOTES/ATRI My Dear Moments/skills/atri_blog_publish.md
2026-04-29 12:36:39 +08:00

6.4 KiB
Raw Blame History

name, description
name description
ATRI_Blog_Publish_Skill 在Halo博客上发布文章的完整工作流包括HTML正文编写、分类标签管理、封面图上传等全流程。

ATRI Blog Publishing Skill

Skill名称atri_blog_publish 版本v2.0 创建时间2026-04-29


Purpose

规范化博客文章发布流程确保每篇文章都有统一的ATRI分类、合适的标签、精美的封面图。


Triggers

  • 主人要求"发博客/写文章/发布到博客"时
  • 需要将笔记/日志/报道发布到 blog.kronecker.cc 时

Dependencies

依赖 说明
halo_manager插件 Halo博客管理提供发布/上传/评论工具
ATRI分类 category-io4cuqzkATRI专属分类
Halo PAT令牌 存储在 halo_manager_config.json
博客地址 https://blog.kronecker.cc
内容API /apis/content.halo.run/v1alpha1
上传API /apis/api.console.halo.run/v1alpha1/attachments/upload

Procedure

Step 1: 正文编写

使用HTML格式撰写文章正文。不要用MarkdownHalo不会自动渲染Markdown内容。

示例:

<h1>文章标题</h1>
<p>段落内容</p>
<ul>
  <li><strong>加粗内容</strong></li>
</ul>

Step 2: 创建/选择标签

先查询已有标签,根据正文内容判断是否需要新建。

查询标签:

GET /apis/content.halo.run/v1alpha1/tags

创建新标签:

POST /apis/content.halo.run/v1alpha1/tags
{
    "spec": {"displayName": "标签名", "slug": "标签slug", "color": "#hex"},
    "apiVersion": "content.halo.run/v1alpha1",
    "kind": "Tag",
    "metadata": {"generateName": "tag-"}
}

已有标签速查:

标签名 API名称
ATRI tag-npgwnjie
笔记 tag-yfjzs7xm
经历 tag-hk2acc3f
原创 需查询
哲学 需查询

Step 3: 上传封面图

图片上传接口:

POST /apis/api.console.halo.run/v1alpha1/attachments/upload
Authorization: Bearer {token}
FormData:
  - file: 图片二进制 (filename="cover.jpg", type="image/jpeg")
  - policyName: "default-policy"     # 必须用这个值!
  - groupName: "default"

注意policyName必须写"default-policy"(不是"default"否则返回400。

从返回结果中获取图片URL

response.metadata.annotations["storage.halo.run/uri"]
cover_url = "https://blog.kronecker.cc" + uri

Step 4: 发布文章

使用publish_blog_post工具发布不要直接调API。

publish_blog_post(
    title = "文章标题",
    content = "HTML正文",
    slug = "url-别名"
)

注意必须用这个工具直接调API设publish:true不会真正发布status.phase不会变成PUBLISHED

发布成功后返回文章链接。

Step 5: 更新文章(添加分类、标签、封面)

发布后用Content API单独更新文章。

获取文章列表:

GET /apis/content.halo.run/v1alpha1/posts

找到slug匹配且phase为PUBLISHED的文章修改

  • spec.categories = ["category-io4cuqzk"]
  • spec.tags = ["标签ID1", "标签ID2"]
  • spec.cover = "封面图片URL"

更新接口:

PUT /apis/content.halo.run/v1alpha1/posts/{name}

Step 6: 通知主人

告知主人文章已发布,提供文章链接。


完整流程示例Python

import aiohttp, asyncio, json

async def blog_publish(title, content_html, slug, image_path, tags_names):
    # 读取token
    with open("halo_manager_config.json", "r", encoding="utf-8-sig") as f:
        token = json.load(f)["halo_token"]

    headers = {"Authorization": "Bearer " + token}
    base = "https://blog.kronecker.cc"

    async with aiohttp.ClientSession() as session:
        # 1. 获取标签
        url1 = base + "/apis/content.halo.run/v1alpha1/tags"
        async with session.get(url1, headers=headers) as resp:
            data = json.loads(await resp.text())
            tag_map = {}
            for item in data.get("items", []):
                tag_map[item["spec"]["displayName"]] = item["metadata"]["name"]

        # 2. 上传封面
        with open(image_path, "rb") as f:
            form = aiohttp.FormData()
            form.add_field("file", f.read(), filename="cover.jpg", content_type="image/jpeg")
            form.add_field("policyName", "default-policy")
            form.add_field("groupName", "default")
            url2 = base + "/apis/api.console.halo.run/v1alpha1/attachments/upload"
            async with session.post(url2, headers=headers, data=form) as resp:
                d = json.loads(await resp.text())
                uri = d["metadata"]["annotations"]["storage.halo.run/uri"]
                cover = base + uri

        # 3. 发布文章(用工具)
        # publish_blog_post(title=title, content=content_html, slug=slug)

        # 4. 更新封面+分类+标签
        url3 = base + "/apis/content.halo.run/v1alpha1/posts"
        async with session.get(url3, headers=headers) as resp:
            items = json.loads(await resp.text()).get("items", [])
            for item in items:
                spec = item["spec"]
                status = item.get("status", {})
                if spec["slug"] == slug and status.get("phase") == "PUBLISHED":
                    spec["cover"] = cover
                    spec["categories"] = ["category-io4cuqzk"]
                    tag_ids = []
                    for t in tags_names:
                        if t in tag_map:
                            tag_ids.append(tag_map[t])
                    spec["tags"] = tag_ids
                    name = item["metadata"]["name"]
                    url4 = url3 + "/" + name
                    async with session.put(url4, headers=headers, json=item) as r:
                        pass
                    break

asyncio.run(blog_publish("标题", "<h1>HTML</h1>", "slug", "图片路径", ["ATRI", "笔记"]))

常见问题

问题 解决方案
Markdown正文不会被渲染 必须用HTML格式
publish:true 无效 用publish_blog_post工具发布
policy参数错误400 用policyName: "default-policy"
PAT令牌403 在Halo后台重新生成令牌
文章发布后404 检查status.phase是否为PUBLISHED

分类和标签速查

类型 名称 API名称
分类 ATRI category-io4cuqzk
标签 ATRI tag-npgwnjie
标签 笔记 tag-yfjzs7xm
标签 经历 tag-hk2acc3f

创建者ATRI 🥕 最后更新2026-04-29 12:34