feat: 检索页聚合搜索,修复中文关键词导致主进程崩溃

一次查询所有已启用数据源并按源分组展示,每组最多 5 条,
超出时提供「查看更多」跳转到该源的单源检索。

同时修复聚合并发暴露出的网络层问题:

- 主进程崩溃:Memory of the World 会把搜索关键词原样回写进
  ETag 响应头,中文关键词下 Electron net.fetch 在内部 emit
  回调里抛 ByteString TypeError,await 无法捕获,主进程直接
  崩溃且 Promise 永不 settle。现拦截该类异常并回退到 undici。
- OpenLibrary / LibGen 要求关键词至少 3 字符,否则返回 422。
  改为前置校验,直接返回空结果加说明,耗时从 14s 降到 3ms。
- 重试只针对可自愈错误(超时/5xx/限流),不再为 4xx 白等;
  重试时收紧超时,避免最坏耗时翻倍。镜像轮询类源关闭内层
  重试,换镜像交给 tryMirrors/raceMirrors。
- 网络错误文案改为可读提示,不再把整条 URL 抛给用户。
- Sci-Hub 非 DOI 关键词返回空而非报错,避免聚合结果刷屏。

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
lofyer
2026-07-26 11:59:40 +08:00
co-authored by factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
parent 1a1288ce18
commit de3e1d8a44
10 changed files with 484 additions and 72 deletions
+4 -5
View File
@@ -66,7 +66,7 @@ function extractPdf(html, base) {
async function fetchSciHub(base, doi) {
const url = `${base}/${doi}`;
const html = await fetchText(url);
const html = await fetchText(url, { retries: 0 });
if (isChallenge(html)) {
throw new Error(`${base} 启用了人机验证`);
}
@@ -97,13 +97,12 @@ module.exports = {
return { items: [], maxPage: 1, page: 1 };
},
// 仅支持 DOI。非 DOI 关键词返回空而不是抛错,
// 这样在聚合搜索里不会被当成"失败的源"刷屏。
async search(keyword, page) {
page = clampPage(page);
const doi = normalizeDoi(keyword);
if (!doi) return { items: [], maxPage: 1, page: 1 };
if (!DOI_RE.test(doi)) {
throw new Error('Sci-Hub 仅支持 DOI 查询,例如 10.1038/nature12373');
}
if (!doi || !DOI_RE.test(doi)) return { items: [], maxPage: 1, page: 1, note: '仅支持 DOI 查询,例如 10.1038/nature12373' };
const r = await resolve(doi);
return {
items: [{