后端与接口
需要读写或整理 Raindrop.io 书签时:用…
当你要通过脚本或命令行批量管理 Raindrop.io 账号中的书签、收藏夹、标签、高亮和备份时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
需要读写或整理 Raindrop.io 特定
解决思路
- 按固定顺序解析 token:先读环境变量 `RAINDROP_TOKEN`;再看对话上下文里用户是否已提供 token;两者都没有就用 AskUserQuestion 向用户索要。
- 用 `[ -n "$RAINDROP_TOKEN" ] && echo "Token available" || echo "Token not set"` 检查环境变量中是否存在 token。
- 个人使用或开发场景:到 https://app.raindrop.io/settings/integrations 打开自己的 app,复制 Test token(test token 不会过期)。
- 所有请求都带 Bearer 头:`curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/ENDPOINT"`;POST/PUT 再加 `-X POST`、`-H "Content-Type: application/json"` 和 `-d '{"key": "value"}'`。
- 用 `GET /user` 验证 token:`curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/user" | jq '.user.fullName'`。
- 遵守基础约定:Base URL 为 `https://api.raindrop.io/rest/v1/`,请求/响应体均为 JSON,时间戳用 ISO 8601,限流为每认证用户每分钟 120 次请求,支持浏览器 CORS。
- 执行任何破坏性操作(DELETE、批量更新、移入回收站)前,必须用 AskUserQuestion 请用户确认;一组逻辑相关的操作只需一次确认。破坏性操作含删除 raindrop/collection/tag、批量更新或移动 raindrop、合并或移除标签、移除共享 collection 的协作者、清空回收站;只读 GET 无需确认。
- 单个 raindrop 操作端点:GET `/raindrop/{id}`、POST `/raindrop`、PUT `/raindrop/{id}`、DELETE `/raindrop/{id}`、PUT `/raindrop/file`(上传文件)、PUT `/raindrop/{id}/cover`(上传封面)、GET `/raindrop/{id}/cache`(取永久副本)、POST `/raindrop/suggest`(新 URL)、GET `/raindrop/{id}/suggest`(已有 URL)。
- 创建/更新 raindrop 时可用字段:`link`(创建必填)、`title`、`excerpt`、`note`(支持 Markdown)、`tags`(字符串数组)、`collection`(`{"$id": collectionId}`)、`type`(`link`/`article`/`image`/`video`/`document`/`audio`)、`important`、`order`、`media`、`highlights`、`cover`(URL 或 `<screenshot>` 自动截图)、`pleaseParse`(传 `{}` 触发后台元数据解析)、`created`、`lastUpdate`、`reminder`。
- 记住删除语义:删除 raindrop 只是移入 Trash(collection ID `-99`),只有从 Trash 中删除才是永久删除。
- 多个 raindrop 操作端点:GET `/raindrops/{collectionId}`、POST `/raindrops`、PUT `/raindrops/{collectionId}`、DELETE `/raindrops/{collectionId}`、GET `/raindrops/{collectionId}/export.{format}`。
- collectionId 取值:`0` 全部 raindrop、`-1` Unsorted、`-99` Trash、任意正整数为具体 collection。
- GET `/raindrops/{collectionId}` 查询参数:`sort`(`-created` 默认、`created`、`score`、`-sort`、`title`、`-title`、`domain`、`-domain`)、`perpage`(最大 50)、`page`(从 0 开始)、`search`、`nested`(布尔,是否包含子 collection 的书签)。
- 批量更新(PUT 时带 `ids` 数组或 `search` 查询)支持的字段:`important`、`tags`(追加;传空数组清空全部)、`media`(追加;空数组清空)、`cover`(URL 或 `<screenshot>`)、`collection`(`{"$id": collectionId}` 用于移动)。
- 导出格式:`csv`、`html`、`zip`。
- Collection 端点:GET `/collections`(根)、GET `/collections/childrens`(子)、GET `/collection/{id}`、POST `/collection`、PUT `/collection/{id}`、PUT `/collection/{id}/cover`、DELETE `/collection/{id}`、DELETE `/collections`(批量删除)、PUT `/collections`(重排/展开全部)、PUT `/collections/merge`(合并)、PUT `/collections/clean`(移除空 collection)、DELETE `/collection/-99`(清空回收站)、GET `/user/stats`(系统 collection 计数)、GET `/collections/covers/{text}`(搜索封面/图标)、GET `/collections/covers`(精选封面)。
- Collection 字段:`title`、`view`(`list`/`simple`/`grid`/`masonry`)、`public`、`parent`(`{"$id": parentCollectionId}` 用于嵌套)、`sort`(排序位置)、`cover`(图片 URL 数组)、`expanded`、`color`。
- 注意系统 collection(不可删除):ID `-1` 为 Unsorted,ID `-99` 为 Trash。
- 访问级别 `access.level`:`1` 只读、`2` 协作者(可写)、`3` 协作者(可写+可管理)、`4` 所有者。
- Tag 端点:GET `/tags/{collectionId}`、PUT `/tags/{collectionId}`(重命名或合并)、DELETE `/tags/{collectionId}`(删除标签);collectionId 省略或用 `0` 表示所有 collection 的标签。
- 重命名标签:`curl -s -X PUT -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"replace": "new-name", "tags": ["old-name"]}' "https://api.raindrop.io/rest/v1/tags/0"`。
- 合并标签:同一端点,在 `tags` 数组里放多个标签,如 `-d '{"replace": "merged-name", "tags": ["tag1", "tag2", "tag3"]}'` 请求 `/tags/0`。
- 删除标签:`curl -s -X DELETE -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"tags": ["tag-to-remove"]}' "https://api.raindrop.io/rest/v1/tags/0"`。
- Highlight 端点:GET `/highlights`(全部)、GET `/highlights/{collectionId}`、GET `/raindrop/{id}`(某 raindrop 的高亮);添加、更新、删除高亮都通过 PUT `/raindrop/{id}` 完成。
- 查过滤器:`curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/filters/{collectionId}" | jq '.'`,`0` 表示所有 collection;返回坏链、重复、收藏、未打标签、标签和内容类型的聚合计数;参数有 `tagsSort`(`-count` 默认或 `_id` 字母序)和 `search`。
- 用户端点:GET `/user` 获取当前用户,PUT `/user` 更新用户。
- 导入端点:GET `/import/url/parse?url={url}` 解析 URL、POST `/import/url/exists` 检查 URL 是否存在、POST `/import/file` 解析 HTML 书签文件。
- 备份端点:GET `/backups` 列出备份、GET `/backup/{id}.{format}` 下载备份、GET `/backup` 生成新备份;格式为 `html` 或 `csv`。
- 为访问其他用户的数据(非个人使用)走完整 OAuth2:先把用户引导到 `https://raindrop.io/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code`。
- 用授权码换 token:`curl -s -X POST "https://raindrop.io/oauth/access_token" -H "Content-Type: application/json" -d '{"code": "AUTH_CODE", "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET", "redirect_uri": "YOUR_REDIRECT_URI", "grant_type": "authorization_code"}' | jq '.'`,响应含 `access_token`、`refresh_token`、`expires_in`、`token_type`。
- access token 两周后过期,用 refresh token 刷新:POST 同一地址,body 为 `{"client_id": "...", "client_secret": "...", "refresh_token": "...", "grant_type": "refresh_token"}` 再 `jq '.'`。
- 按 HTTP 状态码判断结果:`200` 成功、`204` 成功无内容、`400` 请求错误、`401` 认证失败(检查 token)、`403` 权限不足、`404` 资源不存在、`429` 超出限流(120 req/min)、`5xx` 服务端错误。
- 带错误处理的调用模板:用 `curl -s -w "\n%{http_code}"` 同时捕获响应体与状态码,`tail -1` 取状态码、`sed '$d'` 取 body,若状态码在 200–299 之间则 `echo "$body" | jq '.'`,否则打印 `Error: HTTP $http_code` 和 body。
- 列出某 collection 的书签:`curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/raindrops/COLLECTION_ID?perpage=50" | jq '.items[] | {title, link}'`。
- 创建书签:`curl -s -X POST -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"link": "https://example.com", "title": "Example Site", "tags": ["reference", "example"], "collection": {"$id": COLLECTION_ID}, "pleaseParse": {}}' "https://api.raindrop.io/rest/v1/raindrop" | jq '.'`。
- 搜索书签:跨所有 collection 用 GET `/raindrops/0?search=YOUR_QUERY` 再 `jq '.items[] | {title, link}'`;按标签过滤用 `?search=%23tagname`(即 `#tagname`)。
- 移动书签到 collection:`curl -s -X PUT -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"collection": {"$id": TARGET_COLLECTION_ID}}' "https://api.raindrop.io/rest/v1/raindrop/RAINDROP_ID" | jq '.'`。
- 获取所有标签:`curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/tags/0" | jq '.items[] | {tag: ._id, count}'`。
- 创建 collection:`curl -s -X POST -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"title": "My Collection", "view": "list"}' "https://api.raindrop.io/rest/v1/collection" | jq '.'`。
- 列出所有 collection:根用 GET `/collections` 后 `jq '.items[] | {id: ._id, title}'`;子用 GET `/collections/childrens` 后 `jq '.items[] | {id: ._id, title, parent: .parent."$id"}'`。
- 翻页遍历全部书签:`page=0` 起循环,每次请求 `GET /raindrops/0?perpage=50&page=$page`,用 `jq '.items | length'` 取条数,条数小于 50 就 `break`,否则 `page=$((page + 1))`。
- 导出书签:CSV 用 `curl -s -H "Authorization: Bearer $RAINDROP_TOKEN" "https://api.raindrop.io/rest/v1/raindrops/0/export.csv" -o bookmarks.csv`;HTML 用 `.../export.html -o bookmarks.html`。
- 检查 URL 是否已保存:`curl -s -X POST -H "Authorization: Bearer $RAINDROP_TOKEN" -H "Content-Type: application/json" -d '{"urls": ["https://example.com"]}' "https://api.raindrop.io/rest/v1/import/url/exists" | jq '.'`。
- 使用基于页码的分页(不是 cursor):`page`(从 0 开始)、`perpage`(最大 50,highlights 默认 25);返回条数少于 `perpage` 即已到最后一页。
- 重建完整嵌套侧边栏需要三步:GET `/user` 拿到含排序的 `groups` 数组、GET `/collections` 拿根 collection、GET `/collections/childrens` 拿嵌套 collection;根排序持久化在 `groups[].collections`,子排序存在 collection 的 `sort` 字段。
- 按工作流推进:解析 token → 用 `GET /user` 验证认证 → 读操作直接执行 → 写操作先确认 → 用页码循环处理分页直到条数小于 perpage → 用 jq 解析并格式化响应。
适用边界 · 注意事项
- 没有 Raindrop.io 账号或有效 token 时无法使用,本技能只针对 Raindrop.io 的 REST API。
- 访问其他用户的数据时不能使用个人 test token,必须走完整 OAuth2 授权流程。
- 不要跳过破坏性操作的确认步骤,也不要超过每分钟 120 次请求的限流。