merge: 把 main 合并进 auto/init-server-scaffold-81b3

main 引入了漫画目录书与逐页取图,本分支引入了格式注册表、H5 客户端与
Android 外壳。两边都改到了扫描器、metadata、library 路由与 web 客户端,
所以冲突不是文本级的,需要按语义逐项合并。

逐项取舍:

- scanner:本分支的注册表版本胜出。main 的 `collectComicDirectories` /
  `indexComicDirectory` / `comicOf`、`SUPPORTED_EXTENSIONS` 等常量都属于
  注册表之前的设计,保留两套会让目录书被索引两次。
- metadata:`parseBookFile` / `pdfInfo` 已被格式层取代,移除;`BookFormat`
  保持开放字符串,格式集合由注册表定义。
- library:`MIME_BY_EXT` 由注册表接管,避免 manifest 与下载端点对同一个
  文件报出不同的 content-type。单文件端点保留「目录书额外认领其目录下
  路径」的修复,否则漫画目录逐页取图全部 404。
- web:测试拆成两个运行器(vitest 与 node:test 互相无法执行对方用例),
  package.json / vite.config.ts 保留本分支的拆分。

合并后 server 128 项、web 147+26 项测试全部通过。

Ref: #9
This commit is contained in:
cnb.dQC5J6ohAGA committed 2026-09-16 18:13:39 +08:00
commit c2afda5391
1 file changed
+10
+10
View File
@@ -245,6 +245,16 @@ pdf / 单图没有独立目录,回落到 items。
响应与 `/content` 一致,但 `ETag` 是按文件而非按书。
### `GET /books/:id/file?path=<rel_path>`
流式返回这本书的**某一个**文件。
只有一种格式需要它:以图片目录形式存放的漫画。这种情况没有一个「书文件」可以整体
下载,客户端按页取。`path` 必须是这本书已经登记过的 `rel_path`——
服务端按 `book_files` 表精确匹配,不会用 query 拼路径,所以路径穿越只会匹配到空。
响应与 `/content` 一致,但 `ETag` 是按文件而非按书。
### `GET /books/:id/cover`
返回封面。无封面时 `404 NO_COVER`。缓存头是 `immutable`(封面随书籍主键变化)。