Windows 桌面 AI 新闻 RSS 阅读器。默认订阅 橘鸦AI早报,支持多订阅源、可自定义主题与布局、Mini 挂件模式与插件扩展。
- 多订阅源:浏览器式标签页,一源一页;支持添加 / 删除 / 启停
- 标签栏:Chrome 式标签页——可拖动排序(全部标签自由重排)、等宽弹性宽度(少量标签铺满、溢出横向滚动)、数量上限(20)与超限提示;标签会话重启自动恢复
- 三种布局预设:紧凑列表、卡片网格(1–4 列可调)、杂志风;卡片字段(封面 / 摘要 / 时间 / 来源)可独立开关
- 应用内阅读:渲染 RSS
content:encoded全文(DOMPurify 消毒),图片懒加载;点击行为可在设置中切换为浏览器打开 - 橘鸦定制阅读系统:内置橘鸦AI早报源提供五套独立视觉风格(卡片主题式 / 千禧网页式 / 波普艺术式 / 90 年代报刊式 / 蒸汽梦核式)× 亮暗双变体;订阅页遵循「布局」的预设 / 列数 / 显示字段;可整体关闭回退通用样式;内置源不可删除、不可停用
- 主题系统:内置 Windows-Light、Windows-Dark、Claude-Design、Juya-Daily 四套主题;主题编辑器支持取色、字体、字号、圆角实时预览并另存为自定义主题
- Mini 模式:无边框置顶小窗,整体可拖动,日期行可展开——橘鸦源展示简报、其他源展示限长摘要,「查看更多」回正常模式阅读(不开外链),一键切回
- 历史记录:已读 / 收藏 / 阅读时间持久化,保留天数可配
- 自动刷新:启动拉取 + 定时刷新(间隔可配)+ 手动刷新
- 插件机制:
plugins/目录加载三类注册点 —— FeedProvider(订阅源抓取)与 Theme(主题)完整可用,CardRenderer 在 v1 仅登记元数据;契约、限制与排障见 docs/PLUGIN_API.md
| 领域 | 技术 |
|---|---|
| 桌面运行时 | Electron 43 · electron-vite 5 |
| 前端界面 | React 19 · Tailwind CSS 3 |
| 语言与构建 | TypeScript 7 · Vite 7 |
| 状态与持久化 | Zustand 5 · electron-store 8 |
| RSS 与内容安全 | rss-parser 3 · DOMPurify 3 |
安装依赖:npm install
项目提供两个一键脚本,分别用于开发调试与发布构建。两者均内置本机托管 Node 路径与 ELECTRON_RUN_AS_NODE 清除,双击即可运行。
开发模式(热重载)。双击 start.bat,或手动:
npm run devstart.bat 会切换到托管 Node 22.22.2、清除 ELECTRON_RUN_AS_NODE、优雅关闭上一轮遗留的 dev 实例(仅限本项目路径下的 electron,不影响 VSCode 等其它 Electron 应用),随后启动 electron-vite dev。Ctrl+C 停止。
一键发布构建。双击 build.bat,或在项目根运行:
.\build.bat流程:
- 调用
build.ps1完成 electron-vite + electron-builder 生产构建 →build/OpiaRSSReader-<version>-portable.exe - 精简 locales(仅保留 en-US / zh-CN)、删除残留
default_app.asar与.pdb调试符号 - 组装完整可运行 app 到
release/,并生成 zip 与 portable exe
产出(位于 release/,已被 .gitignore 忽略):
| 文件 | 说明 |
|---|---|
OpiaRSSReader-v<version>-win32-x64\ |
完整 app 目录(exe + dll + 资源) |
OpiaRSSReader-v<version>-win32-x64.zip |
同名压缩包,供 GitHub Releases 上传 |
OpiaRSSReader-<version>-portable.exe |
单文件便携版 |
构建前若检测到 VSCode 正在运行,
build.bat会提示先关闭——VSCode 的 AI 扩展会扫描并锁定build/下的 asar 文件,导致 electron-builder 报 EBUSY。
build.ps1 是 build.bat 的构建核心,也可单独运行做快速验证。加 -Run 会在构建后启动 build/win-unpacked/ 里的实际 exe(非 portable SFX,以便捕获 stdout),并 tail 日志直到出现 initial refresh 标记:
powershell -File build.ps1 # 仅构建 portable exe 到 build/
powershell -File build.ps1 -Run # 构建并启动,tail 启动日志本机环境注意:若环境变量存在
ELECTRON_RUN_AS_NODE=1,Electron 会以纯 Node 模式运行而无法开窗。三个脚本均已内置清除;在其它 shell 中手动运行npm run dev/npm run build前请自行unset ELECTRON_RUN_AS_NODE(bash)或Remove-Item Env:ELECTRON_RUN_AS_NODE(PowerShell)。脚本中的 Node 路径
C:\Users\Einn Tzai\.workbuddy\binaries\node\versions\22.22.2为本机托管运行时,其它机器请改为自己的 Node 路径或移除该行改用系统 Node。
npm test # vitest 单元测试(解析器等纯逻辑,tests/unit)
npm run test:e2e # Playwright 渲染层端到端(先自动 build:dir,驱动 out/renderer + window.opia 内存桩)
npx tsc --noEmit # 类型检查(提交前必过)src/
├── main/ # 主进程
│ ├── index.ts # 入口、单实例锁、服务装配
│ ├── window.ts # 窗口创建、Mini/完整模式切换
│ ├── feed/ # FeedService(抓取/缓存/定时刷新)+ 内置 RssProvider
│ ├── store/ # StoreService(electron-store 封装)
│ ├── theme/ # ThemeService + 内置主题 token
│ ├── plugin/ # PluginManager(plugins/ 目录加载器)
│ └── ipc.ts # IPC handler 集中注册
├── preload/index.ts # contextBridge 类型安全 API(window.opia)
├── renderer/ # React 渲染层
│ ├── components/ # TitleBar / TabStrip / HomeView / ReaderView / BrowserPage / SettingsPanel / ThemeEditor / MiniView 等
│ ├── juya/ # 橘鸦定制阅读系统:结构化解析 / 风格注册表 / 五风格模板 / juya.css
│ ├── layouts/ # 紧凑列表 / 卡片网格 / 杂志风
│ ├── stores/ # zustand 全局状态
│ └── theme/ # CSS 变量注入
└── shared/ # 主/渲染共用:types.ts、ipc-contract.ts、plugin-api.ts
tests/ # vitest 单测(tests/unit)+ Playwright 端到端(tests/e2e)+ 脱敏夹具(tests/fixtures,不提交)
plugins/ # 插件目录(含示例 example-hello)
- 设置 / 订阅源 / 历史 / 文章缓存:
%APPDATA%/Opia RSS Reader/opia-data.json - 自定义主题:
%APPDATA%/Opia RSS Reader/themes/*.json
插件是 plugins/ 下的一个目录,含清单与 CommonJS 入口:
plugins/<your-plugin>/
├── manifest.json # { id, name, version, main, provides: ["feed-provider"|"theme"|"card-renderer"] }
└── index.cjs # 导出实现 OpiaPlugin 的对象(类型见 src/shared/plugin-api.ts)
provides是能力开关:没声明的注册点,即使入口里带了对应字段也不会生效。- 加载发生在启动时(一次、同步、无热重载),改完插件需重启应用;没有
init/dispose钩子。 - 发行版是便携 exe,
app.asar内的plugins/只读 —— 用户插件请放%APPDATA%\Opia RSS Reader\plugins\。 - 插件以 main 进程完整权限运行且未沙箱化;主题颜色会直接注入 CSS,核心不做净化。
- 三类注册点可用度不同:FeedProvider 与 Theme 完整可用,CardRenderer 在 v1 仅登记元数据、界面无变化。
完整契约、provider 选中规则、主题校验规则、排障日志与坑位清单见 docs/PLUGIN_API.md。
可直接照抄的骨架见仓库内三个示例(npm test 会校验它们真实可加载):
| 示例 | 注册点 |
|---|---|
plugins/example-json-feed/ |
feed-provider —— JSON Feed 1.1 解析器 |
plugins/example-theme/ |
theme —— 亮/暗各一的完整主题 |
plugins/example-hello/ |
card-renderer —— 仅元数据(演示 v1 未接通) |
重启应用后自动加载,主进程日志 [main] plugin registry: {...} 可见注册结果。
这里的 TODO 是公开路线图,欢迎通过 Issue 讨论优先级,或直接提交 PR 认领已经明确的任务。
- 补充 IPC、FeedService、标签会话与主题系统的自动化测试(
npm test:契约三处同步守卫、provider 选中与源锁定、会话序列化与恢复截断、主题亮暗分类与校验) - 完善
FeedProvider、Theme、CardRenderer插件 API 文档与示例(docs/PLUGIN_API.md +plugins/三个示例;CardRenderer 明确标注 v1 未接通) - 持续优化不同 Windows 环境下的兼容性、打包与升级体验
- 根据社区反馈完善订阅管理、阅读体验与无障碍支持
发现 Bug、希望新增功能或有使用建议,欢迎前往 GitHub Issues。
- 提交前请先搜索已有 Issue,避免重复反馈。
- 新建 Issue 时请尽量提供应用版本、Windows 版本、复现步骤、预期行为和实际行为。
- UI 或交互问题请附上截图;启动、刷新或构建问题请附上相关日志,并移除订阅地址、本地路径等敏感信息。
- 如果问题涉及安全或隐私,请只公开必要信息,并在提交前确认日志中没有个人数据。
也可以直接使用 新建 Issue 入口提交反馈。
我们欢迎任何可行的贡献代码、插件、文档、测试和 UI 改进。建议按以下流程参与:
- 先在 Issues 中搜索或讨论变更意图。
- Fork 仓库,创建独立分支,并保持每个 PR 聚焦于一个主题。
- 完成修改后运行
npx tsc --noEmit和npm run build。 - 提交 Pull Request,说明变更内容、关联的 Issue、验证方式;涉及 UI 的改动请附截图或录屏。
提交代码时请遵循项目的架构边界:
- 渲染进程不直接访问网络或文件系统,跨进程数据统一经 IPC 传递。
- 新增 IPC 通道时,同步更新共享契约、preload 暴露和主进程 handler。
- 新增订阅源解析能力时,优先实现
FeedProvider,不要直接硬编码进FeedService。 - UI 样式使用主题 token;无关重构请与功能性改动分开提交。
感谢每一位提交反馈、修复问题、编写插件或完善文档的贡献者。 其中,Codex(OpenAI)作为共同作者与贡献者参与本项目。