Files
reader/docs
cnb.dQC5J6ohAGA 664141f0f1 feat: 支持 txt 与漫画等多种格式,格式层改为注册表
原先只认 .epub 和 .pdf,本地书库里占很大比重的 txt 长篇与漫画
(cbz、图片目录)会整片「消失」—— 用户能看到文件在 NAS 上,却在
书架里找不到,这是最让人困惑的一类问题。

格式列表硬编码在三处(扫描器白名单、parseBookFile 分支、content-type
映射表),加一种格式要同时改三处,漏掉任何一处就得到一个「扫到了但读不
出来」的安静 bug。这次把格式收进注册表,并补齐四种格式。

新增格式
- cbz / zip:按包内页序自然排序翻页,扫描时不解压到磁盘
- 漫画目录:一个目录一本书,子目录为卷,支持卷/页两级寻址
- txt:UTF-8 严格解码失败才回退 GB18030(UTF-16 BOM 也识别),
  按中文网文章节标题分章,正文可按章节或字节偏移读取
- 单张图片按单页读物入库
- 明确不支持 cbr/rar:需要非自由解压实现,与单容器约束冲突

格式层
- registry.ts 定义 handler 契约(parse/manifest/asset)与扩展名路由,
  扫描器与 HTTP 层只与它对话;扩展名白名单、能力声明、遍历过滤都自动派生
- zip-reader.ts 自研只读 ZIP,只用 node:zlib。JsZip 会把整包解压进内存,
  而漫画动辄几百 MB,首次扫描真实漫画库会 OOM
- natural-sort.ts 自研自然排序:page10 必须排在 page2 之后,
  否则整本漫画的阅读顺序是乱的;不用 localeCompare 是因为 ICU 行为
  在不同平台上不一致
- epub 章节返回前重写章节内的相对资源引用,否则 WebView 里图片/字体/
  样式全部 404;绝对 URL、data: URI 与文内锚点保持原样,脚注不会坏

修复
- 目录型读物认领后,其内部文件从索引中排除,否则同一部漫画会以
  「系列 + 每卷 + 每页」的形式重复出现
- 目录认领顺序改为从外往里:反过来的话一部漫画会变成 N 本独立卷
- 主键新增原地编辑规则:txt/漫画没有内嵌标识,追加一章会算出新 id
  并把读者进度留在旧记录上。现在同路径原地编辑算更新,移动/重命名
  仍走内容哈希规则,所以进度都保得住
- 损坏的 .cbz 仍然入库并记录失败原因,而不是静默从书架消失
- PDF 不再用正则猜页数(会匹配到无关的 /Count 并报出错误页数,
  让客户端分页错乱),改为诚实上报 null
- 清理已迁出的 parseBookFile / pdfInfo / SUPPORTED_EXTENSIONS

测试
- 新增 65 个用例(共 92 个):真实 zip 与真实文件,不用 mock;
  fixtures 由测试自己生成,不需要签入二进制
- 覆盖自然排序、编码探测、ZIP 边界(ZIP64/加密/超大条目)、
  目录认领、原地编辑、只读约束、各格式的读取端点
2026-09-16 14:31:15 +08:00
..