write-post-event-highlight-reel-script
将活动笔记转化为社交平台用的简短回顾脚本。
通过API创建、更新和读取OpenNote笔记,支持图文与标签管理。
openclaw skills install @liam-duan/write-opennote命令、参数、文件名以原文为准
使用 https://api.opennote.cc/api/v1 处的公共 API 将笔记写入 [OpenNote](https://opennote.cc)。
- diaries:write — 创建和更新笔记
- images:write — 向笔记上传图片
milo_pat_v1_ 开头,且 仅显示一次在你的 OpenClaw 环境中设置 OPENNOTE_API_TOKEN:
选项 A — OpenClaw 配置(推荐):
在 OpenClaw 设置中添加环境变量:
OPENNOTE_API_TOKEN=milo_pat_v1_your_token_here选项 B — Shell 配置文件(本地运行时使用):
export OPENNOTE_API_TOKEN="milo_pat_v1_your_token_here"将此内容添加至 ~/.zshrc 或 ~/.bashrc 以在会话间持久化。
安全提示:
OPENNOTE_API_TOKEN401 INVALID_API_TOKEN 错误,说明令牌已过期或被撤销令牌从 OPENNOTE_API_TOKEN 环境变量读取。必须具备 diaries:write 权限。若需上传图片,则还需 images:write 权限。
此技能在工作目录下的 .opennote/ 中维护两个本地文件:
.opennote/opennote-labels-cache.json — 缓存的用户标签.opennote/opennote-history.json — 通过此技能写入/编辑的所有笔记日志每次调用开始时都应读取这些文件。若文件缺失,视为为空。若用户询问之前写过的笔记,请查阅历史文件。
读取 .opennote/opennote-labels-cache.json。若文件存在且上次获取时间在 24 小时内,则使用缓存标签。
预期缓存格式:
{
"fetchedAt": 1741111111111,
"labels": [
{ "categoryID": 1, "categoryName": "个人", "categoryColor": 4294198070 },
{ "categoryID": 2, "categoryName": "工作", "categoryColor": 4283215696 }
]
}若缓存缺失、为空或过期(超过 24 小时),则从 API 获取标签:
curl -s "https://api.opennote.cc/api/v1/labels" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN"响应示例:
{
"labels": [
{ "categoryID": 1, "categoryName": "个人", "categoryColor": 4294198070, "visibility": true, "coverImageName": null, "lastModified": 1741111111111, "fontFamily": null, "backgroundPreset": null }
]
}获取后,将结果写入 .opennote/opennote-labels-cache.json,并使用当前时间戳作为 fetchedAt。
categoryIDcategory: 0(无标签)随机选择标签时,需告知用户选择了哪个标签。
向用户询问想写的内容。收集以下信息:
const now = Date.now(); // Unix 毫秒时间戳
const fileName = `${now}.json`;构建 Quill Delta 操作数组,然后通过 JSON.stringify() 转换为 richContent 字段。
纯文本:
{ "insert": "你好世界" }换行符(必需 — 每个 Delta 必须至少包含一个):
{ "insert": "\n" }内联样式(在插入文本时设置):
bold(布尔值)italic(布尔值)underline(布尔值)strike(布尔值)color(十六进制字符串,如 "#2a7fff")—— 推荐使用下方配色板中的颜色以获得最佳效果size(数字,通常为 2–99;应用默认值为 17){ "insert": "重要", "attributes": { "bold": true, "color": "#ff0000", "size": 20 } }可用颜色配色板(共 36 种颜色):
始终存储 浅色模式下的十六进制值 — 应用会在深色模式下自动映射。
| 名称 | 浅色模式十六进制 |
|---|---|
| 黑色 | #000000 |
| 炭灰色 | #545454 |
| 深灰 | #616161 |
| 温暖青灰 | #455a64 |
| 深红 | #b71c1c |
| 深红色 | #c0392b |
| 砖红 | #bf360c |
| 深琥珀色 | #a04000 |
| 奶油黄 | #9a6e00 |
| 深橄榄绿 | #558b2f |
| 森林绿 | #2e7d32 |
| 深金色 | #8b6914 |
| 深青绿 | #00695c |
| 深青色 | #00838f |
| 皇家蓝 | #1565c0 |
| 蓝色 | #007aff |
| 靛蓝 | #5856d6 |
| 深紫色 | #6a1b9a |
| 洋红 | #e91e63 |
| 粉红 | #ff2d55 |
| 李子色 | #880e4f |
| 梅紫 | #6a0572 |
| 深紫罗兰 | #4a148c |
| 棕色 | #8d6e63 |
| 红色 | #ff3b30 |
| 深玫瑰红 | #ad1457 |
| 陶土色 | #8b3a1f |
| 海绿色 | #007a63 |
| 深夜蓝 | #1a237e |
| 深鼠尾草绿 | #2e5902 |
| 橙赭色 | #7a5c00 |
| 钢灰色 | #37474f |
| 葡萄酒红 | #8b0000 |
| 枫木色 | #6d2f1f |
| 深海蓝 | #005b72 |
| 深咖啡色 | #4e342e |
块/行样式(附加在换行操作符后):
align: "left"(左对齐)、"center"(居中)、"right"(右对齐)indent: 整数,表示缩进量list: "ordered"(有序列表)、"bullet"(项目符号)、"checked"(已勾选)、"unchecked"(未勾选)code-block: true(启用代码块)blockquote: true(启用引用块){ "insert": "一个项目符号项" },
{ "insert": "\n", "attributes": { "list": "bullet" } }图片嵌入:
{ "insert": { "image": "{\"src\":\"my_photo.jpg\",\"w\":1920,\"h\":1080}" } }若尺寸未知:
{ "insert": { "image": "my_photo.jpg" } }拼贴图嵌入(多图布局):
{
"insert": {
"collage": "{\"layout\":\"twoHorizontal\",\"images\":[\"img1.jpg\",\"img2.jpg\"]}"
}
}可用的拼贴布局:
twoHorizontal(2张图横向排列)bigLeft2Right(3张图,左侧大图,右侧小图)bigRight2Left(3张图,右侧大图,左侧小图)threeRow(3张图纵向排列)bigLeft2RectRight(3张图,左侧大图,右侧矩形小图)bigTop2Bottom(3张图,顶部大图,底部小图)bigLeftTopRect2Bottom(4张图,左上角大图,右下角矩形区域)grid2x2(4张图,2×2网格布局)分隔线嵌入:
{ "insert": { "divider": "split" } }richContent 字段必须是 JSON 字符串(而非对象):
"[{\"insert\":\"我的标题\\n\",\"attributes\":{\"bold\":true,\"size\":24}},{\"insert\":\"今天是个好日子。\\n\"},{\"insert\":{\"image\":\"photo.jpg\"}},{\"insert\":\"\\n\"}]"content 是用于主页预览和搜索的纯文本摘要。请移除所有格式化内容,仅保留文字内容。不要在此处放入 JSON 或 Markdown。
stickerData 是一个 JSON 字符串(非对象),包含一组贴纸叠加对象。贴纸会浮在笔记页面上方,且不属于 richContent 内容。
每个贴纸对象结构如下:
{
"id": "唯一十六进制标识符",
"assetPath": "assets/stickers/bunny.svg",
"dx": 150.0,
"dy": 200.0,
"normalizedDx": 0.39,
"normalizedDy": 0.25,
"scale": 1.0,
"rotation": 0.0
}字段规则:
id:唯一字符串,格式为 <十六进制时间戳>_<六位十六进制随机码>assetPath:必须与以下打包贴纸列表中的路径完全匹配dx, dy:相对于笔记画布左上角的像素偏移量(典型画布宽度约 390px)normalizedDx, normalizedDy:比例位置(dx 范围 0.0–1.0;dy 可超过 1.0,适用于长内容)scale:缩放比例,范围 0.3 至 4.0(1.0 表示默认 70px 基础大小)rotation:旋转角度,单位为弧度stickerData 字段示例值:
"[{\"id\":\"18f0c9d2_a1b2c3\",\"assetPath\":\"assets/stickers/bunny.svg\",\"dx\":150.0,\"dy\":200.0,\"normalizedDx\":0.39,\"normalizedDy\":0.25,\"scale\":1.0,\"rotation\":0.0}]"可爱风格:
assets/stickers/backpack.svg assets/stickers/bird.svg
assets/stickers/book.svg assets/stickers/bunny.svg
assets/stickers/burger.svg assets/stickers/cake_slice.svg
assets/stickers/cat.svg assets/stickers/cheese.svg
assets/stickers/chicken.svg assets/stickers/clapboard.svg
assets/stickers/crown.svg assets/stickers/flower_2.svg
assets/stickers/frog.svg assets/stickers/garland.svg
assets/stickers/gramophone.svg assets/stickers/hat.svg
assets/stickers/heart_2.svg assets/stickers/kiwi.svg
assets/stickers/kitten.svg assets/stickers/little_girl.svg
assets/stickers/little_girl_2.svg assets/stickers/meals.svg
assets/stickers/muffin.svg assets/stickers/piggy_bank.svg
assets/stickers/pizza.svg assets/stickers/plant.svg
assets/stickers/pop_corn.svg assets/stickers/rabbit.svg
assets/stickers/rabbit_2.svg assets/stickers/saturn.svg
assets/stickers/shooting_star.svg assets/stickers/skirt.svg
assets/stickers/soda_can.svg assets/stickers/strawberry.svg
assets/stickers/symbol.svg assets/stickers/tea_pot.svg
assets/stickers/ufo.svg assets/stickers/wallet.svg
assets/stickers/watermelon.svg assets/stickers/watermelon_2.svg动物类: assets/stickers/animals/001-crocodile.svg 至 040-hippopotamus.svg(共 40 个)
自然类: assets/stickers/nature/001-sunflower.svg 至 024-tree.svg(共 24 个)
角色类: assets/stickers/characters/girl_001-girl.svg 至 girl_020-girl.svg,hippie_001-hippie.svg 至 hippie_020-dj.svg
食物类: assets/stickers/food/misc_001-meat.svg 至 misc_020-dolphin.svg,k760_001-cat.svg 至 k760_020-ice_cream.svg,k791_001-cat.svg 至 k791_020-book.svg
萌趣生活类: assets/stickers/cute_life/k678_001-badge.svg 至 k678_020-vinyl_record.svg,k612_001-teddy_bear.svg 至 k612_020-yogurt.svg,k155_001-egg_and_bacon.svg 至 k155_020-rainbow.svg
日常用品类: assets/stickers/everyday/k448_001-cake.svg 至 k448_020-violin.svg,k450_001-backpack.svg 至 k450_020-turtle.svg
如果笔记中包含图片,请先上传每一张:
curl -s -X POST "https://api.opennote.cc/api/v1/images" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN" \
-F "image=@/path/to/photo.jpg"响应结果:
{ "imageName": "photo.jpg", "sizeInMB": 0.42 }Skill: Write OpenNote
Version: 1.0.0
Chunk: 3/3
使用返回的 imageName 填入 imageList、richContent 中的图片嵌入,以及可选的 diaryCoverImageName。
图片限制:
curl -s -X POST "https://api.opennote.cc/api/v1/diaries" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"fileName": "<timestamp>.json",
"time": <timestamp>,
"content": "<plain text summary>",
"richContent": "<JSON string of Quill Delta ops>",
"stickerData": "<JSON string of sticker array or null>",
"diaryCoverImageName": null,
"category": <categoryID>,
"title": "<optional title>",
"imageList": [],
"isDeleted": false,
"lastModified": <timestamp>,
"hideTitle": false
}'如果 API 返回 409 ALREADY_EXISTS,请改用 PUT 请求重试:
curl -s -X PUT "https://api.opennote.cc/api/v1/diaries/<fileName>" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "content": "...", "richContent": "...", "lastModified": <now> }'创建或更新成功后,将一条记录追加至 .opennote/opennote-history.json 文件中。
先读取现有文件(若不存在则初始化为空数组 []),然后追加新条目并写回。
每条历史记录格式如下:
{
"fileName": "1741111111111.json",
"action": "created",
"timestamp": 1741111111111,
"title": "Morning Walk",
"contentPreview": "Woke up early and went for a walk in the park...",
"categoryID": 2,
"categoryName": "Personal",
"hasStickers": true,
"hasImages": false,
"imageList": []
}历史记录规则:
action:值为 "created" 或 "updated"contentPreview:取 content 的前 150 个字符categoryName:从缓存的标签列表中查找,若 category 为 0 则显示 "No Label"hasStickers:当 stickerData 非空时为 truehasImages:当 imageList 非空时为 trueaction: "updated" 的记录(不覆盖旧记录)告知用户:
当用户请求读取、搜索或以现有笔记作为模板时,请使用读取接口(需在 token 中包含 diaries:read 权限)。
注意: 创建 token 时,
diaries:read权限可能尚未可用。若在调用读取接口时收到403 INSUFFICIENT_SCOPE错误,说明 token 缺少该权限。此时仍可正常写入笔记和获取标签信息。
curl -s "https://api.opennote.cc/api/v1/diaries?category=CATEGORY_ID&search=KEYWORD&limit=50&offset=0" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN"查询参数(全部可选):
category — 按 categoryID(整数)筛选search — 在内容和标题中进行关键词匹配(部分匹配)limit — 每页结果数量,范围 1–200,默认 50offset — 分页偏移量,默认 0响应示例:
{
"diaries": [ { "fileName": "...", "time": ..., "content": "...", "richContent": "...", ... } ],
"total": 42,
"limit": 50,
"offset": 0
}curl -s "https://api.opennote.cc/api/v1/diaries/FILENAME.json" \
-H "Authorization: Bearer $OPENNOTE_API_TOKEN"当用户询问之前写过的笔记(例如:“上次写了什么?”、“找一下关于 X 的笔记”),请读取 .opennote/opennote-history.json 文件。可通过以下方式匹配:
title(部分匹配)contentPreview(关键词搜索)categoryName(标签名称)timestamp(时间范围)fileName(精确匹配)报告所有匹配项的标题、内容预览、日期和标签信息。
发送前请进行以下验证:
richContent 必须是 JSON null,或能解析为数组的 JSON 字符串,且数组中每个元素必须包含 insert 键。richContent 中放入纯文本、Markdown、"NULL"、"null" 或空字符串 ""。content 必须为纯文本(用于预览和搜索),不能是 JSON 格式。imageList 必须仅包含文件名,并且必须包含 richContent 中所有嵌入图片的文件名。time 和 lastModified 使用 Unix 毫秒时间戳。stickerData 必须省略、为 null,或为可解析为有效贴纸对象数组的 JSON 字符串。assetPath 必须与提供的贴纸列表中的路径完全一致。scale 值应在 0.3 至 4.0 之间。已收录 1 个 Skill