v1.1.3: 网络层加固

- gfetch 失败自动重试 2 次(1s 间隔),应对代理/节点瞬断
- 重试耗尽降级原生 fetch(CDN 带 ACAO:* 可直连)
- 错误原因完整显示到面板,不再只报网络错误
- 背景: 17:25 mihomo 节点故障导致分片请求全部建连失败,
  Reqable 记录 remote.ip 为空 + mihomo 17:29 重启为证
This commit is contained in:
2026-10-08 17:42:58 +08:00
parent eaacacc8e0
commit 19a3828b18
+19 -4
View File
@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name 黄果短剧全集下载 // @name 黄果短剧全集下载
// @namespace huangguo-video // @namespace huangguo-video
// @version 1.1.2 // @version 1.1.3
// @description 在黄果短剧详情页添加"全集下载"按钮:下载全部集数 → 解密 → 转 MP4 → 打包 ZIP 存到 ~/Downloads,文件名为 剧名_集数 // @description 在黄果短剧详情页添加"全集下载"按钮:下载全部集数 → 解密 → 转 MP4 → 打包 ZIP 存到 ~/Downloads,文件名为 剧名_集数
// @author CETACEA // @author CETACEA
// @match https://huangguo.me/detail/* // @match https://huangguo.me/detail/*
@@ -22,7 +22,22 @@
const CONCURRENCY = 4; // 分片并发下载数 const CONCURRENCY = 4; // 分片并发下载数
/* ---------- 网络:GM_xmlhttpRequest promise 化(绕 CORS) ---------- */ /* ---------- 网络:GM_xmlhttpRequest promise 化(绕 CORS) ---------- */
function gfetch(url, type = 'text') { function gfetch(url, type = 'text', retries = 2) {
const fail = (why) => {
if (retries > 0) {
console.warn(`[全集下载] ${why},1s 后重试(剩 ${retries} 次):`, url);
return new Promise((r) => setTimeout(r, 1000))
.then(() => gfetch(url, type, retries - 1));
}
// 重试耗尽 → 降级原生 fetch(CDN 带 Access-Control-Allow-Origin: * 可直连)
console.warn(`[全集下载] GM 失败,尝试原生 fetch:`, url);
return fetch(url).then((resp) => {
if (!resp.ok) throw new Error(`HTTP ${resp.status}: ${url.slice(0, 100)}`);
return type === 'arraybuffer' ? resp.arrayBuffer() : resp.text();
}).catch((e) => {
throw new Error(`${why}(且 fetch 兜底失败:${e.message}): ${url.slice(0, 120)}`);
});
};
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
GM_xmlhttpRequest({ GM_xmlhttpRequest({
method: 'GET', method: 'GET',
@@ -32,8 +47,8 @@
onload: (r) => (r.status >= 200 && r.status < 300 onload: (r) => (r.status >= 200 && r.status < 300
? resolve(type === 'arraybuffer' ? r.response : r.responseText) ? resolve(type === 'arraybuffer' ? r.response : r.responseText)
: reject(new Error(`HTTP ${r.status}: ${url.slice(0, 100)}`))), : reject(new Error(`HTTP ${r.status}: ${url.slice(0, 100)}`))),
onerror: () => reject(new Error(`网络错误: ${url.slice(0, 100)}`)), onerror: () => fail(`网络错误`).then(resolve, reject),
ontimeout: () => reject(new Error(`超时: ${url.slice(0, 100)}`)), ontimeout: () => fail(`超时30s`).then(resolve, reject),
}); });
}); });
} }