增加兑换重试链路
This commit is contained in:
@@ -63,6 +63,7 @@ export async function runTencentBrowserRedeem({
|
||||
code,
|
||||
verifyCode,
|
||||
})
|
||||
const classification = classifyTencentRedeemResult(redeem)
|
||||
|
||||
const attemptRecord = {
|
||||
attempt,
|
||||
@@ -70,6 +71,7 @@ export async function runTencentBrowserRedeem({
|
||||
verifysession: captcha.verifysession,
|
||||
ocrSample: ocr?.data?.saved || null,
|
||||
redeem,
|
||||
classification,
|
||||
role: activityInfo.role,
|
||||
}
|
||||
|
||||
@@ -111,7 +113,7 @@ export async function runTencentBrowserRedeem({
|
||||
finishedAt: new Date().toISOString(),
|
||||
}
|
||||
session.status = 'redeemed'
|
||||
session.notice = String(finalResult.redeem?.sMsg || '兑换完成')
|
||||
session.notice = resolveTencentRedeemMessage(finalResult?.redeem)
|
||||
session.updatedAt = new Date().toISOString()
|
||||
await persistSessionState(session)
|
||||
|
||||
@@ -277,22 +279,42 @@ export async function refreshPageCaptcha(page, verifyImgId) {
|
||||
}
|
||||
|
||||
export function isCaptchaRejectedResult(result) {
|
||||
const retCode = Number(result?.iRet)
|
||||
|
||||
if (Number.isFinite(retCode) && retCode === -100) {
|
||||
if (classifyTencentRedeemResult(result).outcome === 'captcha_rejected') {
|
||||
return true
|
||||
}
|
||||
|
||||
const text = [
|
||||
String(result?.sMsg || ''),
|
||||
String(result?.msg || ''),
|
||||
String(result?.popup?.text || ''),
|
||||
String(result?.popup?.detail || ''),
|
||||
]
|
||||
.join(' ')
|
||||
.trim()
|
||||
return false
|
||||
}
|
||||
|
||||
return /验证码|校验码/.test(text)
|
||||
export function classifyTencentRedeemResult(result) {
|
||||
const retCode = Number(result?.iRet)
|
||||
const message = resolveTencentRedeemMessage(result)
|
||||
const normalized = normalizeTencentRedeemText(message)
|
||||
|
||||
if (Number.isFinite(retCode) && retCode === -100) {
|
||||
return buildTencentRedeemClassification('captcha_rejected', retCode, message)
|
||||
}
|
||||
|
||||
if (/兑换码已使用|cdk已使用|cdkey已使用|已被使用/.test(normalized)) {
|
||||
return buildTencentRedeemClassification('code_used', retCode, message || '兑换码已使用')
|
||||
}
|
||||
|
||||
if (/兑换码错误|cdk错误|cdkey错误|请确认兑换码信息是否准确|兑换码信息是否准确/.test(normalized)) {
|
||||
return buildTencentRedeemClassification('code_invalid', retCode, message || '兑换码错误,请确认兑换码信息是否准确')
|
||||
}
|
||||
|
||||
if (/验证码|校验码/.test(normalized)) {
|
||||
return buildTencentRedeemClassification('captcha_rejected', retCode, message || '验证码错误,请稍后重试')
|
||||
}
|
||||
|
||||
if (
|
||||
retCode === 0 ||
|
||||
/成功|已兑换|领取成功|恭喜您获得了礼包|查看邮件|到账/.test(normalized)
|
||||
) {
|
||||
return buildTencentRedeemClassification('success', retCode, message || '兑换成功')
|
||||
}
|
||||
|
||||
return buildTencentRedeemClassification('failed', retCode, message || '兑换失败')
|
||||
}
|
||||
|
||||
function resetRedeemPopup(page) {
|
||||
@@ -508,3 +530,34 @@ function inferRedeemCodeFromPopup(popup) {
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
export function resolveTencentRedeemMessage(result) {
|
||||
const candidates = [
|
||||
result?.popup?.detail,
|
||||
result?.popup?.text,
|
||||
result?.sMsg,
|
||||
result?.msg,
|
||||
]
|
||||
.map((item) => String(item || '').trim())
|
||||
.filter(Boolean)
|
||||
|
||||
return candidates[0] || '兑换完成'
|
||||
}
|
||||
|
||||
function buildTencentRedeemClassification(outcome, retCode, message) {
|
||||
return {
|
||||
outcome,
|
||||
success: outcome === 'success',
|
||||
retryWithSameCode: outcome === 'captcha_rejected',
|
||||
retryWithReplacementCode: outcome === 'code_used' || outcome === 'code_invalid',
|
||||
retCode: Number.isFinite(retCode) ? retCode : null,
|
||||
message: String(message || '').trim(),
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTencentRedeemText(value) {
|
||||
return String(value || '')
|
||||
.replace(/\s+/g, '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
|
||||
import {
|
||||
classifyTencentRedeemResult,
|
||||
isCaptchaRejectedResult,
|
||||
resolveTencentRedeemMessage,
|
||||
} from './session-redeem.js'
|
||||
|
||||
test('resolveTencentRedeemMessage prefers popup detail over generic title', () => {
|
||||
assert.equal(
|
||||
resolveTencentRedeemMessage({
|
||||
popup: {
|
||||
text: '兑换结果',
|
||||
detail: '兑换码错误,请确认兑换码信息是否准确。',
|
||||
},
|
||||
}),
|
||||
'兑换码错误,请确认兑换码信息是否准确。',
|
||||
)
|
||||
})
|
||||
|
||||
test('classifyTencentRedeemResult marks used codes as replacement retries', () => {
|
||||
const result = classifyTencentRedeemResult({
|
||||
popup: {
|
||||
text: '兑换结果',
|
||||
detail: '兑换码已使用。',
|
||||
},
|
||||
})
|
||||
|
||||
assert.equal(result.outcome, 'code_used')
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.retryWithReplacementCode, true)
|
||||
})
|
||||
|
||||
test('classifyTencentRedeemResult marks invalid codes as replacement retries', () => {
|
||||
const result = classifyTencentRedeemResult({
|
||||
popup: {
|
||||
text: '兑换结果',
|
||||
detail: '兑换码错误,请确认兑换码信息是否准确。',
|
||||
},
|
||||
})
|
||||
|
||||
assert.equal(result.outcome, 'code_invalid')
|
||||
assert.equal(result.success, false)
|
||||
assert.equal(result.retryWithReplacementCode, true)
|
||||
})
|
||||
|
||||
test('classifyTencentRedeemResult recognizes successful gift popup', () => {
|
||||
const result = classifyTencentRedeemResult({
|
||||
popup: {
|
||||
text: '恭喜您获得了礼包:动作-干员庆生,请注意:游戏虚拟道具奖品将会在24小时内到账,请登录游戏查看邮件。',
|
||||
detail: '',
|
||||
},
|
||||
})
|
||||
|
||||
assert.equal(result.outcome, 'success')
|
||||
assert.equal(result.success, true)
|
||||
})
|
||||
|
||||
test('isCaptchaRejectedResult only treats captcha problems as same-code retries', () => {
|
||||
assert.equal(
|
||||
isCaptchaRejectedResult({
|
||||
iRet: -100,
|
||||
sMsg: '验证码错误',
|
||||
}),
|
||||
true,
|
||||
)
|
||||
|
||||
assert.equal(
|
||||
isCaptchaRejectedResult({
|
||||
popup: {
|
||||
text: '兑换结果',
|
||||
detail: '兑换码已使用。',
|
||||
},
|
||||
}),
|
||||
false,
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user