feat: 添加邮件时间戳解析功能,优化邮件轮询逻辑,支持时间过滤
This commit is contained in:
+6
-4
@@ -1751,14 +1751,14 @@ async function submitVerificationCode(step, code) {
|
||||
return result || {};
|
||||
}
|
||||
|
||||
async function resolveVerificationStep(step, state, mail) {
|
||||
async function resolveVerificationStep(step, state, mail, options = {}) {
|
||||
const stateKey = getVerificationCodeStateKey(step);
|
||||
const rejectedCodes = new Set();
|
||||
if (state[stateKey]) {
|
||||
rejectedCodes.add(state[stateKey]);
|
||||
}
|
||||
|
||||
let nextFilterAfterTimestamp = null;
|
||||
let nextFilterAfterTimestamp = options.filterAfterTimestamp ?? null;
|
||||
const maxSubmitAttempts = 3;
|
||||
|
||||
for (let attempt = 1; attempt <= maxSubmitAttempts; attempt++) {
|
||||
@@ -1799,6 +1799,7 @@ async function resolveVerificationStep(step, state, mail) {
|
||||
async function executeStep4(state) {
|
||||
const mail = getMailConfig(state);
|
||||
if (mail.error) throw new Error(mail.error);
|
||||
const stepStartedAt = Date.now();
|
||||
const signupTabId = await getTabId('signup-page');
|
||||
if (!signupTabId) {
|
||||
throw new Error('认证页面标签页已关闭,无法继续步骤 4。');
|
||||
@@ -1850,7 +1851,7 @@ async function executeStep4(state) {
|
||||
});
|
||||
}
|
||||
|
||||
await resolveVerificationStep(4, state, mail);
|
||||
await resolveVerificationStep(4, state, mail, { filterAfterTimestamp: stepStartedAt });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1921,6 +1922,7 @@ async function executeStep6(state) {
|
||||
async function executeStep7(state) {
|
||||
const mail = getMailConfig(state);
|
||||
if (mail.error) throw new Error(mail.error);
|
||||
const stepStartedAt = Date.now();
|
||||
const authTabId = await getTabId('signup-page');
|
||||
|
||||
if (authTabId) {
|
||||
@@ -1964,7 +1966,7 @@ async function executeStep7(state) {
|
||||
});
|
||||
}
|
||||
|
||||
await resolveVerificationStep(7, state, mail);
|
||||
await resolveVerificationStep(7, state, mail, { filterAfterTimestamp: stepStartedAt });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+79
-3
@@ -82,15 +82,82 @@ function getCurrentMailIds() {
|
||||
return ids;
|
||||
}
|
||||
|
||||
function normalizeMinuteTimestamp(timestamp) {
|
||||
if (!Number.isFinite(timestamp) || timestamp <= 0) return 0;
|
||||
const date = new Date(timestamp);
|
||||
date.setSeconds(0, 0);
|
||||
return date.getTime();
|
||||
}
|
||||
|
||||
function parseMail163Timestamp(rawText) {
|
||||
const text = (rawText || '').replace(/\s+/g, ' ').trim();
|
||||
if (!text) return null;
|
||||
|
||||
let match = text.match(/(\d{4})年(\d{1,2})月(\d{1,2})日\s+(\d{1,2}):(\d{2})/);
|
||||
if (match) {
|
||||
const [, year, month, day, hour, minute] = match;
|
||||
return new Date(
|
||||
Number(year),
|
||||
Number(month) - 1,
|
||||
Number(day),
|
||||
Number(hour),
|
||||
Number(minute),
|
||||
0,
|
||||
0
|
||||
).getTime();
|
||||
}
|
||||
|
||||
match = text.match(/\b(\d{1,2}):(\d{2})\b/);
|
||||
if (match) {
|
||||
const [, hour, minute] = match;
|
||||
const now = new Date();
|
||||
return new Date(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate(),
|
||||
Number(hour),
|
||||
Number(minute),
|
||||
0,
|
||||
0
|
||||
).getTime();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getMailTimestamp(item) {
|
||||
const candidates = [];
|
||||
const timeCell = item.querySelector('.e00[title], [title*="年"][title*=":"]');
|
||||
if (timeCell?.getAttribute('title')) candidates.push(timeCell.getAttribute('title'));
|
||||
if (timeCell?.textContent) candidates.push(timeCell.textContent);
|
||||
|
||||
const titledNodes = item.querySelectorAll('[title]');
|
||||
titledNodes.forEach((node) => {
|
||||
const title = node.getAttribute('title');
|
||||
if (title) candidates.push(title);
|
||||
});
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const parsed = parseMail163Timestamp(candidate);
|
||||
if (parsed) return parsed;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Email Polling
|
||||
// ============================================================
|
||||
|
||||
async function handlePollEmail(step, payload) {
|
||||
const { senderFilters, subjectFilters, maxAttempts, intervalMs, excludeCodes = [] } = payload;
|
||||
const { senderFilters, subjectFilters, maxAttempts, intervalMs, excludeCodes = [], filterAfterTimestamp = 0 } = payload;
|
||||
const excludedCodeSet = new Set(excludeCodes.filter(Boolean));
|
||||
const filterAfterMinute = normalizeMinuteTimestamp(Number(filterAfterTimestamp) || 0);
|
||||
|
||||
log(`步骤 ${step}:开始轮询 163 邮箱(最多 ${maxAttempts} 次)`);
|
||||
if (filterAfterMinute) {
|
||||
log(`步骤 ${step}:仅尝试 ${new Date(filterAfterMinute).toLocaleString('zh-CN', { hour12: false })} 及之后时间的邮件。`);
|
||||
}
|
||||
|
||||
// Click inbox in sidebar to ensure we're in inbox view
|
||||
log(`步骤 ${step}:正在等待侧边栏加载...`);
|
||||
@@ -142,8 +209,16 @@ async function handlePollEmail(step, payload) {
|
||||
|
||||
for (const item of allItems) {
|
||||
const id = item.getAttribute('id') || '';
|
||||
const mailTimestamp = getMailTimestamp(item);
|
||||
const mailMinute = normalizeMinuteTimestamp(mailTimestamp || 0);
|
||||
const passesTimeFilter = !filterAfterMinute || (mailMinute && mailMinute >= filterAfterMinute);
|
||||
const shouldBypassOldSnapshot = Boolean(filterAfterMinute && passesTimeFilter && mailMinute > 0);
|
||||
|
||||
if (!useFallback && existingMailIds.has(id)) continue;
|
||||
if (!passesTimeFilter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!useFallback && !shouldBypassOldSnapshot && existingMailIds.has(id)) continue;
|
||||
|
||||
const senderEl = item.querySelector('.nui-user');
|
||||
const sender = senderEl ? senderEl.textContent.toLowerCase() : '';
|
||||
@@ -164,7 +239,8 @@ async function handlePollEmail(step, payload) {
|
||||
seenCodes.add(code);
|
||||
persistSeenCodes();
|
||||
const source = useFallback && existingMailIds.has(id) ? '回退匹配邮件' : '新邮件';
|
||||
log(`步骤 ${step}:已找到验证码:${code}(来源:${source},主题:${subject.slice(0, 40)})`, 'ok');
|
||||
const timeLabel = mailTimestamp ? `,时间:${new Date(mailTimestamp).toLocaleString('zh-CN', { hour12: false })}` : '';
|
||||
log(`步骤 ${step}:已找到验证码:${code}(来源:${source}${timeLabel},主题:${subject.slice(0, 40)})`, 'ok');
|
||||
|
||||
// Delete this email via right-click menu, WAIT for it to finish before returning
|
||||
await deleteEmail(item, step);
|
||||
|
||||
Reference in New Issue
Block a user