RSS 集成完全指南:将列表发布为订阅源,并自动抓取外部 Feed 生成书签)
KarakeepHoarderRSS 集成完全指南将列表发布为订阅源并自动抓取外部 Feed 生成书签【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder本篇技术指南聚焦开源项目 Karakeep原 Hoarder的 RSS 集成能力涵盖两大方向一是把任意列表List发布为带访问令牌保护的 RSS 订阅源供 RSS 阅读器或他人订阅二是监控外部 RSS/Atom 源每小时自动抓取新条目并生成书签、可选导入分类标签。读完本文你将掌握完整的界面操作步骤、URL 与令牌机制、字段映射规则以及背后的 Worker 调度、去重、配额检查等源码级实现原理。RSS 集成总览发布与消费的双向能力Karakeep 的 RSS 集成是双向的对应两条独立的技术链路发布Publishing将你创建的任意列表发布为 RSS Feed其他人或 RSS 阅读器可以通过一个带 token 的 URL 订阅你的书签集合消费Consuming在设置中添加外部 RSS/Atom 源后台 Worker 会定时抓取把新条目自动保存为书签适合跟踪博客、新闻站点等内容源。这两条链路在代码中分属不同的模块发布侧位于 API 层的 rss.ts 与 utils/rss.ts消费侧则由独立的 Feed Worker 驱动feedWorker.ts。将列表发布为 RSS 订阅源启用 RSS 的界面操作按官方文档的步骤进入任意列表后导航到你的某个列表点击列表设置三点菜单打开RSS Feed开关复制生成的 RSS Feed URL。从源码看开关背后对应列表在数据库中的rssToken字段。在 lists.ts 中token 的生成与读取由List.getOrCreateRSSKey/getRSSKey实现每次重新生成会写入新的 token 值从而让旧 URL 立即失效。Feed URL 的结构与参数生成的 Feed URL 形如https://你的实例地址/v1/rss/lists/listId?token访问令牌发布端点定义在 rss.ts路由为GET /lists/:listId支持两个查询参数参数类型说明tokenstring可选访问令牌。列表未公开时必须提供且必须与数据库中的rssToken完全一致limitnumber可选返回条数范围1到MAX_NUM_BOOKMARKS_PER_PAGE默认20按创建时间倒序order: desc返回响应头为Content-Type: application/rssxml返回标准的 RSS 2.0 XML。Feed 的标题会自动带上列表图标与名称例如Bookmarks from 我的收藏feedUrl指向 API 端点siteUrl指向 Web 端的列表页面/dashboard/lists/listId。RSS 中发布的内容与字段映射文档明确了 Feed 中包含的内容类型其具体映射逻辑在 utils/rss.ts 中实现书签内容是否包含RSS 字段映射链接Link✅url取书签 URLauthor取页面作者description取书签描述title取书签标题资产Asset✅url指向资产的查看地址由publicUrl getAssetUrl(assetId)拼接用于查看 PDF、图片等上传文件标签Tags✅作为 RSS 的category分类元素导出日期✅书签创建时间createdAt作为pubDate发布日期纯文本笔记Note❌不包含——笔记没有关联 URL无法作为链接条目导出每个条目的guid使用书签 ID确保条目在阅读器中的唯一性与稳定更新。同时注意一个安全细节在生成条目之前代码会过滤掉javascript:、data:等不安全协议的历史链接通过isAllowedBookmarkUrl校验防止阅读器跟踪恶意 URL。安全模型令牌、重新生成与即时失效唯一令牌访问每个 Feed 需要唯一的 token 才能访问对应数据库中的rssToken字段随时重新生成重新生成 token 会覆盖旧值旧 URL 立即失效关闭即撤销禁用列表的 RSS 开关后rssToken不再有效访问即被拒绝。在 lists.ts 的getPublicList查询中可以印证访问控制逻辑列表可被访问的条件是「列表本身标记为公开public true」或「传入的 token 与rssToken相等」。也就是说只要列表启用了公开访问或持有有效 token就能读取内容。订阅并自动抓取外部 RSS 源添加 Feed 的界面步骤与字段文档中的操作路径为设置Settings→ RSS Feeds → Add Feed需要填写的字段如下NameFeed 的友好名称URLRSS/Atom 源的地址Enabled是否启用该 FeedImport Tags是否把 RSS 分类categories作为标签附加到生成的书签上。这些字段与 feeds.ts 中的 zod 校验约束一一对应底层约束值得注意字段类型校验约束namestring必填长度1–100urlstring必填必须是合法 URL最长2000字符enabledboolean是否启用importTagsboolean默认false仅新建时可设置每小时自动检查的调度机制文档说明 Karakeep每隔一小时检查启用的 Feed。源码中的实现比「整点扫描」更精细在 feedWorker.ts 中一个 cron 表达式为0 * * * *的调度器在每小时的第 0 分钟运行它先查询所有enabled true的 Feed然后通过一个基于 Feed ID 哈希的getFeedMinuteOffset函数把每个 Feed 映射到当前小时的某个分钟偏移0–59再以对应延迟将抓取任务入队。这样做的好处是把大量 Feed 的抓取均匀分散在一小时内的各个时间点避免整点并发风暴。每个任务还带有一个idempotencyKey格式为feedId-小时窗口保证同一小时内同一 Feed 不会被重复调度。新条目去重与书签创建流程在 feedWorker.ts 的run函数中抓取流程包含完整的状态机配额预检通过QuotaService.canCreateBookmark检查用户是否还有书签配额配额不足时直接跳过本轮抓取返回success不算失败网络抓取使用fetchWithProxy请求 Feed URL携带 5 秒超时、User-Agent: Karakeep-RSS/1.0与 XML 相关的 Accept 头响应校验HTTP 状态必须为 200且Content-Type必须包含xml否则记录failure并等待下一轮解析条目通过parseFeedItems基于rss-parserfeedParser.ts把 XML 解析为条目列表每个条目的guid按guid ?? id ?? link的优先级推导去重查询rssFeedImportsTable中该 Feed 已导入的entryId只保留既无guid重复、又具备link与guid的新条目批量创建通过模拟用户身份的 tRPC 客户端buildImpersonatingTRPCClient调用bookmarks.createBookmark类型固定为 LINKsource标记为rss便于溯源标签导入若启用了importTags且条目带有 categories则通过bookmarks.updateTags把每个分类作为标签附加到对应书签记录导入映射把entryId ↔ bookmarkId的映射写入rssFeedImportsTableonConflictDoNothing幂等作为后续去重的依据。抓取完成后Feed 记录会更新lastSuccessfulFetchAt时间戳任务结果success/failure会写入lastFetchedStatus与lastFetchedAt——这正是设置页面中展示 Feed 健康状态的字段来源。手动立即抓取除了每小时自动调度还可以手动触发某个 Feed 立即抓取。REST 端点POST /feeds/:feedId/fetchfeeds.ts以及 tRPC 的feeds.fetchNowrouters/feeds.ts都会把该 Feed 的抓取任务直接投入队列无需等待下一个小时窗口。面向开发者的 API 与数据模型一览REST 端点Hono 实现发布侧与消费侧的管理接口均定义在 packages/api/routes 下方法路径说明GET/v1/rss/lists/:listId获取列表的 RSS Feed公开端点无需登录靠 token 鉴权GET/feeds列出当前用户的全部 FeedPOST/feeds新建 FeedGET/feeds/:feedId获取单个 Feed 详情PATCH/feeds/:feedId更新 Feed名称、URL、启用状态等DELETE/feeds/:feedId删除 FeedPOST/feeds/:feedId/fetch手动触发抓取tRPC 路由器与所有权隔离管理类操作同样以 tRPC 形式暴露feedsAppRouterrouters/feeds.ts提供create / update / get / list / delete / fetchNow六个过程统一走createScopedAuthedProcedure(feeds)鉴权。其中update / get / delete / fetchNow通过ensureFeedOwnership中间件先加载 Feed 并校验归属越权访问会抛出User is not allowed to access resource错误。数据模型rssFeedsTable存储用户订阅的外部 Feed包含id、userId、name、url、enabled、importTags、lastFetchedStatus、lastFetchedAt、lastSuccessfulFetchAt等字段见 schema.ts 中rssFeedsTable定义rssFeedImportsTable记录每个 Feed 已导入的条目entryId与生成书签bookmarkId的映射是去重机制的核心。测试覆盖与边界限制feeds.test.ts 提供了完整的路由级测试可以佐证以下行为创建/更新/列表/删除的常规 CRUD 均通过测试用例覆盖Feed 数量上限为 1000 个创建第 1001 个 Feed 会抛出Maximum number of RSS feeds (1000) reached跨用户隔离用户 A 无法删除或更新用户 B 的 Feed列表接口也只返回自己的 Feed删除不存在的 Feed 或所有权检查后行消失会返回Feed not found/NOT_FOUND。适用场景与注意事项推荐场景把公开列表转成订阅源分享给团队或读者把博客、技术媒体、更新公告等 RSS/Atom 源接入 Karakeep实现自动收藏归档。注意事项RSS 发布依赖rssToken分享 URL 时务必完整携带?token...参数token 泄露后应立即在列表设置中重新生成纯文本笔记不会出现在发布的 RSS 中如需对外分享笔记请使用列表的公开分享链接抓取频率以小时为单位且分散在一小时内的不同分钟对时效性要求极高的场景需手动触发fetch抓取器要求响应Content-Type含xml某些非标准实现的源可能因响应头问题被判定为失败Feed 生成的书签会占用用户书签配额配额不足时抓取会被跳过。掌握以上双向链路后你既可以把 Karakeep 当作一个「个人书签的 RSS 输出站」也可以把它变成「外部内容的自动采集器」两种能力都可在 [设置 → RSS Feeds] 与列表设置中零代码完成。【免费下载链接】hoarderA self-hostable bookmark-everything app (links, notes and images) with AI-based automatic tagging and full text search项目地址: https://gitcode.com/GitHub_Trending/ho/hoarder创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考