Skip to content

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

296 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reader-cloudflare

书源聚合阅读器:兼容 Legado 书源规则格式的解析引擎 + 自带阅读器。整套跑在 Cloudflare 上 (Workers + D1 + 静态资源),也能跑在自己的机器上 —— 包括 Docker。

主流阅读器都上不了 Workers:Legado 是安卓 App、hectorqin/reader 是 JVM 且带状态、 any-reader 用的是另一套源格式。而书源规则本身是声明式的,所以这里复刻的是一套规则语法, 不是某个应用的内部实现。

本项目不提供、也不分发任何书源。第一次进来是空的,要在「书源」页导入一份书源 JSON 才有 东西可搜 —— 见下面「书源」。

能做什么

逐项的兼容性账本(每一行都跟着对应的轮次)在 EXPERIENCE.md 的「当前状态」, 下面是按用途归的一层。

规则引擎

覆盖的是「能真的读完一本书」那条路径,而不是某个子集:

一类 说明
四种方言 JSOUP 默认规则(class.x.0@tag.a@href)、@css:、XPath(完整 XPath 1.0)、JSONPath(含简单过滤器)与 JSON 的裸字段名
取值链 ##正则##替换、### OnlyOne、AllInOne;&& / || / %% 连接符(不切进 JS 代码、引号与 JSONPath 过滤器里)
变量 @put: / @get:(含跨请求那一路)与 ruleBookInfo.init(铺变量与换根两种写法)
脚本 @js: 与 <js></js>,写在 URL 字段、字段规则、列表规则里都认;result 按脚本自己的写法绑成节点或字符串
列表规则 @js: 返回数组、<js> 块 + 尾段选择器(条目保留节点)、CSS 式首段 + @ 步骤与下标后缀、开头的 + 标记
四类源 文本 / 音频 / 图片 / 文件(bookSourceType 0–3),媒体一律由服务端代取(防盗链、混合内容、跨域)
翻页 nextTocUrl(目录最多 20 页)与 nextContentUrl(跨页章节最多 10 页)
编码 GBK / GB2312 等非 UTF-8 站点自动嗅探 + 按站点声明解码

沙箱

规则里的 JS 跑在 QuickJS(asyncify 版)里,java.*、org.jsoup.Jsoup、Packages.java.* 按 Legado 的签名对齐。缺的东西显式报错并报出名字,不静默返回空 —— 后者会让书源表现成 「搜不到书」,排查成本极高。

  • 取网:java.ajax / get / post / ajaxAll,在脚本里当同步函数用;重定向自己跟,每一跳的 Set-Cookie 都收
  • 纯计算:AES / DES、MD5 / SHA-256、base64 / hex、java.getString / getElements / timeFormat
  • 全局对象:source / book / chapter / cookie(cookie 罐)/ cache / infoMap / Packages
  • 书源自带的 jsLib 作为前置脚本先跑一遍

阅读器

零依赖、无构建步骤:public/ 直接作为静态资源发布,模块用原生 ESM 分文件。

  • 书架 / 搜索 / 发现 / 书源管理 / 详情 / 阅读 / 账号
  • 搜索:结果按书合并(同一本在多个书源上只占一条,点开可以挑读哪个源);一次能搜多少书源由部署决定 —— 线上那份按页(免费计划每请求 10 毫秒 CPU),自建与容器一次搜完(见 DOCKER.md)
  • 换源:读到一半发现这个源的错字多 / 缺章,可以换到别的源接着读。书架记录与阅读位置一起搬,落点按章名对;对不上会如实说「从第一章开始」,而不是假装对上了
  • 阅读:滚动与翻页两种模式,翻页走 CSS 多栏排版(换字号、换窗口宽都不用重新分页);手势与键盘走同一套翻页;进度记到页
  • 显示设置:背景色 8 种 + 跟随主题、字号、行距、翻页动画、主题、强调色;字号有四个入口(面板、双指捏合、Ctrl+滚轮、键盘)
  • 章内搜索、书签(可带备注)、笔记、替换净化(浏览器端、渲染前应用、实时预览)
  • PWA:装到桌面、断网还能开(缓存界面与正在读的那本书)
  • 账号:书架 / 进度 / 书签 / 笔记 / 替换规则跟着账号走;书源是全局的

界面上的错误一律就地显示原因,而不是只给一句「出错了」。

书源管理

  • 导入 Legado 书源 JSON(裸数组或 {"sources":[...]}),多文件与拖放都行;逐条校验、逐条报拒绝原因
  • 同一个站点地址重复导入算更新:只刷规则,保留改过的名字、分组与启用状态
  • 启停单条或一批;按分组浏览、按名字 / 分组 / 状态 / 能力(搜索 / 发现 / 登录)筛
  • 登录态:跑一次 loginUrl 落库,之后每趟请求都带上;写了 loginUi 的源会在界面上渲染成表单
  • 列表接口 /api/sources 带 ETag,没变回 304

