Folo Desktop v0.3.0 版本解析:自定义 RSSHub 实例、可配置 OPML 导出与账号管理
Folo(AI RSS Reader)桌面端 v0.3.0 是一次围绕"数据获取与数据带走"能力展开的版本更新:新增可接入的自定义 RSSHub 实例、带选项的 OPML 订阅导出,以及更完整的账号信息管理。读完本文,你可以掌握 v0.3.0 中每项新功能的实际形态——RSSHub 实例页面的组织与排序规则、自建实例的接入字段与环境变量约定、OPML 导出表单的校验逻辑与请求参数,并能在 Folo 源码中快速定位这些功能的实现位置。
版本概览:v0.3.0 改了什么
v0.3.0 的变更说明记录在 apps/desktop/changelog/0.3.0.md,整体分为三部分:
- New Features(新增功能):
- Custom RSSHub Instances(自定义 RSSHub 实例):接入自建 RSSHub 实例以提升数据获取效率;贡献自己部署的 RSSHub 实例还可获得额外 $POWER 激励。
- OPML Export Options(OPML 导出选项):导出 OPML 文件时,可可选地指定 RSSHub URL 与文件夹分类模式。
- Account Management(账号管理):支持更新邮箱,并方便地管理已关联的第三方社交账号。
- Improvements(改进):
- 支持更新邮箱并管理关联的社交账号;
- 当用户已停留在 Discover(发现)页面时再次导航进入,会自动滚动回顶部。
- Bug Fixes:修复了若干缺陷(原文未逐一列举)。
下面按功能逐项展开,并结合当前仓库中的源码实现说明其行为边界。
功能一:自定义 RSSHub 实例
这是 v0.3.0 的核心功能。Folo 内置了官方 RSSHub("Folo Built-in RSSHub"),但用户现在可以添加、编辑、删除自己部署的 RSSHub 实例,并自由切换当前账号使用的实例。
实例页面:官方实例置顶,用户实例按可用性排序
RSSHub 实例管理页面的入口在 rsshub 子视图页面/(layer)/(subview)/rsshub/index.tsx)。页面结构从源码结构看是:顶部标题与简介、"Add new instance" 按钮,然后是实例卡片网格(响应式 1/2/3 列)。
实例列表的排序逻辑在 List 组件中(同文件 L245-L283):
- 官方实例永远排在第一位,以
{ id: "official", isOfficial: true }的形式虚拟插入列表; - 用户实例中,当前正在使用的实例排前(依据
status.usage.rsshubId); - 其次按健康状态排序,带
errorMessage的实例排后; - 最后按负载率(
userCount / userLimit)从低到高排序,满载实例沉底。
每张实例卡片展示 owner 头像、描述、当前用户数(Users)与容量上限(Limit),并带有若干状态标签(L124-L143):
official:Folo 官方内置实例;in use:当前账号正在使用的实例;yours:当前登录用户自己部署的实例;Error:实例健康检查报错。
对于自己拥有的实例,页面还提供 Edit 与 Del 操作;其中 Delete 按钮会在"实例上还有其他用户"时禁用(L205-L216,disabled={!!instanceUserCountExceptOwner}),避免误删影响他人。
添加实例:baseUrl + accessKey,以及自建实例的环境变量约定
添加实例的表单在 add-modal-content.tsx,其 Zod schema(L41-L48)定义了两个字段:
baseUrl:必填,且必须是合法 URL(z.string().url());accessKey:可选,用于访问受限实例时的密钥。
提交后调用 useAddRSSHubMutation,即以 { baseUrl, accessKey, id } 参数请求后端创建实例记录(id 存在时为编辑已有实例)。
更值得注意的是,添加弹窗内直接用 Shiki 高亮展示了一段 dotenv 格式的部署指引(L69-L73),告诉实例部署方需要在服务端配置哪些环境变量:
FOLLOW_OWNER_USER_ID=${用户 id 或 handle} # 你的 Folo 账号 id 或 handle
FOLLOW_DESCRIPTION=${实例描述} # 你的实例描述
FOLLOW_USER_LIMIT=${容量上限} # 用户数上限;设为 0 或 1 可将实例私有化,留空表示不限制
从默认值处理看,userLimit 缺省时按 1000 展示(L72)。也就是说,自建实例的容量策略是:0/1 = 私有、留空 = 不限制、其他正整数 = 明确上限。实例卡片上 userLimit > 1 时显示具体数字,≤ 1 时显示 "Private" 标签(rsshub/index.tsx/(layer)/(subview)/rsshub/index.tsx) L116-L122)。
切换实例:使用状态、二次验证与容量校验
切换("Use")实例的确认弹窗在 set-modal-content.tsx,会展示该实例的 owner、描述、当前用户数与容量上限(L34-L59),用户确认后才执行切换。从源码结构看,切换动作被包在 useTOTPModalWrapper 中(L21),即切换实例属于敏感操作,会触发 TOTP 二次验证。
数据层封装在 queries/rsshub.ts:
useAddRSSHubMutation:调用followClient.api.rsshub.create({ baseUrl, accessKey, id }),成功后使rsshub.list()与rsshub.status()两个查询失效并刷新;useSetRSSHubMutation:调用followClient.api.rsshub.use切换当前使用实例,成功后同样刷新列表、状态与对应实例详情;useDeleteRSSHubMutation:按id删除实例;- 查询侧提供
rsshub.get/rsshub.list/rsshub.status三个defineQuery封装,其中list成功时会顺带把实例 owner 信息写入用户 store(L75-L81),供页面渲染头像使用。
另外,实例卡片上的选择按钮(SelectInstanceButton,rsshub/index.tsx/(layer)/(subview)/rsshub/index.tsx) L295-L329)有两道可用性拦截:
- 实例带
errorMessage(健康检查失败)时按钮禁用,显示 "unavailable"; userCount >= userLimit(容量已满)时按钮禁用,显示 "limit reached"。
这与 changelog 中"使用自定义 RSSHub 实例提升数据获取效率"的定位一致:官方实例不可用时,用户可以切换到自建的、负载更低的实例。
功能二:OPML 导出选项
v0.3.0 让 OPML 导出不再是"一键全量",而是允许用户在导出前指定两个可选项。实现位于桌面端设置页的数据管理标签页 data-control.tsx 中的 ExportFeedsForm(L116-L196)。
表单字段与校验规则
导出的表单 schema(L116-L119):
const exportFeedFormSchema = z.object({
rsshubUrl: z.string().url().optional(), // 可选,但填写后必须是合法 URL
folderMode: z.enum(["view", "category"]), // 二选一,默认 "view"
})
- RSSHub URL(
rsshubUrl):可选项。输入框 placeholder 为https://rsshub.app,提示用户可以填入自己使用的 RSSHub 地址; - 文件夹分类模式(
folderMode):枚举值只有两个——view(按视图/收藏组织)与category(按分类组织),默认选中view(defaultValues: { folderMode: "view" },L124-L129)。
导出流程:拼接导出请求并触发下载
提交逻辑(L131-L141)并不在客户端本地生成 OPML,而是动态构造一个带查询参数的导出接口 URL 并触发浏览器下载:
function onSubmit(values) {
const exportUrl = new URL(`${env.VITE_API_URL}/subscriptions/export`)
exportUrl.searchParams.append("folderMode", values.folderMode)
if (values.rsshubUrl) {
exportUrl.searchParams.append("RSSHubURL", values.rsshubUrl)
}
// 通过创建 <a download> 触发下载
link.href = exportUrl.toString()
link.download = "follow.opml"
link.click()
}
也就是说,最终请求形如:
GET {API_URL}/subscriptions/export?folderMode=view[&RSSHubURL=https://your-rsshub.example.com]
文件名固定为 follow.opml。从参数设计可以推断两个选项的作用:folderMode 决定 OPML 内的层级如何映射(跟随 App 内的视图结构或分类结构),而 RSSHubURL 决定导出文件中那些经由 RSSHub 生成的订阅地址以哪个实例前缀写出——配合"自定义 RSSHub 实例"功能,用户换环境或换实例时导入的 OPML 依然指向自己能访问的实例。
同一个数据管理标签页还包含其他数据操作(可作为对照):导出本地数据库(exportDB())、清理缓存(Electron 与 Web 两套实现)、数据库重建等,见 data-control.tsx L38-L114。
功能三:账号管理
changelog 将"Account Management"列为 v0.3.0 的新功能,并在 Improvements 中再次强调"Update email and manage linked social accounts"。该能力允许用户在 Folo 中:
- 更新绑定邮箱;
- 管理已关联的第三方社交账号(查看/解除关联)。
从源码结构看,桌面端个人资料相关界面集中在 profile 模块(如 UserProfileModalContent.tsx),账号状态数据则由共享的 user store 维护(packages/internal/store/src/modules/user/store.ts)。changelog 本身未展开该功能的细节,此处以版本说明为准,具体交互以上述模块当前实现为参考入口。
改进项与其他修复
- Discover 页面重复导航回顶:当用户已处于 Discover(发现)页时再次导航进入,会自动滚动到顶部,避免停留在上次浏览的滚动位置。这类滚动控制逻辑位于 discover 相关页面与路由钩子(如 useDiscoverRSSHubRoute 所在的功能区)中。
- Bug 修复:changelog 以"Some bugs are fixed."一笔带过,未逐项列举具体缺陷。
延伸阅读:与 v0.3.0 相关的源码路径
如需继续深入 v0.3.0 的功能实现,可以从以下文件入手:
| 功能 | 文件 |
|---|---|
| 版本变更说明 | apps/desktop/changelog/0.3.0.md |
| RSSHub 实例管理页(列表/排序/卡片/操作) | rsshub/index.tsx/(layer)/(subview)/rsshub/index.tsx) |
| 添加/编辑实例表单与部署环境变量 | add-modal-content.tsx |
| 实例详情与切换(Use)确认 | set-modal-content.tsx |
| RSSHub 增删切换的 React Query 封装 | queries/rsshub.ts |
| OPML 导出选项表单与导出请求构造 | data-control.tsx |
需要说明的是:v0.3.0 是较早的版本,当前仓库中的上述源码是演进后的实现(例如 OPML 导出表单已并入设置页的数据管理标签),细节字段与交互可能比 0.3.0 发布时更完整,但整体功能脉络与该版本 changelog 的三项新功能保持一致。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00