# @hyzyn/dsh-rss 中文 | [English](README.en.md) > DSH 的 RSS / 新闻聚合插件:订阅多个 RSS / Atom 源,每天自动汇总一篇「今日值得读」,并把结果注入 systemPrompt 让模型直接引用。 ## 特性 - **汇总结果注入 systemPrompt**:作为 `systemPrompt` section 注入,模型可直接引用当天条目,问「今天有什么值得读」即得内容。开关(`announceToAgent`)**热生效**——保存即出现 / 撤下,不用重启;注入段落**按条数收口**(最多列前 8 条,按 `digest.items` 原序、分类标题保留),其余条数在段尾指向当天的 digest 文件,避免每一轮请求都发一份超长列表。 - **定时抓取、按分类汇总**:按日生成;弹窗内可搜索、按分类筛、复制 Markdown。 - **订阅源在面板内维护**:内置渠道 + 自定义源,RSSHub 精选目录一键添加,支持 OPML 导入导出。 - **单源失败就地降级**:个别源挂掉只标注它自己,其余照常出;可选 AI 摘要失败时回落原文摘要并说明原因。 ## 刷新时的过渡层 「今日值得读」弹窗与设置卡刷新时,会出现与 dsh-docker「切目标过渡」同一套语言的提示:内容区顶部一条 **2px 不定长流光进度条**,一行**蓝色胶囊**(`⟳ 正在刷新订阅源 · 当前数据生成于 14:29`,完整解释在 `title`);进度条落在分类行下沿、胶囊骑线居中,**绝对定位、不推版**。只在**慢刷新**时出现(沿用已有的 180ms 消抖),毫秒级请求不会闪;数据落地时正文 **8px 上滑 + 淡入**,动效尊重 `prefers-reduced-motion`。 刷新期间正文仍按原行为压暗(`opacity:.55`),旧内容继续可读;stale-while-revalidate、骨架屏消抖、刷新后搜索框焦点/光标与列表滚动位置还原全部保留。弹窗的慢加载路径**刻意不重渲染整棵树**,所以过渡层是「只插两个绝对定位节点」而不是靠重渲染——这条路径漏了注入,浮层就永远不出现。 实现取舍(强调色 token 的坑、为什么必须绝对定位、6 条回归断言)见 [ROADMAP § 已完成](./ROADMAP.md#已完成落点--门槛)。 ## 功能 - 内置渠道库(阮一峰、少数派、Solidot、Hacker News、掘金、IT之家、36氪),在设置里勾选要展示的渠道即可;36氪官方 feed 被反爬拦截,内置地址为第三方 RSSHub 镜像; - 支持自定义渠道:填写自己的 RSS / Atom 地址,保存时真实抓取校验,抓不到内容的地址会提示且不保存;支持 **OPML 导入 / 导出**(从任意 RSS 阅读器或网站导入订阅)与**粘贴 URL 列表批量导入**(每行一个地址,或「名称, 地址」),自动跳过已订阅项,导入后可一键保存校验生效; - **订阅源目录(多来源)**:目录可来自多个来源——内置 [awesome-rsshub-routes](https://jackyst0.github.io/awesome-rsshub-routes/) 精选列表(官方 RSS 与 RSSHub 路由,快照 + 每 12 小时静默刷新)+ 任意数量自定义 OPML 目录(在设置卡片「订阅源目录」里添加 OPML 地址,名称 / URL 均可配置);所有来源的结果统一汇总、标注「来自 xxx」并按来源筛选,支持搜索 / 按分类筛选 / 勾选多选后批量添加(全选 / 清空 / 一键添加选中),实时显示「已订阅 / 已选」计数;单个目录源失败不影响整个目录读取; - 零依赖解析 RSS 2.0 与 Atom,按链接 / id / 标题去重,并按时间倒序生成 Markdown; - **可选 AI 摘要**:启用后调用宿主 LLM 为每条资讯生成一句话中文摘要,显示在 digest / 弹窗里并追加进 systemPrompt;摘要按条目缓存 30 天(最多 500 条,`ai-cache.json`),重复条目不会重复请求;单条失败(超时 / 非 stop 终止 / 空输出)只回落原文摘要,不影响其它条目,路由缺失时本次生成整体跳过并在 digest 中记录原因; - 默认每天 `08:00` 自动生成当天 digest;插件启动时若当天 digest 不存在也会自动补生成; - 把当天 digest 注入 `systemPrompt`,模型在用户问“今日值得读”时可以直接引用; - 提供 Web GUI 卡片「RSS / 新闻聚合」:维护内置渠道开关 / 自定义渠道 / 新闻分类 / 聚合设置,保存后自动刷新当天 digest;自定义渠道支持按名称 / URL 筛选与计数,并对重复 URL 给出内联警告;卡片顶部直接预览今日 digest(条数 / 源数 / 生成时间 / 失败告警),可一键查看列表、刷新、复制 Markdown; - 界面采用「分区块更新」渲染:输入、目录搜索、增删渠道只重建受影响区块,焦点 / 光标 / 滚动不丢失;未保存修改有角标提示; - 在侧边栏「新建会话」下方(任务看板 / SSH 附近)提供「今日值得读」快捷入口,点击弹窗直接查看新闻;弹窗支持按标题 / 摘要 / 来源搜索、按分类筛选、显示「可见 / 总数」计数、复制 Markdown,支持 Esc 关闭与焦点圈定; - digest 按「分类」分组展示(无分类归入「未分类」),条目标注来源与日期;每个来源的「查看更多」直达其官网; - 在 UI 的「设置」页维护内置渠道开关、自定义渠道(RSS/Atom 地址、分类、条数限制)和新闻分类;渠道的分类从「新闻分类」列表里选择,保存时自动把使用中的分类合并进列表; - 生成的 Markdown 保存在 `~/.dsh/rss-digest/YYYY-MM-DD.md`,同时写入 `latest.json` 便于外部读取。 ## 界面截图 「RSS / 新闻聚合」卡片(内置渠道勾选 + 自定义渠道 + 新闻分类): ![RSS 设置卡片](https://cdn.jsdelivr.net/gh/hyzyn/dsh-plugin-kit@main/docs/dsh-plugin-kit-rss-setting.png) 设置面在宿主里的位置随 DSH 版本变,但**始终是同一份表单**——各代际的落点与四条注册契约的唯一归宿在 [conventions.md § 客户端设置面](../../docs/conventions.md#客户端设置面内联优先)。 侧边栏「今日值得读」弹窗(按分类分组、来源带「查看更多」直达官网、底部可手动刷新): ![今日值得读弹窗](https://cdn.jsdelivr.net/gh/hyzyn/dsh-plugin-kit@main/docs/dsh-plugin-kit-rss-view.png) 向模型询问当天新闻时,直接引用当天 digest(无需打开弹窗): ![查询今日新闻](https://cdn.jsdelivr.net/gh/hyzyn/dsh-plugin-kit@main/docs/dsh-plugin-kit-rss-query-news.png) ## 配置示例 在 DSH 的插件配置中传入 `Config`: ```ts { sources: [ { name: '阮一峰的网络日志', url: 'https://www.ruanyifeng.com/blog/atom.xml', category: '技术' }, { name: '少数派', url: 'https://sspai.com/feed', category: '效率' }, ], maxItemsPerSource: 5, maxTotalItems: 30, dailyTime: '08:00', digestDir: '~/.dsh/rss-digest', } ``` > 不传 `sources` 时默认启用全部内置渠道;传入 `sources` 则以内置渠道全部关闭、只使用该列表。 常用配置项: | 字段 | 说明 | 默认 | | --- | --- | --- | | `enabled` | 是否启用插件 | `true` | | `announceToAgent` | 是否把 digest 注入 systemPrompt(**热生效**:保存即出现 / 撤下,不用重启) | `true` | | `includeCatalog` | 是否提供订阅源目录(/api/dsh-rss/catalog) | `true` | | `sources` | 自定义订阅源列表;传入后替代全部内置渠道 | 内置 7 个渠道 | | `maxItemsPerSource` | 每个源最多取多少条 | `5` | | `maxTotalItems` | 每天最多汇总多少条 | `30` | | `dailyTime` | 每天自动生成时间(HH:mm) | `08:00` | | `autoGenerateOnMount` | 启动时若当天 digest 不存在是否自动生成 | `true` | | `digestDir` | 输出目录 | `~/.dsh/rss-digest` | | `requestTimeoutMs` | 单次请求超时 | `10000` | ## AI 摘要(可选) AI 摘要默认关闭,配置只走可编辑 store `~/.dsh/rss.json` 的 `ai` 字段(设置卡片「AI 摘要」区块可改,不新增 Config 字段): ```json { "ai": { "enabled": true, "provider": "deepseek", "model": "deepseek-chat", "maxItems": 20, "concurrency": 3, "timeoutMs": 20000 } } ``` | 字段 | 说明 | 默认 | | --- | --- | --- | | `enabled` | 是否启用 AI 摘要 | `false` | | `provider` / `model` | 模型路由,**必须成对填写**;都留空则跟随宿主默认模型(`agentDefaultModel` / settings 的 `agent-default-model`;都取不到则本次生成跳过 AI 摘要) | 留空 | | `maxItems` | 单次 digest 最多摘要条数(列表前 N 条),夹紧 1..50 | `20` | | `concurrency` | 并发请求数,夹紧 1..6 | `3` | | `timeoutMs` | 单条请求超时毫秒数,夹紧 5000..60000 | `20000` | 只填 `provider` / `model` 之一时整段 `ai` 配置会被忽略并在保存响应里给出告警。 两个容易踩的点(都是真机上实测出来的): - **`maxTokens` 写死在插件里(当前 4096),推理模型要留足推理预算**:推理 token 与最终答案 **共享**这个上限,太小会让模型还没写出正文就把预算耗在推理上,finish 变成 `max-tokens`、 该条摘要判失败。实测(`commandcode/deepseek/deepseek-v4.1-flash`,20 条):200 → 7 条成功、 1024 → 12 条、4096 → **20 条全成功**(整轮 48s,单条约 7s,仍在 `timeoutMs` 内)。换更重的 推理模型若再撞上限,失败原因里会直接写出当前 `maxTokens` 值。 - **失败原因会带出来**:部分失败时 `aiSummary.failures` 给出原因分布(最多 3 类,含次数), Markdown 的「抓取失败」小节也会写上去(例:`原因:终止原因 max-tokens(…)×8`)。 早先只有一句「N 条失败」,既分不清超时 / 限流 / provider 报错,也无从判断是不是插件的问题。摘要结果写入 digest 目录的 `ai-cache.json`(`{ version: 1, entries: { : { text, model, at } } }`),命中且未过期(30 天)直接复用;超出 500 条按写入时间淘汰最旧。 ## 开发 ```bash pnpm --filter @hyzyn/dsh-rss build pnpm --filter @hyzyn/dsh-rss typecheck ``` ## 安装到 DSH ```bash dsh plugin --profile web add link:$(pwd) ``` 或从仓库根目录: ```bash dsh plugin --profile web add link:$(pwd)/packages/rss ``` ## 文件 | 文件 | 说明 | | --- | --- | | `package.json` | `dsh.bundle.patch` 指向 cordis.patch.yml;`main` / `exports["."]` 指向 lib/index.js | | `cordis.patch.yml` | bundle 补丁:`insert: { id: rss-digest, name: '@hyzyn/dsh-rss' }` 把本插件行插入 profile 阵容 | | `src/index.ts` | 插件宿主半体:RSS/Atom 解析、抓取、digest 生成、AI 摘要、定时调度、HTTP API、systemPrompt 注入 | | `client.js` | 浏览器半体:「RSS / 新闻聚合」卡片 | | `test/ai-summary.test.ts` | AI 摘要的回归测试(消息构造 / 清洗、缓存 TTL·LRU、路由解析、store 白名单、渲染、LLM 终止分支、生成降级路径) | | `tsconfig.json` | 继承根 tsconfig.base.json,tsc 产出 lib/ |