快速开始

npm install
npm run db:migrate    # 建本地 D1 表(首次、以及每次新增迁移后)
npm run dev           # 打开 http://127.0.0.1:8787

打开就是登录页 —— 整个应用需要登录,先注册一个账号。然后去「书源」页导入一份书源 JSON; 在那之前书架与搜索都是空的,这是对的。

npm test              # 单元测试(1135 项,Node 里秒级跑完)
npm run smoke         # 端到端冒烟(要另开终端,且本地服务开着;它只打真实 HTTP)
npm run typecheck     # 类型检查
npm run format:check  # 格式检查

三种跑法

方式 适合 入口
Cloudflare 两份 想要一个公网地址,不想自己维护进程 npm run deploy:all —— 页面发 Pages、接口发 Worker,两次独立部署;首次要建 D1 并跑远端迁移,步骤见 EXPERIENCE.md 的「部署」
自建 Node 不想依赖 Cloudflare,或者嫌免费计划每请求 10 毫秒的 CPU 太紧 npm run start:node(本机 SQLite,没有 CPU 上限)
Docker 想把依赖、Node 版本、数据目录封在一起 docker compose up -d --build —— 也是两份(页面 nginx + 接口 node),见 DOCKER.md

Cloudflare 上那两份是页面(Pages:public/ 的静态资源 + 一层把 /api 接回去的同源反代) 与接口(Worker:src/index.ts + D1)。分开部署的好处是改界面不必碰接口、改接口不必重发 页面;代价是两者之间多了一层反代(见 EXPERIENCE.md 里那一节)。

书源

本项目不提供、也不分发任何书源。规则引擎是中立的工具,指向哪个站点、抓取什么内容, 由使用者自行决定并自负其责 —— Legado、any-reader 这些项目也都是这么划线的。

请遵守目标站点的服务条款与 robots 协议,并注意所在地区的版权法规。 项目自带的「内置测试站点」只包含项目自己生成的内容,用于验证链路;它由 ENABLE_FIXTURE 控制,线上默认关闭。

目录结构

Dockerfile / Dockerfile.page       容器那两份:接口(node)与页面(nginx)
docker-compose.yml / page.nginx.conf  两个容器怎么拼起来、页面那层反代(用法见 DOCKER.md)
DOCKER.md                         容器部署:起法与参数、数据与备份、与 Cloudflare 那份的差异
pages/                            Cloudflare Pages 的两个约定文件(_worker.js / _routes.json)
EXPERIENCE.md                     实现细节与踩坑记录:能力总表、规则语义、沙箱、每轮改了什么、验证、接口
migrations/                       D1 迁移(按序号递增,不可回改已应用的)
public/                           前端(零依赖、无构建步骤)
src/                              服务端:路由 / 规则引擎 / 数据层 / 平台适配(逐文件说明见 EXPERIENCE.md)
test/                             单元测试(快的那些;全量扫描默认跳过)
scripts/                          冒烟、体检与探针

文档

文档 里面有什么
EXPERIENCE.md 工程经验与实现笔记。规则引擎每一处的语义与取舍、沙箱与全局对象、每一轮改了什么 / 为什么 / 怎么验、验证命令、接口清单
DOCKER.md 容器部署。起法与参数、数据放在哪与怎么备份、与 Cloudflare 那份的差异、实测记录
TODO.md 待办。每条写清「为什么 / 已经到哪一步 / 下一步做什么 / 怎么算做完」
src/changelog.ts 版本更新记录,/api/version 与界面「关于」页读它

许可

AGPL-3.0-or-later。LICENSE 是 AGPL-3.0 的标准原文,与 SPlayer 项目里那份逐字相同 (git hash-object LICENSE 两边都是 dbbe3558157f5861bff35dcb37b328b679b0ccfd)。 package.json 里的 SPDX 标识写的是 AGPL-3.0-or-later 而不是 -only:前者允许被许可方 选用后续版本,两者法律含义不同。

选 AGPL 而不是 MIT,是因为这是个网络服务:AGPL 第 13 条要求「用户通过网络与这个程序交互时 必须能拿到它的源代码」,这一条正好挡住「拿去做闭源 SaaS」。

部署时要做到这一条:前端页脚里有一个指向 https://github.com/hashiqi12138/reader-cloudflare 的「源代码」链接,而 npm run smoke 会断言它存在 —— 删掉 CI 就会红(许可义务靠「记得」是保不住的)。改仓库名或换地址时, 记得同步改 public/index.html 页脚里那一个链接:链接失效等于没履行。

AGPL 只约束本项目的代码,不改变上面「书源」那一条。

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages