mirror of
https://github.com/hectorqin/reader.git
synced 2026-11-11 05:20:54 +08:00
feat(sources): add configuration pages and chapter updates
This commit is contained in:
1 parent
a6fddab953
commit
c192fc2f12
30 files changed
+1233
-95
No files matched your search
+20
-23
@@ -1,6 +1,6 @@
|
||||
# 来源插件系统设计
|
||||
|
||||
状态:内置来源、进程插件和章节阅读闭环已实现
|
||||
状态:内置来源、插件、配置 UI、章节富文本/图片与自动追更已实现
|
||||
|
||||
适用接口:`/api/v1`,来源插件协议 1
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
本文定义 reader 对本地书库、OPDS 书库和远程书源的统一扩展架构。目标是让核心程序只维护一套书架、阅读、缓存和任务逻辑;内置 `local`、`opds` 两种来源;远程书源以独立插件开发、安装和升级。
|
||||
|
||||
本文区分目标架构和本轮交付。当前已实现 local、OPDS 下载入库、受信任 Node 来源插件及管理接口;外部章节已接入持久化出版物、书架、按章节缓存、手动刷新和既有阅读进度。设备端缓存已读章节,不提供整书预下载或后台自动追更。交付状态与验证见 §13,调用示例见 [API 参考](api.md#来源与插件)。
|
||||
|
||||
## 1. 目标与范围
|
||||
|
||||
### 1.1 目标
|
||||
@@ -169,7 +167,7 @@ interface PublicationContent {
|
||||
}
|
||||
```
|
||||
|
||||
SDK 的 `ResourceResponse` 支持 `mediaType`、`size`(若已知)、`data`、`text` 和 `stream`。内置 OPDS 提供者通过流下载。首个外部进程只支持章节来源,声明 `acquire.file` 会被拒绝;资源通过有大小上限的 `text/base64` JSON 传输。来源级开发预览始终返回 JSON,实际入库阅读只接受 UTF-8 `text/plain`,暂不支持远程 HTML、图片或其他富文本。后续资源通道支持背压和取消后,外部插件才适合传输大文件。
|
||||
SDK 的 `ResourceResponse` 支持 `mediaType`、`size`、`data`、`text` 和 `stream`。内置 OPDS 使用流下载;进程插件暂只支持章节,`acquire.file` 会被拒绝。进程资源通过有大小上限的 `text/base64` JSON 传输;入库章节接受 UTF-8 纯文本或 HTML/XHTML,HTML 内插图通过 `reader-res:<ref>` 引用同一插件的二进制资源。宿主清洗并内嵌图片后才返回给阅读器。来源开发预览始终返回 JSON。
|
||||
|
||||
### 4.3 能力
|
||||
|
||||
@@ -220,7 +218,7 @@ content.update
|
||||
|
||||
### 5.2 宿主能力
|
||||
|
||||
SDK 预留以下能力;首个切片的 `SourceContext` 中能力注入是可选的,独立进程内暂未实现宿主能力的反向 RPC,不能假设以下约束已强制生效:
|
||||
SDK 的目标能力如下。独立进程尚未实现宿主能力的反向 RPC;已实现的凭据注入会在每次调用时,按用户、来源实例、`credentialKeys` 和 `permissions.credentials` 选择允许传递的键,放入 `context.credentials`。这不等于以下全部运行约束都已强制生效:
|
||||
|
||||
| 能力 | 规则 |
|
||||
| --- | --- |
|
||||
@@ -239,7 +237,7 @@ SDK 预留以下能力;首个切片的 `SourceContext` 中能力注入是可
|
||||
|
||||
```text
|
||||
request = { jsonrpc: "2.0", id, method,
|
||||
params: { sourceType, context: { instance, userId }, ... } }
|
||||
params: { sourceType, context: { instance, userId, credentials? }, ... } }
|
||||
response = { jsonrpc: "2.0", id, result }
|
||||
error = { jsonrpc: "2.0", id, error: { code, message, data? } }
|
||||
```
|
||||
@@ -270,9 +268,9 @@ error = { jsonrpc: "2.0", id, error: { code, message, data? } }
|
||||
|
||||
目标上插件负责搜索、详情、目录快照、正文清洗和图片引用;宿主负责缓存、限流、任务、权限和阅读协议。插件返回 `chapters` 绑定后,宿主获取目录快照、分配稳定 book ID 并加入调用用户书架;HTTP 返回 `ready/publicationId`,阅读器继续使用 `/books/:id/manifest|toc|assets`。
|
||||
|
||||
当前入库阅读只接受 UTF-8 `text/plain`。正文按纯文本下发,客户端负责排版和转义;HTML、图片和其他富文本资源会被拒绝。章节资源第一次读取后持久化,插件禁用或卸载后仍可读取已缓存正文,尚未缓存的章节返回来源不可用。
|
||||
入库阅读支持 UTF-8 `text/plain`、`text/html` 和 `application/xhtml+xml`。纯文本由客户端转义排版;HTML 经 `sanitize-html` 白名单处理,只保留段落、标题、强调、列表、表格等静态标签。删除脚本、样式、表单、外链和 SVG。插图须声明 `reader-res:<插件资源引用>`,宿主调用同一来源 `readResource`,校验 PNG/JPEG/GIF/WebP 类型与文件签名,再内嵌 data URL。整章(含图片)原子缓存,任一资源失败不写半份缓存。禁用或卸载插件后已缓存正文和插图仍可读。
|
||||
|
||||
刷新目录通过 `POST /books/:id/refresh` 显式触发;Web 阅读器目录面板提供“刷新目录”,以稳定章节 href 恢复当前位置。获取或校验失败保留旧目录,界面在目标章节可读后才替换视图。本轮没有定时检查新章、整书预下载或后台追更任务。
|
||||
刷新目录通过 `POST /books/:id/refresh` 或订阅调度触发;阅读器目录面板以稳定 href 恢复当前位置。失败保留旧目录,界面在目标章节可读后才替换视图。`chapter_subscriptions` 持久保存开关、15~10080 分钟间隔、检查时间、失败次数和新增章提示。每分钟调度一次,单轮最多 20 本顺序检查,共用来源并发限制;手动与自动检查同书合并在途调用。失败退避,暂停来源、隐藏书籍、禁用账号时跳过,关闭浏览器不影响检查。新目录不强行替换正在阅读的旧快照,也不预下载正文。
|
||||
|
||||
## 7. 数据模型
|
||||
|
||||
@@ -286,7 +284,8 @@ error = { jsonrpc: "2.0", id, error: { code, message, data? } }
|
||||
| `source_acquisitions` | `(source_id, user_id, entry_ref, option_id)` 到 `book_id` 的映射。 |
|
||||
| `chapter_publications` | 按用户隔离的章节出版物、来源引用、当前 revision 和目录快照。 |
|
||||
| `chapter_snapshots` | 出版物历次目录快照;刷新后保留旧 revision。 |
|
||||
| `chapter_resources` | 每个 revision 的章节引用、已缓存正文和正文 SHA-256。 |
|
||||
| `chapter_resources` | 每个 revision 的章节引用、已缓存正文、`media_type` 和正文 SHA-256;HTML 正文包含校验后的内嵌图片。旧缓存增量迁移为纯文本。 |
|
||||
| `chapter_subscriptions` | 每书追更开关、间隔、检查时间、失败退避、新增章数及配置 generation。 |
|
||||
| `plugin_storage` | 宿主 KV,按来源和用户命名空间保存;外部进程尚无反向访问接口。 |
|
||||
| `installed_plugins` | 插件 ID、已放置的包目录名及启用状态。 |
|
||||
|
||||
@@ -362,9 +361,9 @@ QUOTA_EXCEEDED 缓存或下载配额不足
|
||||
- 内置 OPDS 的网络请求经过宿主校验:允许 origin、重定向目标、Basic 凭据转发、超时和响应大小;普通 OPDS 链接不能跳到未配置的 origin。
|
||||
- 外部 Node 插件当前是受信任进程,仍拥有本机 Node 的网络、文件和子进程权限;manifest 权限声明和 `SourceContext` 可选能力尚未构成 OS 级网络沙箱。管理员只能安装信任的包。
|
||||
- 插件凭据不出现在普通配置、前端 DTO 和日志中。
|
||||
- 外部插件资源预览只返回 JSON 文本或 base64;入库章节只接受纯文本,并带 `nosniff` 和限制内容执行的 CSP。阅读器自行转义正文,不执行插件 HTML;远程富文本和图片清洗属于后续工作。
|
||||
- 资源预览只返回 JSON;阅读正文纯文本转义或 HTML 白名单清洗,并带 `nosniff`、禁止脚本和外网资源的 CSP。图片经来源通道获取后内嵌,不让浏览器直接访问书源网站。
|
||||
- 本地和已获取文件路径通过宿主 `resolveInside()` 校验;外部插件直接读写路径的能力目前依赖管理员信任,系统沙箱属于后续工作。
|
||||
- 当前硬限制是宿主来源调用 60 秒、插件 RPC 30 秒、单条 JSON 2 MiB、文件获取 256 MiB;章节目录最多 10,000 项及 2 MiB,单章纯文本最多 2 MiB(仍受 RPC 消息上限约束)。CPU/内存和域名权限的强制隔离属于后续工作。
|
||||
- 硬限制:宿主调用及整章加载 60 秒、插件 RPC 30 秒、JSON 2 MiB、文件获取 256 MiB;目录最多 10,000 项及 2 MiB,原始正文 2 MiB;最多 32 个不同图片、每图 2 MiB,内嵌后整章最多 8 MiB。图片仍受 RPC base64 开销限制。CPU/内存和域名权限的系统级隔离属于后续工作。
|
||||
- 插件安装及来源实例配置需要管理员权限;实例配置共享,凭据按用户隔离。
|
||||
|
||||
manifest 中的权限声明用于宿主授权和展示,不能单独视为安全沙箱;运行不可信插件需要容器或操作系统策略。
|
||||
@@ -393,7 +392,7 @@ GET /sources/:id/publications/:publicationRef/resource?ref=...
|
||||
POST /books/:id/refresh 获取并提交新的章节目录快照
|
||||
```
|
||||
|
||||
HTTP 返回宿主 DTO,凭据不回显。插件管理均需管理员权限;来源浏览、搜索、获取和当前用户凭据设置需登录。来源的 URL、名称和 config 更新、来源删除、插件包上传及升级尚无接口。请求参数、响应和可运行示例见 [API 参考](api.md#来源与插件)。
|
||||
HTTP 返回宿主 DTO,凭据不回显。插件和来源配置管理需管理员权限;浏览、获取和个人凭据需登录。`PATCH /sources/:id` 更新名称/config/启停,config 变更清除所有用户的该来源凭据;有在途来源调用时拒绝变更 config。`DELETE` 只移除无获取记录的非本地来源。Web `#/sources` 根据类型 schema 绘制配置表单,普通成员只有浏览、凭据和个人追更操作。插件可声明 credentialKeys 与 credentials 权限,宿主只按调用用户向进程传递明确声明的键。包上传和在线升级尚未实现。
|
||||
|
||||
## 11. 分阶段实施
|
||||
|
||||
@@ -439,8 +438,6 @@ HTTP 返回宿主 DTO,凭据不回显。插件管理均需管理员权限;
|
||||
|
||||
## 13. 本轮实施状态与后续工作
|
||||
|
||||
本轮交付服务端扩展接口、OPDS 下载阅读闭环和纯文本章节阅读闭环。状态截至 2026-09-20;后续条目不能视为已交付。
|
||||
|
||||
| 工作 | 本轮状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 来源契约 | 已实现并测试 | `server/src/sources/types.ts`,包括目录、获取、章节和资源。 |
|
||||
@@ -448,22 +445,22 @@ HTTP 返回宿主 DTO,凭据不回显。插件管理均需管理员权限;
|
||||
| OPDS 解析、浏览、搜索、获取 | 已实现并测试 | OPDS 1.x/2.x、相对链接、OpenSearch、分页、Basic 认证和获取关系。 |
|
||||
| OPDS 文件下载入库 | 已实现并测试 | 同步下载,真实哈希、256 MiB 上限、失败清理、幂等复用、当前用户上架;复用现有阅读接口。 |
|
||||
| SourceHost、来源实例及凭据 | 已实现 | 实例由管理员配置共享,密码按来源/用户加密,调用预算 60 秒;并发限额每实例 2、全宿主 8。 |
|
||||
| 来源管理 HTTP 接口 | 已实现并测试 | 创建、列表、启停和来源调用;仅 `enabled` 可更新,不含前端配置页面。 |
|
||||
| 来源管理与配置 UI | 已实现并测试 | 创建、编辑、启停、删除空来源、浏览/搜索、获取及个人凭据。 |
|
||||
| 内置 local 与本地内容 seam | 已实现并测试 | 保留现有 book ID、书架及阅读接口,集中本地与下载文件解析。 |
|
||||
| 受信任 Node ProcessRunner | 已实现并测试 | JSON-RPC、30 秒调用预算、硬取消、异常退出、2 MiB 消息上限。 |
|
||||
| 插件安装、启停、卸载与启动恢复 | 已实现并测试 | 包由管理员预置到 `DATA_DIR/plugins`;卸载保留数据和包文件。 |
|
||||
| 最小外部来源示例 | 已实现并测试 | `examples/plugins/demo-chapters`,提供静态示例目录和正文,不联网。 |
|
||||
| 插件安装 UI、包上传、在线升级与状态回滚 | 后续 | 本轮不承诺完整插件市场和包管理。 |
|
||||
| 插件安装 UI | 已实现 | 安装预部署目录、启停、重启失败进程、卸载;包上传、在线升级和回滚仍后续。 |
|
||||
| 后台下载任务、断点恢复、JobManager | 后续 | 当前完整文件会持久化,下载过程本身没有后台任务及恢复机制。 |
|
||||
| 外部章节写入书架与阅读 | 已实现并测试 | 私有稳定 book ID、现有 manifest/items/toc/assets、书架、继续阅读和进度。 |
|
||||
| 目录快照与服务端章节缓存 | 已实现并测试 | 稳定 href、revision 资源引用、已读缓存、失败保留旧目录、禁用/卸载/重启后缓存可读。 |
|
||||
| Web 章节阅读与设备离线缓存 | 已实现 | 目录与已读章节按服务器和用户持久缓存;断网或服务端 5xx 时回退;授权及资源不存在错误不回退。 |
|
||||
| 手动刷新目录 | 已实现 | 阅读器目录面板入口;恢复当前章节位置;无后台追更。 |
|
||||
| 远程富文本、图片、整书预缓存、缓存配额与淘汰 | 后续 | 当前只支持 UTF-8 纯文本,设备仅已读章节可离线。 |
|
||||
| 自动检查新章与追更任务 | 后续 | 当前只有显式刷新 API 和阅读器按钮。 |
|
||||
| 反向宿主能力 RPC、凭据和配额强制隔离 | 后续 | 类型预留不等于运行策略已生效。 |
|
||||
| 手动刷新目录 | 已实现 | 阅读器目录面板入口,恢复当前章节位置,记录检查状态。 |
|
||||
| 远程富文本与图片 | 已实现并测试 | 白名单 HTML、受控栅格图片、服务端与设备整章缓存;设备仅已读内容可离线。 |
|
||||
| 整书预缓存、缓存配额与淘汰 | 后续 | 保留历史目录与缓存,无自动清理配额。 |
|
||||
| 自动追更 | 已实现并测试 | 用户按书订阅,服务端定时检查、持久状态、失败退避与新增章提示。 |
|
||||
| 声明凭据注入 | 已实现并测试 | 每次调用仅传递获准声明键,按用户和来源隔离。 |
|
||||
| 反向宿主能力 RPC、系统权限隔离和缓存配额 | 后续 | 类型预留不等于运行策略已生效。 |
|
||||
| 容器/操作系统沙箱 | 后续 | 首个版本仅允许运行管理员信任的插件。 |
|
||||
|
||||
验证覆盖来源、插件进程、管理接口、OPDS 下载、用户隔离、并发限额、参数校验与既有本地阅读回归。章节端到端测试使用真实 Node 进程和可变目录 fixture,覆盖获取幂等、插章定位、版本缓存、旧快照拒绝、刷新失败、禁用/卸载/扫描/重启和 HTML 资源拒绝;核心测试另覆盖迁移、请求与刷新并发及资源边界。测试均使用本地 HTTP fixture 或示例插件,未验证特定公网 OPDS 服务或第三方采集站点。
|
||||
|
||||
本轮验证结果:服务端 `npm test` 274 通过、1 项因 Windows 不支持 Unix 目录权限位而跳过;Web `npm test` 547 通过;两端类型检查和生产构建通过。真实 Chrome 验证了刷新按钮显示、插入章节后保留当前章节及新增章节提示。全页 UI 评审另有两项未通过(沉浸分页顶行截断、书架操作按钮透明度),未纳入本轮修复;Android 安装包未构建。
|
||||
本轮验证结果:服务端全量 `npm test` 281 通过、1 项因 Windows 不支持 Unix 目录权限位而跳过,包含旧缓存媒体类型迁移回归。Web `npm test` 552 通过;两端类型检查和生产构建通过。真实 Chrome 检查了书架入口、配置表单、追更列表及插件信任勾选,在 390×844 手机和 1280×900 桌面布局下没有横向溢出。本轮未重跑全页 UI 评审;上一轮记录的沉浸分页顶行截断、书架操作按钮透明度问题仍未纳入修复。Android 安装包未构建。
|
||||
Reference in new issue
Block a user