From 0afa9518140d3d860ba32644257a0d1119214c70 Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Sat, 30 May 2026 02:24:57 +0800 Subject: [PATCH 1/2] fix: parse latest GPC log entry by timestamp --- .../background/steps/fill-plus-checkout.js | 25 ++++++++++++------- ...us-checkout-billing-tab-resolution.test.js | 12 ++++++--- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/flows/openai/background/steps/fill-plus-checkout.js b/flows/openai/background/steps/fill-plus-checkout.js index 5b9a009..9b7cadc 100644 --- a/flows/openai/background/steps/fill-plus-checkout.js +++ b/flows/openai/background/steps/fill-plus-checkout.js @@ -225,15 +225,20 @@ const cardModeButton = modeButtons.find((element) => /卡密充值/.test(textOf(element))); const freeModeButton = modeButtons.find((element) => /免费充值/.test(textOf(element))); const bodyText = String(document.body?.innerText || document.documentElement?.innerText || '').replace(/\r/g, ''); + const rawTextOf = (element) => String(element?.innerText || element?.textContent || element?.value || ''); const logNodes = Array.from(document.querySelectorAll('[class*="log"], [id*="log"], .design-log, .logs, pre, code')); - const logText = logNodes.map(textOf).filter(Boolean).join('\n') || bodyText; + const logText = logNodes.map(rawTextOf).map((text) => text.trim()).filter(Boolean).join('\n') || bodyText; const extractLastLogLine = (rawText = '') => { - const lines = String(rawText || '') - .split(/\n+/) - .map((line) => line.replace(/\s+/g, ' ').trim()) + const normalizeLogLine = (line = '') => String(line || '').replace(/\s+/g, ' ').trim(); + const ignoredLinePattern = /^(?:GPC Plus 充值|系统全自动出号|限量\d+份|自助购买卡密通道|实时进度|免费池|付费池|模式:|任务:|未开始|导出|充值模式|填写卡密|Access Token|开始 Plus 充值|停止当前任务|页面已就绪)$/i; + const timestampEntries = String(rawText || '') + .replace(/\r/g, '') + .match(/\[\d{2}:\d{2}:\d{2}\][\s\S]*?(?=\s*\[\d{2}:\d{2}:\d{2}\]|$)/g); + const entries = (timestampEntries && timestampEntries.length ? timestampEntries : String(rawText || '').split(/\n+/)) + .map(normalizeLogLine) .filter(Boolean) - .filter((line) => !/^(?:GPC Plus 充值|系统全自动出号|限量\d+份|自助购买卡密通道|实时进度|免费池|付费池|模式:|任务:|未开始|导出|充值模式|填写卡密|Access Token|开始 Plus 充值|停止当前任务|页面已就绪)$/i.test(line)); - return lines[lines.length - 1] || ''; + .filter((line) => !ignoredLinePattern.test(line)); + return entries[entries.length - 1] || ''; }; const lastLogLine = extractLastLogLine(logText) || extractLastLogLine(bodyText); const cardInputs = Array.from(document.querySelectorAll('input.card-key-seg, input[placeholder*="XXXXXXXX"], input[maxlength="8"]')) @@ -266,11 +271,13 @@ function getGpcLastLogSummary(pageState = {}) { const rawText = String(pageState.lastLogLine || pageState.logText || pageState.bodyText || ''); - const lines = rawText - .split(/\n+/) + const timestampEntries = rawText + .replace(/\r/g, '') + .match(/\[\d{2}:\d{2}:\d{2}\][\s\S]*?(?=\s*\[\d{2}:\d{2}:\d{2}\]|$)/g); + const entries = (timestampEntries && timestampEntries.length ? timestampEntries : rawText.split(/\n+/)) .map((line) => line.replace(/\s+/g, ' ').trim()) .filter(Boolean); - const line = lines[lines.length - 1] || ''; + const line = entries[entries.length - 1] || ''; if (!line) { return ''; } diff --git a/tests/plus-checkout-billing-tab-resolution.test.js b/tests/plus-checkout-billing-tab-resolution.test.js index 796b2db..680039d 100644 --- a/tests/plus-checkout-billing-tab-resolution.test.js +++ b/tests/plus-checkout-billing-tab-resolution.test.js @@ -1058,7 +1058,10 @@ test('GPC billing restarts when start button returns without subscription done', const { events, executor, pageHarness } = createGpcPageExecutorHarness([ { startButtonText: '开始 Plus 充值', logText: 'SYSTEM 页面已就绪' }, { startButtonText: '任务进行中', logText: '处理中' }, - { startButtonText: '开始 Plus 充值', logText: 'SYSTEM\n卡密次数不足,任务已停止' }, + { + startButtonText: '开始 Plus 充值', + logText: '[02:17:28] ACTION 任务已提交 [02:17:28] SYSTEM 排队中,等待 worker 调度... [02:17:31] SUCCESS [02/09] 购买短信号码:+6283******846 [02:17:59] ERROR 卡密次数不足,任务已停止', + }, { startButtonText: '任务进行中', logText: '第二次处理中' }, { startButtonText: '开始 Plus 充值', logText: '订阅完成', hasSubscriptionDone: true }, ]); @@ -1071,7 +1074,8 @@ test('GPC billing restarts when start button returns without subscription done', assert.equal(pageHarness.clicks.length, 2); assert.equal(events.logs.some((entry) => /准备再次启动/.test(entry.message)), true); - assert.equal(events.logs.some((entry) => /准备再次启动.*最近日志:卡密次数不足,任务已停止/.test(entry.message)), true); + assert.equal(events.logs.some((entry) => /准备再次启动.*最近日志:\[02:17:59\] ERROR 卡密次数不足,任务已停止/.test(entry.message)), true); + assert.equal(events.logs.some((entry) => /最近日志:\[02:17:28\] ACTION/.test(entry.message)), false); assert.equal(events.completed.length, 1); }); @@ -1099,7 +1103,7 @@ test('GPC billing collapses repeated running status logs with a multiplier', asy test('GPC billing fails current round without restart when account has no trial eligibility', async () => { const { events, executor, pageHarness } = createGpcPageExecutorHarness([ - { startButtonText: '开始 Plus 充值', logText: 'SYSTEM\n该账户没有试用资格', noTrial: true }, + { startButtonText: '开始 Plus 充值', logText: '[02:20:00] ACTION 任务开始执行... [02:20:09] ERROR 该账户没有试用资格', noTrial: true }, ]); await assert.rejects( @@ -1108,7 +1112,7 @@ test('GPC billing fails current round without restart when account has no trial plusCheckoutSource: 'gpc-helper', plusCheckoutTabId: 77, }), - /PLUS_CHECKOUT_NON_FREE_TRIAL::.*该账户没有试用资格.*最近日志:该账户没有试用资格/ + /PLUS_CHECKOUT_NON_FREE_TRIAL::.*该账户没有试用资格.*最近日志:\[02:20:09\] ERROR 该账户没有试用资格/ ); assert.equal(pageHarness.clicks.length, 0); From 8c2cb2f8e0aa800fe2a263e4a76f6543309530a1 Mon Sep 17 00:00:00 2001 From: QLHazyCoder <2825305047@qq.com> Date: Sat, 30 May 2026 02:35:07 +0800 Subject: [PATCH 2/2] fix: stop GPC flow on no-trial logs --- .../background/steps/fill-plus-checkout.js | 13 ++++++++++ ...us-checkout-billing-tab-resolution.test.js | 25 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/flows/openai/background/steps/fill-plus-checkout.js b/flows/openai/background/steps/fill-plus-checkout.js index 9b7cadc..1674567 100644 --- a/flows/openai/background/steps/fill-plus-checkout.js +++ b/flows/openai/background/steps/fill-plus-checkout.js @@ -289,6 +289,18 @@ return summary ? ` 最近日志:${summary}` : ''; } + function hasGpcNoTrialFailure(pageState = {}) { + if (pageState.noTrial) { + return true; + } + const text = normalizeText([ + pageState.lastLogLine, + pageState.logText, + pageState.bodyText, + ].filter(Boolean).join(' ')); + return /(?:该|此|当前)?账[户号].{0,12}(?:没有|无|不具备).{0,8}试用资格|(?:没有|无|不具备).{0,8}试用资格/.test(text); + } + async function ensureGpcCardMode(tabId) { if (!chrome?.scripting?.executeScript) { throw new Error('步骤 7:当前运行环境不支持脚本注入,无法切换 GPC 卡密充值模式。'); @@ -485,6 +497,7 @@ while (Date.now() <= deadline) { throwIfStopped(); const pageState = await inspectGpcPortalPage(tabId); + pageState.noTrial = hasGpcNoTrialFailure(pageState); const buttonText = normalizeText(pageState.startButtonText); await collectStatusLog(pageState, buttonText); diff --git a/tests/plus-checkout-billing-tab-resolution.test.js b/tests/plus-checkout-billing-tab-resolution.test.js index 680039d..ae0d559 100644 --- a/tests/plus-checkout-billing-tab-resolution.test.js +++ b/tests/plus-checkout-billing-tab-resolution.test.js @@ -1119,6 +1119,31 @@ test('GPC billing fails current round without restart when account has no trial assert.equal(events.completed.length, 0); }); +test('GPC billing treats no-trial log text as terminal even when page flag is missing', async () => { + const { events, executor, pageHarness } = createGpcPageExecutorHarness([ + { startButtonText: '开始 Plus 充值', logText: 'SYSTEM 页面已就绪' }, + { startButtonText: '任务进行中', logText: '处理中' }, + { + startButtonText: '开始 Plus 充值', + logText: '[02:30:00] ACTION 任务开始执行... [02:30:18] ERROR 该账号没有试用资格', + noTrial: false, + }, + ]); + + await assert.rejects( + () => executor.executePlusCheckoutBilling({ + plusPaymentMethod: 'gpc-helper', + plusCheckoutSource: 'gpc-helper', + plusCheckoutTabId: 77, + }), + /PLUS_CHECKOUT_NON_FREE_TRIAL::.*该账户没有试用资格.*最近日志:\[02:30:18\] ERROR 该账号没有试用资格/ + ); + + assert.equal(pageHarness.clicks.length, 1); + assert.equal(events.logs.some((entry) => /准备再次启动/.test(entry.message)), false); + assert.equal(events.completed.length, 0); +}); + test('GPC billing times out when page never finishes', async () => { const { executor, pageHarness } = createGpcPageExecutorHarness([ { startButtonText: '任务进行中', logText: '处理中' },