feat: 清单存 /s/ 路径,重开程序跳过画廊页解析

画廊页要翻 ?p=N 分页收集全部页(206 张 = 11 次请求)。之前每次运行都要
重新解析一遍,即使本地已经有完整清单。现改为:

- 清单升级到 v2,pageMap 存每页的 /s/ 路径与文件名
- 下载前先按 gid 找磁盘上的画廊目录,读到 v2 清单就直接下载,不请求画廊页
- 解析完立即写清单,崩溃/关程序也不丢

为什么存 /s/ 路径而不是 hath 直链:
hath 直链是「随机子域 + 随机端口 + 时间戳签名」,每次都变且会过期,
存下来也没法用(手动复制到浏览器打开,下次同样失效)。/s/ 路径是稳定的。

降级策略(都实测过):
- v1 旧清单(没有 pageMap)→ 重新解析,并把清单升级成 v2
- 清单 JSON 损坏 → 重新解析,跑完重写一份正常的
- 清单的 /s/ 路径过期(待下页几乎全失败)→ 自动重新解析一次再重试
- 找不到清单但目录存在(换了目录模板)→ 按新模板名/旧标题名找到目录继续

另外 pageMap 里存了 meta,否则从清单重建时目录模板(如 {artist}/...)
会退化到兜底值,算出来的目录名和之前对不上。

测试从 68 增至 74,其中 TestManifestSkipsReparse 实测第二次运行
画廊页请求数为 0 增量。
This commit is contained in:
2026-10-09 08:58:18 +08:00
parent 9241c5dcd1
commit 0623c55407
4 changed files with 753 additions and 77 deletions
+40 -5
View File
@@ -247,24 +247,57 @@ https://oclzqqk.gyktyewfonyf.hath.network:39656/h/4e9af9f.../keystamp=1791448200
### 画廊目录清单(.ehdl.json)
每个画廊目录下会写一份 `.ehdl.json`:
每个画廊目录下会写一份 `.ehdl.json`。首次下载时(解析完画廊页)写入,之后每次跑都会更新。
```json
{
"version": 1,
"version": 2,
"gid": "4239274",
"token": "55e069b6b9",
"title": "[Noxe] 0820 Qingxiao",
"totalPages": 206,
"donePages": [1, 2, 3, 5],
"failedPages": [4],
"pageMap": {
"1": { "page": 1, "file": "001.png", "sPath": "/s/bb06b5db77/4239250-1", "finished": true },
"2": { "page": 2, "file": "002.png", "sPath": "/s/cc11ee22ff/4239250-2", "finished": true }
},
"meta": { "artist": "Noxe", "group": "CriticalHAI", "tags": ["qingxiao"] },
"updatedAt": 1791475732842
}
```
作用:断点续传的依据是「文件在且非空」,但那有个盲区 —— 如果 `state.json`
丢了,程序就不知道这个画廊**原本应该有多少张**。清单补上了这个认知,
扫目录就能算出「应该 206 张,现在只有 4 张」。
**关键作用:跳过重新解析。**
画廊页要翻 `?p=N` 分页收集全部页(206 张 = 11 次请求)。有了 `pageMap` 里的
`/s/` 路径,程序重启后可以直接下载,不必再解析画廊页。
```
首次:解析画廊页(11次) → 写清单 → 下载
重开:读清单(0次请求) → 直接下载
```
**为什么 `pageMap` 存 `/s/` 路径而不是图片直链?**
hath 直链是 `随机子域 + 随机端口 + 时间戳签名`,每次请求都不一样且会过期 ——
存下来也没法用(就算手动复制到浏览器打开,下次也会失效)。
`/s/` 路径是稳定的,用它每次实时换取直链。
### 清单失效怎么办
如果清单里的 `/s/` 路径过期了(EH 换 key、或作者更新了画廊),下载会失败。
程序会自动检测:**待下载页几乎全失败 → 重新解析一次画廊页 → 用新路径重试**。
日志里会看到:
```
画廊 4239274 用本地清单(206 页),跳过重新解析
画廊 4239274:本地清单的页面路径似乎已失效,重新解析画廊页
画廊 4239274:重新解析后全部下载完成
```
如果重新解析后还是失败(画廊真被删了/受限制了),才会标记「部分失败」。
这时候按标题手动搜一次重新导入即可。
状态文件:
- Windows:`%APPDATA%\EH Downloader\state.json`
@@ -316,6 +349,8 @@ go test -race ./... # 竞态检测
- **全局限流**(并发穿透验证 + 精确计时)
- **整轮扫尾**(首轮 4 次重试全挂 → 扫尾救回 / 永久失败 → partial)
- **画廊清单**(读写往返、目录扫描、state.json 丢失后的恢复)
- **清单优先**:第二次下载完全跳过画廊页解析(实测画廊页请求数不增)
- **清单降级**:v1 旧清单 / 损坏清单 / `/s/` 路径过期,三种情况都能正确回退
## 免责声明