gacha-calendar-core 0.10.7 → 0.10.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core.mjs +149 -32
- package/package.json +1 -1
package/core.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// 用途:缓存里记录"这份数据是哪版插件产出的"。更新插件后首次启动,据此**强制**刷新一次
|
|
5
5
|
// (不看自动刷新开关)——因为有些改动(悬停格式、来源地址、样式、解析器)不刷新就看不到效果。
|
|
6
6
|
// 写入时机见 engine-api.js 的 refresh();判定见 60-helpers.js 的 autoRefreshPlan()。
|
|
7
|
-
const PLUGIN_VERSION = "0.10.
|
|
7
|
+
const PLUGIN_VERSION = "0.10.8";
|
|
8
8
|
//#endregion
|
|
9
9
|
|
|
10
10
|
//#region config
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
// 其中 recommend 组含逐期「角色/武器活动唤取」公告,正文带 ✦活动时间✦ 起止
|
|
62
62
|
const WUWA_NOTICE_ENTRY = "https://aki-gm-resources-back.aki-game.com/gamenotice/G152/76402e5b20be2c39f095a152090afddc/entrypoint.json";
|
|
63
63
|
const WUWA_BWIKI_URL = "https://wiki.biligame.com/wutheringwaves/api.php?action=parse&page=%E9%A6%96%E9%A1%B5%2F%E8%A7%92%E8%89%B2%E8%BD%AE%E6%8D%A2%E6%B1%A0&prop=text&format=json&formatversion=2";
|
|
64
|
+
// 鸣潮 Bwiki 活动日历页(已从**默认活动源降级为备选**,2026-10-01):
|
|
65
|
+
// 该页仍可解析(parseWuwaCalendar 能抽到 11 条),但**已停更**——最新一条结束于 2026/9/29,
|
|
66
|
+
// 没有当期 3.7 的活动,所以不改解析器,只把它挪到备选。
|
|
67
|
+
const WUWA_EVENT_BWIKI_URL = "https://wiki.biligame.com/wutheringwaves/api.php?action=parse&page=%E9%A6%96%E9%A1%B5%2F%E6%B4%BB%E5%8A%A8%E6%97%A5%E5%8E%86&prop=text&format=json&formatversion=2";
|
|
64
68
|
// 绝区零官网公告(api-takumi-static content_v2_user,经 host 代理;无 CORS、无需登录):
|
|
65
69
|
// iChanId=279(公告频道)返回逐条公告正文(sIntro/sContent),其中「X.Y版本限时频段(上/下期)」
|
|
66
70
|
// 含该期精确起止 + 限定 S 级代理人/音擎;起点写「版本更新后」时取同版本「更新公告」的 dtStartTime。
|
|
@@ -128,19 +132,27 @@
|
|
|
128
132
|
},
|
|
129
133
|
{
|
|
130
134
|
id: "wuwa",
|
|
131
|
-
parserVersion:
|
|
135
|
+
parserVersion: 2,
|
|
132
136
|
name: "鸣潮",
|
|
133
137
|
icon: "https://storage.moegirl.org.cn/moegirl/commons/2/29/WutheringWavesIcon.png!/fw/64",
|
|
134
138
|
source: "官方公告",
|
|
135
|
-
// 默认卡池源=官方公告(aki-gm-resources-back,经 host
|
|
139
|
+
// 默认卡池源=官方公告(aki-gm-resources-back,经 host 代理):
|
|
140
|
+
// entrypoint.json → <dir>/zh-Hans.json,其 `recommend` 组里 tag=7 为逐期「角色/武器活动唤取」,
|
|
141
|
+
// 条目自带 `startTimeMs`/`endTimeMs` 绝对时间戳(不再解析正文,见 parseWuwaNotice)。
|
|
136
142
|
// 无当期公告或抓取失败时由抓取器自动回退 Bwiki 角色轮换池;也可在设置中手动切 Bwiki(备选)
|
|
137
143
|
url: WUWA_NOTICE_ENTRY,
|
|
138
144
|
altSources: [
|
|
139
145
|
{ label: "Bwiki 角色轮换池", url: WUWA_BWIKI_URL, fetcher: "wuwa-bwiki" }
|
|
140
146
|
],
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
// 活动源:**默认=同一份官方公告**(`recommend` 组里 tag=5 为限时活动,见 parseWuwaRecommendEvents),
|
|
148
|
+
// 与卡池同址 → 一次请求复用两侧数据。
|
|
149
|
+
// ⚠️ 2026-10-01 改:Bwiki 活动日历页**已停更**(最新一条结束于 2026/9/29,无 3.7 内容),
|
|
150
|
+
// 所以把它从默认**降级为备选**(eventAltSources),仍可在设置里手动切回。
|
|
151
|
+
eventUrl: WUWA_NOTICE_ENTRY,
|
|
152
|
+
eventSource: "官方公告",
|
|
153
|
+
eventAltSources: [
|
|
154
|
+
{ label: "Bwiki 活动日历", url: WUWA_EVENT_BWIKI_URL, fetcher: "wuwa-event-bwiki" }
|
|
155
|
+
]
|
|
144
156
|
},
|
|
145
157
|
{
|
|
146
158
|
id: "arknights",
|
|
@@ -1384,8 +1396,13 @@ export function createEngine(env) {
|
|
|
1384
1396
|
return null;
|
|
1385
1397
|
}
|
|
1386
1398
|
|
|
1387
|
-
// 鸣潮官方公告解析:从全量公告(game/activity/recommend)中取"覆盖当前时刻"
|
|
1388
|
-
//
|
|
1399
|
+
// 鸣潮官方公告解析:从全量公告(game/activity/recommend)中取"覆盖当前时刻"的「角色活动唤取」。
|
|
1400
|
+
//
|
|
1401
|
+
// ⚠️ 时间**必须用 JSON 里的绝对时间戳** `startTimeMs` / `endTimeMs`,不要再去解析正文。
|
|
1402
|
+
// 正文写的是 `✦活动时间✦ 3.7版本更新后 ~ 2026年10月22日09:59(服务器时间)` ——
|
|
1403
|
+
// 起始端是**版本标签**而非绝对日期,旧实现用 `(\d{4})年(\d{1,2})月…` 匹配整段 → 恒失败 →
|
|
1404
|
+
// 卡池侧返回 null(2026-10-01 实测:官方 JSON 已带 3 个在开角色池,却显示"未公布")。
|
|
1405
|
+
// 现在源站直接给了时间戳,比解析正文更准,也不受措辞漂移影响。
|
|
1389
1406
|
function parseWuwaNotice(list, now = nowMs()) {
|
|
1390
1407
|
const groups = [list?.game, list?.activity, list?.recommend].filter(Array.isArray);
|
|
1391
1408
|
const stripH = (s) => String(s || "")
|
|
@@ -1396,41 +1413,88 @@ export function createEngine(env) {
|
|
|
1396
1413
|
const pools = [];
|
|
1397
1414
|
for (const arr of groups) {
|
|
1398
1415
|
for (const it of arr) {
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
const
|
|
1402
|
-
const
|
|
1403
|
-
if (!
|
|
1404
|
-
const sTs =
|
|
1405
|
-
|
|
1416
|
+
// 标题可能是 "[但愿长圆如此夜]\n角色活动唤取" / "「玉阙玄华」武器活动唤取"
|
|
1417
|
+
const title = stripH(it.tabTitle || it.title || "").replace(/\s+/g, " ").trim();
|
|
1418
|
+
const isChar = /角色活动唤取/.test(title);
|
|
1419
|
+
const isWeapon = /武器活动唤取/.test(title);
|
|
1420
|
+
if (!isChar && !isWeapon) continue;
|
|
1421
|
+
const sTs = Number(it.startTimeMs), eTs = Number(it.endTimeMs);
|
|
1422
|
+
if (!Number.isFinite(sTs) || !Number.isFinite(eTs)) continue;
|
|
1406
1423
|
if (sTs > now || eTs < now) continue; // 只要当期覆盖
|
|
1407
1424
|
const name = title
|
|
1408
1425
|
.replace(/\s*(?:角色|武器)活动唤取\s*$/, "")
|
|
1409
1426
|
.replace(/^[\[【「]\s*/, "")
|
|
1410
1427
|
.replace(/\s*[\]】」]$/, "")
|
|
1411
1428
|
.trim();
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1429
|
+
if (!name) continue;
|
|
1430
|
+
// 类型名(外显用):标题尾部那一段,如 `角色活动唤取` / `武器活动唤取`
|
|
1431
|
+
const type = isChar ? "角色活动唤取" : "武器活动唤取";
|
|
1432
|
+
// 角色名:正文开头那句「活动期间,5星角色「心」,4星角色「卜灵」、「桃祈」、「釉瑚」唤取概率限时提升!」
|
|
1433
|
+
// 用 [^。!?\n]+ 限在一句内,避免把后面「唤取说明」里的角色也带进来
|
|
1434
|
+
const text = stripH(it.content || "");
|
|
1435
|
+
const upM = text.match(/活动期间,([^。!?\n]+?)唤取概率限时提升/);
|
|
1436
|
+
const roles = upM
|
|
1437
|
+
? [...new Set([...upM[1].matchAll(/[「【]([^」】]+)[」】]/g)].map((x) => x[1].trim()).filter(Boolean))].join("、")
|
|
1438
|
+
: "";
|
|
1439
|
+
pools.push({ name, type, isChar, roles, startTs: sTs, endTs: eTs });
|
|
1415
1440
|
}
|
|
1416
1441
|
}
|
|
1417
1442
|
const cur = pools.filter((p) => p.isChar && p.name);
|
|
1418
1443
|
if (cur.length === 0) return null;
|
|
1419
|
-
|
|
1420
|
-
const
|
|
1444
|
+
// 外显与窗口取**结束最早**的那个池(与 selectCurrent 的 first 同口径)。
|
|
1445
|
+
const first = cur.slice().sort((a, b) => a.endTs - b.endTs)[0];
|
|
1446
|
+
// 角色:**先拆成单个名字再去重**,然后合并。
|
|
1447
|
+
// ⚠️ 别写成 `new Set(cur.map(p => p.roles))` —— 那样比较的是"整串"(各池的 4★ 名单相同
|
|
1448
|
+
// 但 5★ 不同 → 整串不同 → 重复留下)。拆开才能把三池共有的 4★ 去成一份。
|
|
1449
|
+
// 顺序 = 各池依次展开(5★ 在前、4★ 共有名在后),去重后即 `心、千咲、尤诺、卜灵、桃祈、釉瑚`。
|
|
1450
|
+
const roles = [...new Set(cur.flatMap((p) => p.roles.split("、").map((s) => s.trim()).filter(Boolean)))].join("、");
|
|
1421
1451
|
const fmt = (ts) => {
|
|
1422
1452
|
const d = new Date(ts);
|
|
1423
1453
|
return `${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")} ${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
|
|
1424
1454
|
};
|
|
1425
1455
|
const raw = fmtWindow(first.startTs, first.endTs);
|
|
1426
|
-
//
|
|
1427
|
-
|
|
1456
|
+
// 悬停:首行=卡池类型(与卡片外显同源),随后每池"池名:角色"一行;窗口相同则时间只在末尾写一遍;
|
|
1457
|
+
// 按结束时间升序。**类型行只在本源补**,不动全站共用的 buildPoolHover(它按约定对 0/1 池返回 "")。
|
|
1458
|
+
const poolHover = buildPoolHover(cur.map((p) => ({
|
|
1428
1459
|
name: p.name,
|
|
1429
1460
|
label: `${p.name}\uFF1A${p.roles || "-"}`,
|
|
1430
1461
|
startTs: p.startTs,
|
|
1431
1462
|
endTs: p.endTs
|
|
1432
1463
|
})));
|
|
1433
|
-
|
|
1464
|
+
const bannerHover = poolHover ? `${first.type}\n${poolHover}` : "";
|
|
1465
|
+
// **外显用卡池类型**(`角色活动唤取`),不用某一个池名:
|
|
1466
|
+
// 角色是多池合并的,若外显挂"但愿长圆如此夜",卡片就成了"标题只说一个池、角色却是三个池的合成"。
|
|
1467
|
+
// 与用户 2026-09-30 定的统一口径一致(国服显示 `限时限定招募`、异环显示 `限定棋盘`)。
|
|
1468
|
+
// 具体池名在悬停里逐条列出,不丢信息。
|
|
1469
|
+
return { banner: first.type, roles, bannerDates: raw, bannerDatesRaw: raw, startTs: first.startTs, endTs: first.endTs, bannerHover };
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// 鸣潮官方活动解析:同一份全量公告的 `recommend` 组里,`tag === 7` 是卡池、**`tag === 5` 是限时活动**。
|
|
1473
|
+
// 活动条目形如 tabTitle="[团团勇者大乱斗]休闲活动",同样带绝对时间戳。
|
|
1474
|
+
// 这是 2026-10-01 起鸣潮活动的**默认源**——Bwiki 活动日历页已停更(最新一条结束于 2026/9/29),
|
|
1475
|
+
// 而官方源有当期 3.7 的活动,且与卡池同源、同一次请求即可拿到两侧数据。
|
|
1476
|
+
function parseWuwaRecommendEvents(list, now = nowMs()) {
|
|
1477
|
+
const arr = Array.isArray(list?.recommend) ? list.recommend : [];
|
|
1478
|
+
const stripH = (s) => String(s || "")
|
|
1479
|
+
.replace(/<br\s*\/?>/gi, "\n").replace(/<[^>]+>/g, " ")
|
|
1480
|
+
.replace(/ /g, " ").replace(/&/g, "&")
|
|
1481
|
+
.replace(/[ \t]+/g, " ").replace(/\n\s*\n+/g, "\n").trim();
|
|
1482
|
+
const events = [];
|
|
1483
|
+
for (const it of arr) {
|
|
1484
|
+
if (Number(it.tag) !== 5) continue; // 7=卡池;5=限时活动
|
|
1485
|
+
const name = stripH(it.tabTitle || "").replace(/\s+/g, " ").trim();
|
|
1486
|
+
if (!name) continue;
|
|
1487
|
+
const sTs = Number(it.startTimeMs), eTs = Number(it.endTimeMs);
|
|
1488
|
+
if (!Number.isFinite(sTs) || !Number.isFinite(eTs)) continue;
|
|
1489
|
+
if (sTs > now || eTs < now) continue;
|
|
1490
|
+
events.push({ name, cat: "", startTs: sTs, endTs: eTs });
|
|
1491
|
+
}
|
|
1492
|
+
if (events.length === 0) return null;
|
|
1493
|
+
const sorted = sortEventItems(events);
|
|
1494
|
+
if (sorted.length === 0) return null;
|
|
1495
|
+
const primary = pickEventPrimary(sorted) || sorted[0];
|
|
1496
|
+
const dates = fmtWindow(primary.startTs, primary.endTs);
|
|
1497
|
+
return { banner: primary.name, bannerDates: dates, bannerDatesRaw: dates, eventHover: buildEventHover(sorted) };
|
|
1434
1498
|
}
|
|
1435
1499
|
|
|
1436
1500
|
// 鸣潮卡池默认抓取器:官方公告(entrypoint → 目录 → zh-Hans.json 全量)优先;
|
|
@@ -1444,8 +1508,18 @@ export function createEngine(env) {
|
|
|
1444
1508
|
let list = null;
|
|
1445
1509
|
try { list = await proxyFetchJson(dir + "zh-Hans.json", ref); } catch { list = null; }
|
|
1446
1510
|
if (!list || typeof list !== "object") list = await proxyFetchJson(dir + "notice.json", ref);
|
|
1511
|
+
// **同一份 JSON 里卡池(tag=7)与活动(tag=5)都在** → 顺带把活动字段也返回。
|
|
1512
|
+
// 这是"统一来源注册表"里写明的同址复用契约:卡池载荷带 event 字段时,
|
|
1513
|
+
// refresh 不再为活动侧另抓一次(否则同址条目每轮多一个请求)。
|
|
1514
|
+
// ⚠️ 我重写解析时一度只返回卡池字段,导致鸣潮每轮请求从 1 次变成 2 次 —— 已补回。
|
|
1515
|
+
// 活动侧仍保留自己的抓取器(fetchWuwaEventsOfficial):卡池侧失败、或用户在设置里
|
|
1516
|
+
// 单独选活动来源时,活动侧要能自己抓、自己报错(解耦不变)。
|
|
1517
|
+
const ev = parseWuwaRecommendEvents(list, now);
|
|
1518
|
+
const evFields = ev
|
|
1519
|
+
? { event: ev.banner, eventDates: ev.bannerDates || "", eventDatesRaw: ev.bannerDatesRaw || ev.bannerDates || "", eventHover: ev.eventHover || "" }
|
|
1520
|
+
: {};
|
|
1447
1521
|
const d = parseWuwaNotice(list, now);
|
|
1448
|
-
if (d) return d;
|
|
1522
|
+
if (d) return { ...d, ...evFields };
|
|
1449
1523
|
} catch { /* 官方失败 → Bwiki 备选 */ }
|
|
1450
1524
|
const apiUrl = WUWA_BWIKI_URL + (WUWA_BWIKI_URL.includes("?") ? "&" : "?") + "origin=*";
|
|
1451
1525
|
const res = await transportFetchRaw(apiUrl, { signal, headers: rawHeaders(apiUrl) });
|
|
@@ -1456,6 +1530,25 @@ export function createEngine(env) {
|
|
|
1456
1530
|
return parseWuwaPool(html);
|
|
1457
1531
|
}
|
|
1458
1532
|
|
|
1533
|
+
// 鸣潮活动默认抓取器:抓同一份官方公告,取 `recommend` 组里 tag=5 的限时活动。
|
|
1534
|
+
// 与卡池侧同一 URL(entrypoint.json),所以 refresh 的同址复用会让两侧共用一次请求。
|
|
1535
|
+
async function fetchWuwaEventsOfficial(entryUrl) {
|
|
1536
|
+
const ref = "https://aki-gm-resources.aki-game.com/";
|
|
1537
|
+
const ej = await proxyFetchJson(entryUrl, ref);
|
|
1538
|
+
const contentUrl = Array.isArray(ej?.contentUrl) ? ej.contentUrl[0] : "";
|
|
1539
|
+
const dir = contentUrl ? contentUrl.replace(/[^/]*$/, "") : String(entryUrl).replace(/[^/]*$/, "");
|
|
1540
|
+
const list = await proxyFetchJson(dir + "zh-Hans.json", ref);
|
|
1541
|
+
if (!list || typeof list !== "object") throw new Error("wuwa-event-bad-json");
|
|
1542
|
+
const d = parseWuwaRecommendEvents(list, nowMs());
|
|
1543
|
+
if (!d) return null;
|
|
1544
|
+
return {
|
|
1545
|
+
event: d.banner,
|
|
1546
|
+
eventDates: d.bannerDates || "",
|
|
1547
|
+
eventDatesRaw: d.bannerDatesRaw || d.bannerDates || "",
|
|
1548
|
+
eventHover: d.eventHover || ""
|
|
1549
|
+
};
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1459
1552
|
// 绝区零官网公告解析:从公告频道(iChanId=279)取「X.Y版本限时频段(上/下期)」,选覆盖当前时刻的一期。
|
|
1460
1553
|
// 公告形如:sIntro="本期代理人与音擎调频活动时间为:3.2版本更新后 ~ 2026/09/30 11:59",
|
|
1461
1554
|
// sContent 内含「活动期间,限定S级代理人[克拉蕾(电·锋御)]、[南宫羽(以太·击破)]…」。
|
|
@@ -3707,9 +3800,13 @@ export function createEngine(env) {
|
|
|
3707
3800
|
d ? { event: d.banner, eventDates: d.bannerDates || "", eventDatesRaw: d.bannerDatesRaw || d.bannerDates || "" } : null
|
|
3708
3801
|
)
|
|
3709
3802
|
},
|
|
3710
|
-
//
|
|
3803
|
+
// 鸣潮:**默认=同一份官方公告**(`recommend` 组里 tag=5 为限时活动),与卡池同址
|
|
3804
|
+
// → 一次请求复用两侧数据(refresh 的同址复用优化)。
|
|
3805
|
+
// ⚠️ 2026-10-01 改:Bwiki 活动日历**已停更**(最新一条结束于 2026/9/29),
|
|
3806
|
+
// 所以把官方提为默认、Bwiki 降级为备选(`wuwa-event-bwiki`),仍可在设置里手动切回。
|
|
3711
3807
|
wuwa: {
|
|
3712
|
-
default:
|
|
3808
|
+
default: (url, signal) => fetchWuwaEventsOfficial(url, signal),
|
|
3809
|
+
"wuwa-event-bwiki": mkMediaWiki((html) => {
|
|
3713
3810
|
const d = parseWuwaCalendar(html);
|
|
3714
3811
|
return d ? { event: d.banner, eventDates: d.bannerDates || "", eventDatesRaw: d.bannerDatesRaw || d.bannerDates || "", eventHover: d.eventHover || "" } : null;
|
|
3715
3812
|
})
|
|
@@ -3825,9 +3922,21 @@ export function createEngine(env) {
|
|
|
3825
3922
|
let evData = null;
|
|
3826
3923
|
let eventFail = null;
|
|
3827
3924
|
if (source.eventUrl) {
|
|
3828
|
-
//
|
|
3925
|
+
// 活动侧自己的抓取器(与卡池侧各自独立选择,来源可以完全不同)。
|
|
3926
|
+
// 注意:**默认路径就是"活动侧自己抓"** —— 解耦是常态,复用只是优化。
|
|
3829
3927
|
const evFetcher = eventFetcherFor(source, eventUrl);
|
|
3830
|
-
|
|
3928
|
+
// ── 同址复用:**命中才触发**的分支 ──────────────────────────────
|
|
3929
|
+
// 只有两个条件**同时**成立才复用,否则一律走下面的独立抓取:
|
|
3930
|
+
// ① 两侧地址相同(同一次请求本来就能拿到两侧数据)
|
|
3931
|
+
// ② 卡池那次的载荷**确实带了活动字段**(`event`)
|
|
3932
|
+
// 复用只是"省掉一次本来会重复的请求",**不是解耦的腿**:
|
|
3933
|
+
// 活动侧的抓取器、失败归因、来源选择都保持独立(见 §53)。
|
|
3934
|
+
//
|
|
3935
|
+
// 2026-10-01 实测(11 内置条目逐条):复用支命中 5 次
|
|
3936
|
+
// (wuwa / nte / r1999 / ba-cn / ba-global —— 它们的卡池载荷本身就含活动字段),
|
|
3937
|
+
// 其余 6 条目(zzz / genshin / hsr / arknights / ba-jp / endfield)走独立抓取。
|
|
3938
|
+
const reuseSameUrl = eventUrl === gachaUrl && !!(g.data && g.data.event);
|
|
3939
|
+
if (reuseSameUrl) {
|
|
3831
3940
|
// 同 URL:活动字段就在卡池载荷里,不重复抓
|
|
3832
3941
|
evData = {
|
|
3833
3942
|
event: g.data.event,
|
|
@@ -3836,12 +3945,20 @@ export function createEngine(env) {
|
|
|
3836
3945
|
eventHover: g.data.eventHover || ""
|
|
3837
3946
|
};
|
|
3838
3947
|
} else if (eventUrl === gachaUrl && !evFetcher) {
|
|
3839
|
-
//
|
|
3840
|
-
//
|
|
3841
|
-
//
|
|
3842
|
-
//
|
|
3948
|
+
// ── 同址但活动侧**没有自己的抓取器**(该条目就只有这一份载荷可用)──
|
|
3949
|
+
// ⚠️ **这一支不是死代码,别删**:**自定义条目**可以没有注册抓取器 ——
|
|
3950
|
+
// `getAllEntries` 里 customEntries 带 `custom:true` + 用户填的 url/eventUrl,
|
|
3951
|
+
// 而 GACHA_FETCHERS / EVENT_FETCHERS 里没有它们的 id → `eventFetcherFor` 返回 null。
|
|
3952
|
+
// 语义:
|
|
3953
|
+
// · 卡池那次成功但载荷没有活动字段 → 该侧就是"未公布"(nomatch),
|
|
3954
|
+
// 且**不发**那次注定被 CORS 拦的直连;
|
|
3955
|
+
// · 卡池那次本身失败 → 沿用**同一次请求**的失败原因(如 HTTP 567),
|
|
3956
|
+
// 而不是笼统报"无可用来源"。
|
|
3957
|
+
// 教训:我一度只按"内置 11 条目命中 0 次"就判它死代码 —— **错的**,
|
|
3958
|
+
// 把"当前没命中"当成了"不可达"。`_batch1` A3 用合成条目(sim-nte)刻意覆盖这两条语义。
|
|
3843
3959
|
eventFail = g.data ? { kind: "nomatch" } : (g.fail || { kind: "nomatch" });
|
|
3844
3960
|
} else {
|
|
3961
|
+
// 活动侧独立抓取(含"地址不同"与"同址但载荷无活动字段"两种情形)
|
|
3845
3962
|
const ev = await resolveSide("event", {
|
|
3846
3963
|
fetcher: evFetcher,
|
|
3847
3964
|
url: eventUrl,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gacha-calendar-core",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.8",
|
|
4
4
|
"description": "二游活动/卡池排期抓取核心:11 款游戏的来源注册表 + 解析器 + 刷新编排 + 缓存降级。零依赖、零宿主环境依赖,任何 JS 运行时(浏览器扩展 background / Tauri / JavaScriptCore / ArkTS 嵌入式引擎)都能跑。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./core.mjs",
|