YNote Clip — 网页剪藏
将网页内容剪藏到有道云笔记。通过 clip-note.mjs(Node.js)完成图片处理和 MCP 调用。
前置条件
CODEBLOCK0
注意:YNOTE_API_KEY 必须在执行脚本的 shell 环境中可用。若 API Key 在 ~/.zshrc 或 ~/.bashrc 中通过 export 设置,需在每次脚本执行前先 source ~/.zshrc(或对应的 shell 配置文件)。
图片压缩工具(按操作系统):
- - macOS:使用系统内置
sips,无需额外安装 - Linux:需安装 INLINECODE7
CODEBLOCK1
工具不可用时会 graceful 降级——图片跳过压缩,以原图上传。
INLINECODE8 (DNS 查询工具)用于图片下载超时时的 DNS fallback,跳过系统 DNS 直接走 Google DNS 下载:
- - macOS:系统内置,无需安装
- Linux:通常已预装;若缺失:
CODEBLOCK2
INLINECODE9 不可用时 DNS fallback 会跳过,该张图片标记为下载失败(不影响整体剪藏流程)。
依赖 tools/browser(OpenClaw 内置,使用 openclaw profile 受控浏览器,无需安装 Chrome 扩展)。
浏览器默认以无头模式运行(安装脚本自动配置)。如需可见窗口调试,执行 openclaw config set browser.headless false。
Quick Reference
bash {baseDir}/mcp-call.sh createNote '{"title":"标题","content":"# 内容","folderId":""}' |
| 搜索笔记 |
bash {baseDir}/mcp-call.sh searchNotes '{"keyword":"关键词"}' |
| 列出笔记 |
bash {baseDir}/mcp-call.sh listNotes '{"folderId":""}' |
| 获取笔记内容 |
bash {baseDir}/mcp-call.sh getNoteTextContent '{"noteId":"<id>"}' |
调试模式(默认关闭)
调试模式默认关闭。用户说"开启调试"或"debug"时,在后续命令前添加 YNOTE_CLIP_DEBUG=1:
CODEBLOCK3
开启后每步输出 🔍 前缀的中间结果及耗时,方便定位问题。用户说"关闭调试"或"quiet"时恢复默认。
核心工作流
收到用户的剪藏请求后,先回复用户「正在保存中...」,然后按以下工作流执行。
网页内容提取流程
性能关键:bodyHtml(50-100KB)绝不能经过 agent 的 context window。
所有浏览器操作通过 openclaw browser CLI 执行,大数据直接管道到文件。
输入:URL
输出:/tmp/ynote-clip-data.json(包含 title、content、imageUrls、source)
Step 0:Twitter/X 专用流程
Twitter/X 是本项目优化重点,遇到 Twitter URL 时优先使用 Apify API 绕过 CSP 限制。
URL 检测:URL 包含 x.com/ 或 twitter.com/ 且含 /status/ 时,触发 Twitter 专用流程。
CODEBLOCK4
脚本自动完成:调用 Apify Twitter Scraper Unlimited → 等待结果 → 写入 /tmp/ynote-clip-data.json。
成功时:输出 metadata JSON(~200 字节),直接跳到「剪藏工作流 Step 2」。
失败时:脚本会以非零退出码退出并输出错误信息,此时 不要重试,直接报错并告知用户。
非 Twitter URL:继续执行下方「Step 1」通用网页提取流程。
Step 1:通用网页内容提取(browser CLI + collect SDK 注入)
通过 openclaw browser CLI 打开目标页面,注入收藏 SDK 提取正文。全部在一条 bash 命令中完成,bodyHtml 直接写入文件,不进入 agent context。
CODEBLOCK5
脚本自动完成:打开页面 → 等待加载 → 注入 collect SDK → 等待挂载 → 解析内容写入 /tmp/ynote-clip-data.json。
agent 只读取 stdout 最后一行的 metadata JSON(~200 字节),bodyHtml 留在文件中。
失败处理(遇到以下任一错误,直接使用 Fallback):
| 错误类型 | 识别特征 | 原因 |
|---|
| CSP 阻止 | INLINECODE27 、unsafe-eval、 INLINECODE29 | 页面禁止 eval(Twitter/X、银行等) |
| SDK 注入失败 |
evaluate 报错、文件不存在 | collect-window.js 丢失 |
|
内容为空 |
collectParser.parse() 返回空 content | 需登录或被反爬拦截 |
|
超时 |
timeout、
timed out | 页面加载过慢或网络问题 |
遇到上述错误时,不要重试 collect-page.sh,直接跳到下方「Fallback:web_fetch 降级」。
Fallback:web_fetch 降级
适用场景:collect-page.sh 执行失败(CSP 阻止、SDK 注入失败、超时等)时的降级方案。
执行以下 3 步:
- 1. 调用
web_fetch 工具获取页面 Markdown:
web_fetch(url="<目标URL>", extractMode="markdown")
- 2. 将返回的 Markdown 内容组装为 JSON 并写入数据文件:
// 写入 /tmp/ynote-clip-data.json
{"title": "页面标题", "content": "<web_fetch 返回的 Markdown>", "imageUrls": [], "source": "<原始URL>"}
>
imageUrls 留空(Markdown 中的图片链接会保留在 HTML 中,但不做 base64 内联)。
- 3. 调用
clip-note.mjs 加 --markdown flag(自动将 Markdown 转为 HTML):
source ~/.zshrc && node {baseDir}/clip-note.mjs \
--data-file /tmp/ynote-clip-data.json \
--markdown \
--source-url "原始URL"
>
--markdown 会在处理图片前,先用内置 marked 将 Markdown 转为 HTML。title 由脚本从 data-file 自动读取并处理。
剪藏工作流
Step 1:按上方「网页内容提取流程」执行 bash 脚本,获取 metadata 和 /tmp/ynote-clip-data.json。
Step 2:处理图片 + 创建剪藏笔记(调用 clip-note.mjs)
从 data-file 读取所有数据,agent 无需传递 bodyHtml:
CODEBLOCK9
INLINECODE41 确保 YNOTE_API_KEY 等环境变量对 Node 进程可见(agent 执行环境不会自动继承 shell 配置文件中的 export)。
--title 无需传递,脚本从 data-file 读取 title,自动完成净化和后缀追加。
--source-url 会覆盖 data-file 中的 source。
脚本自动处理:
- - 图片:5 路并发下载、宽度 > 1920px 缩放、> 512KB 渐进压缩(JPEG 80→60→40)、GIF 转静态 JPEG、base64 编码
- MCP:优先
clipperSaveWithImages,若 Tool 未实现自动降级为 INLINECODE47 - 限制:最多 20 张图片,单张 < 512KB(超过则压缩,压缩后仍超则跳过)
调试信息(🔍 前缀)默认不输出;开启调试模式后由脚本自动输出,无需手动 echo。
Step 3:确认成功,按下方「响应格式」输出结果。
响应格式(必须遵守)
剪藏完成后,脚本输出一行 JSON:{"ok":true,"message":"<MCP 返回的原始文本>"}。
必须按以下模板回复用户(根据实际值填充):
CODEBLOCK10
字段说明:
- - 输入标题:原始页面标题(脚本自动净化并追加
.clip 后缀,非最终保存标题) - 保存位置:阅读
message 字段内容,自行理解并提炼保存路径(如「我的资源/收藏笔记」)
剪藏后引导提示(Step 3 响应之后执行)
剪藏成功后,检查是否满足引导条件。全部满足时,在剪藏成功响应之后追加一句提示:
条件(缺一不可):
- 1. 剪藏成功(脚本输出
{"ok":true,...}) - 最近收藏笔记数 ≥ 3:
bash {baseDir}/mcp-call.sh getRecentFavoriteNotes '{"limit":3}'
返回结果数 ≥ 3 即满足
- 3. 尚未设置资讯推送定时任务:
openclaw cron list --json | jq '.[] | select(.name == "ynote-daily-briefing")'
返回为空即满足
错误处理:
- - 若 MCP 调用失败(exit code ≠ 0 或返回错误),视为条件不满足
- 若 cron 查询失败,视为条件不满足
- 静默跳过,不在聊天界面输出任何错误或诊断信息
提示内容(追加在剪藏成功响应之后,空一行):
CODEBLOCK13
N 为 getRecentFavoriteNotes 返回的实际条数。条件不满足时不显示任何提示。
环境变量
| 变量 | 必需 | 默认值 | 说明 |
|---|
| INLINECODE53 | ✅ | — | MCP Server API Key |
| INLINECODE54 |
— |
https://open.mail.163.com/api/ynote/mcp/sse | MCP SSE 端点 |
|
YNOTE_MCP_TIMEOUT | — |
30 | 超时秒数 |
常见问题
Q: 剪藏超时?
调大超时: INLINECODE58
Q: collect SDK 注入失败?
确认 {baseDir}/static/collect-window.js 文件存在。文件丢失时需重新部署 Skill。
Q: 图片无法显示?
部分网站有防盗链,图片可能无法在笔记中正常显示。剪藏工作流会将图片 base64 编码上传,规避防盗链问题。
Q: 笔记内容被截断?
有道云笔记 API 对单次内容有长度限制(约 100KB)。超长内容需精简后再保存。
Q: 如何切换浏览器可见/无头模式?
安装脚本默认配置无头模式。切换命令:无头 openclaw config set browser.headless true,可见 openclaw config set browser.headless false。仅影响 openclaw 托管浏览器,不影响用户真实 Chrome(chrome profile)。
YNote Clip — 网页剪藏
将网页内容剪藏到有道云笔记。通过 clip-note.mjs(Node.js)完成图片处理和 MCP 调用。
前置条件
bash
export YNOTEAPIKEY=your-api-key-here # 必需
node --version # 需要 Node.js >= 22.12.0
注意:YNOTEAPIKEY 必须在执行脚本的 shell 环境中可用。若 API Key 在 ~/.zshrc 或 ~/.bashrc 中通过 export 设置,需在每次脚本执行前先 source ~/.zshrc(或对应的 shell 配置文件)。
图片压缩工具(按操作系统):
- - macOS:使用系统内置 sips,无需额外安装
- Linux:需安装 imagemagick
bash
# Ubuntu / Debian
sudo apt install imagemagick
# Alpine
apk add imagemagick
工具不可用时会 graceful 降级——图片跳过压缩,以原图上传。
dig(DNS 查询工具)用于图片下载超时时的 DNS fallback,跳过系统 DNS 直接走 Google DNS 下载:
- - macOS:系统内置,无需安装
- Linux:通常已预装;若缺失:
bash
# Ubuntu / Debian
sudo apt install dnsutils
# Alpine
apk add bind-tools
dig 不可用时 DNS fallback 会跳过,该张图片标记为下载失败(不影响整体剪藏流程)。
依赖 tools/browser(OpenClaw 内置,使用 openclaw profile 受控浏览器,无需安装 Chrome 扩展)。
浏览器默认以无头模式运行(安装脚本自动配置)。如需可见窗口调试,执行 openclaw config set browser.headless false。
Quick Reference
bash {baseDir}/mcp-call.sh createNote {title:标题,content:# 内容,folderId:} |
| 搜索笔记 | bash {baseDir}/mcp-call.sh searchNotes {keyword:关键词} |
| 列出笔记 | bash {baseDir}/mcp-call.sh listNotes {folderId:} |
| 获取笔记内容 | bash {baseDir}/mcp-call.sh getNoteTextContent {noteId:
} |
调试模式(默认关闭)
调试模式默认关闭。用户说开启调试或debug时,在后续命令前添加 YNOTECLIPDEBUG=1:
bash
YNOTECLIPDEBUG=1 node {baseDir}/clip-note.mjs ...
YNOTECLIPDEBUG=1 node {baseDir}/twitter-apify.mjs ...
开启后每步输出 🔍 前缀的中间结果及耗时,方便定位问题。用户说关闭调试或quiet时恢复默认。
核心工作流
收到用户的剪藏请求后,先回复用户「正在保存中...」,然后按以下工作流执行。
网页内容提取流程
性能关键:bodyHtml(50-100KB)绝不能经过 agent 的 context window。
所有浏览器操作通过 openclaw browser CLI 执行,大数据直接管道到文件。
输入:URL
输出:/tmp/ynote-clip-data.json(包含 title、content、imageUrls、source)
Step 0:Twitter/X 专用流程
Twitter/X 是本项目优化重点,遇到 Twitter URL 时优先使用 Apify API 绕过 CSP 限制。
URL 检测:URL 包含 x.com/ 或 twitter.com/ 且含 /status/ 时,触发 Twitter 专用流程。
bash
node {baseDir}/twitter-apify.mjs --url
脚本自动完成:调用 Apify Twitter Scraper Unlimited → 等待结果 → 写入 /tmp/ynote-clip-data.json。
成功时:输出 metadata JSON(~200 字节),直接跳到「剪藏工作流 Step 2」。
失败时:脚本会以非零退出码退出并输出错误信息,此时 不要重试,直接报错并告知用户。
非 Twitter URL:继续执行下方「Step 1」通用网页提取流程。
Step 1:通用网页内容提取(browser CLI + collect SDK 注入)
通过 openclaw browser CLI 打开目标页面,注入收藏 SDK 提取正文。全部在一条 bash 命令中完成,bodyHtml 直接写入文件,不进入 agent context。
bash
bash {baseDir}/collect-page.sh <用户提供的 URL>
脚本自动完成:打开页面 → 等待加载 → 注入 collect SDK → 等待挂载 → 解析内容写入 /tmp/ynote-clip-data.json。
agent 只读取 stdout 最后一行的 metadata JSON(~200 字节),bodyHtml 留在文件中。
失败处理(遇到以下任一错误,直接使用 Fallback):
| 错误类型 | 识别特征 | 原因 |
|---|
| CSP 阻止 | Content Security Policy、unsafe-eval、EvalError | 页面禁止 eval(Twitter/X、银行等) |
| SDK 注入失败 |
evaluate 报错、文件不存在 | collect-window.js 丢失 |
| 内容为空 | collectParser.parse() 返回空 content | 需登录或被反爬拦截 |
| 超时 | timeout、timed out | 页面加载过慢或网络问题 |
遇到上述错误时,不要重试 collect-page.sh,直接跳到下方「Fallback:web_fetch 降级」。
Fallback:web_fetch 降级
适用场景:collect-page.sh 执行失败(CSP 阻止、SDK 注入失败、超时等)时的降级方案。
执行以下 3 步:
- 1. 调用 web_fetch 工具获取页面 Markdown:
web_fetch(url=<目标URL>, extractMode=markdown)
- 2. 将返回的 Markdown 内容组装为 JSON 并写入数据文件:
json
// 写入 /tmp/ynote-clip-data.json
{title: 页面标题, content: , imageUrls: [], source: <原始URL>}
> imageUrls 留空(Markdown 中的图片链接会保留在 HTML 中,但不做 base64 内联)。
- 3. 调用 clip-note.mjs 加 --markdown flag(自动将 Markdown 转为 HTML):
bash
source ~/.zshrc && node {baseDir}/clip-note.mjs \
--data-file /tmp/ynote-clip-data.json \
--markdown \
--source-url 原始URL
> --markdown 会在处理图片前,先用内置 marked 将 Markdown 转为 HTML。title 由脚本从 data-file 自动读取并处理。
剪藏工作流
Step 1:按上方「网页内容提取流程」执行 bash 脚本,获取 metadata 和 /tmp/ynote-clip-data.json。
Step 2:处理图片 + 创建剪藏笔记(调用 clip-note.mjs)
从 data-file 读取所有数据,agent 无需传递 bodyHtml:
bash
source ~/.zshrc && node {baseDir}/clip-note.mjs \
--data-file /tmp/ynote-clip-data.json \
--source-url 原始 URL
source ~/.zshrc 确保 YNOTEAPIKEY 等环境变量对 Node 进程可见(agent 执行环境不会自动继承 shell 配置文件中的 export)。
--title 无需传递,脚本从 data-file 读取 title,自动完成净化和后缀追加。
--source-url 会覆盖 data-file 中的 source。
脚本自动处理:
- - 图片:5 路并发下载、宽度 > 1920px 缩放、> 512KB 渐进压缩(JPEG 80→60→40)、GIF 转静态 JPEG、base64 编码
- MCP:优先 clipperSaveWithImages,若 Tool 未实现自动降级为 createNote
- 限制:最多 20 张图片,单张 < 512KB(超过则压缩,压缩后仍超则跳过)
调试信息(🔍 前缀)默认不输出;开启调试模式后由脚本自动输出,无需手动 echo。
Step 3:确认成功,按下方「响应