EasyReader 是一个自托管、多端阅读系统,目标是把在线书源、本地书籍、阅读进度、离线缓存和多客户端同步收敛到一个可长期维护的个人阅读平台。
项目现在按独立产品线维护,后续路线围绕服务端核心能力、搜索质量、客户端阅读体验和有声书任务体系持续演进。
EasyReader 的早期形态参考并继承了 qq148376839/reader 的大量工作,包括阅读器基础能力、书源处理思路、内容抓取流程和部分工程实现。感谢原作者 qq148376839 以及相关社区积累,让这个项目有了可以继续演进的基础。
当前 EasyReader 已经围绕自托管、多端同步、PWA 离线能力、服务端缓存、本地书籍管理和墨水屏客户端方向进行了持续重构。后续维护目标是独立演进这个项目,而不是作为对原项目的补丁分支;
EasyReader 当前由三部分组成:
- FastAPI 共享服务端:负责书源解析、内容抓取、书架主数据、章节缓存、同步状态、离线任务和字体资源。
- React + Vite Web PWA:面向浏览器和移动端主屏安装,采用在线优先 + 本地缓存增强的阅读体验。
- Kotlin Android 墨水屏客户端:面向低刷新、低干扰、本地阅读优先的设备体验,独立维护在
e-link-client/。
当前产品边界很明确:服务端是共享内容与状态中心,Web PWA 是通用阅读客户端,墨水屏客户端是本地阅读优先客户端。三端共享 API 契约,但不强迫采用同一种联网策略。
- 导入、启用、禁用和删除书源。
- 多源搜索与书籍发现。
- 获取书籍详情、目录和章节正文。
- 支持在线小说正文阅读。
- 服务端章节缓存,降低重复抓取成本。
- 导入
JSON、TXT、EPUB。 - 本地导入书籍可直接进入阅读。
- EPUB 章节标题清洗,避免出现
Text/...xhtml这类不友好的目录名。 - 批量删除、批量预缓存、批量导出
TXT/EPUB。
- 书架列表、分类、隐藏和批量管理。
- 继续阅读进度。
- 阅读中预取后续章节。
- 服务端与浏览器两层缓存统计和清理。
- 浏览器 IndexedDB 章节缓存。
- PWA Workbox 运行时缓存。
- 进度同步:
POST /api/sync/progress/upsert、GET /api/sync/progress/pull。 - 书签同步:
POST /api/sync/bookmarks/batch、GET /api/sync/bookmarks/pull。 - 离线目录:
POST /api/offline/tasks、GET /api/offline/catalog。 - 服务端字体清单与字体下载接口,供客户端复用。
- API 版本与客户端契约头,便于 Web PWA 和墨水屏客户端对齐能力边界。
- 服务端备份下载与恢复上传,支持全量恢复或增量恢复冲突处理。
当前部署形态是单容器部署:
- 前端在 Docker 构建阶段打包为静态文件。
- FastAPI 在运行时同时提供
/api/*和前端 SPA 回退。 - 运行期数据全部写入
data/volume。 - 容器启动时会准备运行所需的数据目录和字体目录。
Browser / PWA -> FastAPI -> SQLite
E-link Android -> FastAPI -> data/cache
-> data/exports
-> data/fonts
更详细的架构、阶段状态和客户端说明见:
- 当前仓库不再使用 Claude 工作流。
- 后续开发统一以仓库文档(
docs/)和.copilot-instructions.md作为 AI 协作基线。
- 后端:FastAPI, aiosqlite, Pydantic, BeautifulSoup
- 前端:React, TypeScript, Vite, Zustand
- PWA:vite-plugin-pwa, Workbox, idb-keyval
- 本地文件:EbookLib, python-multipart
- 墨水屏客户端:Kotlin / Android
- 数据库:SQLite
- 部署:单容器 Docker
EasyReader/
├── backend/ # FastAPI API、数据库、规则引擎和业务服务
├── frontend/ # React + Vite Web PWA
├── e-link-client/ # 墨水屏 Android 客户端
├── data/ # SQLite、缓存、导出文件和字体文件
├── tests/ # 后端回归测试
├── docs/ # 架构、阶段和共享约束文档
└── Dockerfile # 单容器构建入口
要求:Python 3.11+
python -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements-dev.txt
uvicorn backend.main:app --host 127.0.0.1 --port 8080 --reload要求:Node.js 20+
cd frontend
npm install
npm run dev默认开发地址:
- 后端:
http://127.0.0.1:8080 - 前端:
http://127.0.0.1:5173
所有配置项均通过 READER_ 前缀的环境变量设置,也可通过 .env 文件配置:
| 变量 | 默认值 | 说明 |
|---|---|---|
READER_DATA_DIR |
data |
数据存储目录 |
READER_DB_PATH |
{DATA_DIR}/reader.db |
SQLite 数据库路径 |
READER_CACHE_DIR |
{DATA_DIR}/cache |
缓存目录 |
READER_LOG_LEVEL |
INFO |
日志级别 |
READER_PROXY |
None |
HTTP 代理地址 |
READER_REQUEST_TIMEOUT |
15 |
请求超时时间(秒) |
READER_MAX_CONCURRENT_REQUESTS |
10 |
最大并发请求数 |
READER_OFFLINE_TASK_WORKER_ENABLED |
True |
是否启用离线任务 Worker |
READER_PASSWORD |
"" |
登录密码(空=禁用密码认证) |
READER_TOKEN_EXPIRY_DAYS |
90 |
登录 Token 有效期(天) |
READER_MAX_UPLOAD_SIZE_MB |
200 |
最大上传文件大小(MB) |
READER_CORS_ORIGINS |
"*" |
允许的 CORS 来源(逗号分隔) |
READER_USER_AGENT |
Chrome 120 UA | 请求 User-Agent |
设置密码保护系统访问:
# 设置密码(环境变量)
READER_PASSWORD=your-secret-password
# 可选:设置 Token 有效期(默认 90 天)
READER_TOKEN_EXPIRY_DAYS=90首次访问时需要输入密码,验证通过后 Token 保存在浏览器/客户端本地,90 天内无需重新输入。
后端测试:
.venv/bin/python -m pytest前端构建:
cd frontend
npm run buildDocker 构建:
docker build -t easyreader .Docker 运行:
docker run --rm -p 8080:8080 -v $(pwd)/data:/app/data easyreader运行期数据默认存放在 data/ 下:
reader.db:SQLite 数据库。cache/:章节内容和运行缓存。exports/:批量导出的 TXT / EPUB 文件。fonts/:服务器字体文件目录,支持.ttf/.otf/.ttc/.woff/.woff2。
当前核心 API 包括:
POST /api/auth/login:密码登录,返回 Token。GET /api/auth/verify:验证 Token 有效性。
POST /api/sources/import:导入书源(JSON 数组)。POST /api/sources/import-url:从 URL 导入书源。GET /api/sources:获取书源列表。GET /api/sources/groups:获取书源分组。PUT /api/sources/{url}/toggle:启用/禁用书源。DELETE /api/sources/{url}:删除书源。
GET /api/search:多源搜索(支持 SSE 流式)。GET /api/content/book-info:获取书籍详情。GET /api/content/chapters:获取目录。GET /api/content/chapter:获取章节正文。
GET /api/books:获取书架列表。POST /api/books:添加书籍到书架。DELETE /api/books/{id}:删除书籍。POST /api/books/delete-batch:批量删除书籍。POST /api/books/import:导入JSON、TXT或EPUB。POST /api/books/cache-batch:批量预缓存章节。POST /api/books/export-batch:批量导出书籍。GET /api/books/cache/stats:查看服务端缓存统计。POST /api/books/cache/clear:清理服务端缓存。GET /api/books/exports/{file_name}:下载导出文件。
GET /api/books/categories:获取分类列表。POST /api/books/categories:创建分类。PUT /api/books/categories/{name}/hidden:隐藏/显示分类。PUT /api/books/categories/{name}/rename:重命名分类。DELETE /api/books/categories/{name}:删除分类。PUT /api/books/{id}/category:设置书籍分类。POST /api/books/category-batch:批量设置书籍分类。
POST /api/sync/progress/upsert/GET /api/sync/progress/pull:多端进度同步。POST /api/sync/bookmarks/batch/GET /api/sync/bookmarks/pull:书签同步。POST /api/offline/tasks:创建离线任务。GET /api/offline/tasks:获取任务列表。GET /api/offline/catalog:获取离线目录。
GET /api/version:服务端版本信息。GET /api/fonts:获取服务器字体列表。GET /api/fonts/{file_name}/download:下载服务器字体文件。GET /api/backup/export:下载服务端备份 ZIP。POST /api/backup/restore:上传备份 ZIP 并执行全量/增量恢复。GET /api/proxy/image:图片代理。
- ✅ 服务端核心能力:书源解析、内容抓取、书架管理、章节缓存
- ✅ 认证系统:密码认证 + 长期 Token(90天有效)
- ✅ 多端同步:进度同步、书签同步、离线任务
- ✅ Web PWA:IndexedDB + Workbox 双层缓存、
fast/full搜索、自动翻页 - ✅ 安全加固:文件上传限制、CORS 配置、内存泄漏修复
- ✅ 后端测试:110 个测试用例覆盖核心功能
- ✅ 墨水屏客户端:
book_key基线、本地缓存阅读、WiFi 闸门和离线任务接入
- 🔲 有声书 / 音频任务能力
- 🔲 墨水屏客户端补齐请求头、同步冲突处理和显式离线任务状态机
- 🔲 阅读器设备交互收口,包括实体按键、缺章入口和刷新策略协同
- 🔲 前端测试覆盖
- 🔲 速率限制中间件
- 🔲 SSRF 防护
- ✅
还没有统一账号 / 鉴权系统→ 已实现密码认证 - 还没有有声书 / 音频任务能力。
- Android 墨水屏客户端还没有完全补齐请求头、同步冲突语义和显式任务 UI。
- Web PWA 是在线优先 + 本地缓存增强客户端,不能直接等同于墨水屏客户端策略。
- RSS 和漫画暂时不进入下一阶段路线。
当前仓库尚未声明最终开源许可证。
在重新创建公开仓库前,建议先明确许可证策略:
- 如果作为私有自用项目,可以暂不添加开源许可证。
- 如果计划公开发布,需要补充
LICENSE,并确认仓库中保留的第三方代码、素材、工程结构和依赖说明符合对应授权要求。 - 如果保留了来自参考项目的代码或实现结构,需要继续保留“致谢与来源说明”,并按最终确认的许可证要求补充必要声明。
- 如果后续要接受外部贡献,建议同时补充贡献说明和版权归属约定。