重构修改2925获取邮箱
This commit is contained in:
+259
-148
@@ -1,4 +1,4 @@
|
||||
// content/mail-2925.js — Content script for 2925 Mail (steps 4, 7)
|
||||
// content/mail-2925.js - Content script for 2925 Mail (steps 4, 8)
|
||||
// Injected dynamically on: 2925.com
|
||||
|
||||
const MAIL2925_PREFIX = '[MultiPage:mail-2925]';
|
||||
@@ -37,19 +37,28 @@ async function persistSeenCodes() {
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'POLL_EMAIL') {
|
||||
resetStopState();
|
||||
handlePollEmail(message.step, message.payload).then(result => {
|
||||
handlePollEmail(message.step, message.payload).then((result) => {
|
||||
sendResponse(result);
|
||||
}).catch(err => {
|
||||
}).catch((err) => {
|
||||
if (isStopError(err)) {
|
||||
log(`步骤 ${message.step}:已被用户停止。`, 'warn');
|
||||
sendResponse({ stopped: true, error: err.message });
|
||||
return;
|
||||
}
|
||||
|
||||
log(`步骤 ${message.step}:邮箱轮询失败:${err.message}`, 'warn');
|
||||
sendResponse({ error: err.message });
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
if (message.type === 'DELETE_ALL_EMAILS') {
|
||||
Promise.resolve(deleteAllMailboxEmails(message.step)).catch(() => {});
|
||||
sendResponse({ ok: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
const MAIL_ITEM_SELECTORS = [
|
||||
@@ -64,13 +73,67 @@ const MAIL_ITEM_SELECTORS = [
|
||||
'[class*="list-item"]',
|
||||
'li[class*="mail"]',
|
||||
];
|
||||
const MAIL_REFRESH_SELECTOR = '[class*="refresh"], [title*="鍒锋柊"], [aria-label*="鍒锋柊"], [class*="Refresh"]';
|
||||
const MAIL_ITEM_SELECTOR_GROUP = MAIL_ITEM_SELECTORS.join(', ');
|
||||
const MAIL_REFRESH_SELECTORS = [
|
||||
'[class*="refresh"]',
|
||||
'[title*="刷新"]',
|
||||
'[aria-label*="刷新"]',
|
||||
'[class*="Refresh"]',
|
||||
];
|
||||
const MAIL_INBOX_SELECTORS = [
|
||||
'a[href*="mailList"]',
|
||||
'[class*="inbox"]',
|
||||
'[class*="Inbox"]',
|
||||
'[title*="鏀朵欢绠?]',
|
||||
'[title*="收件箱"]',
|
||||
];
|
||||
const MAIL_DELETE_SELECTORS = [
|
||||
'[class*="delete"]',
|
||||
'[title*="删除"]',
|
||||
'[aria-label*="删除"]',
|
||||
'[class*="Delete"]',
|
||||
];
|
||||
const MAIL_SELECT_ALL_SELECTORS = [
|
||||
'input[type="checkbox"]',
|
||||
'[role="checkbox"]',
|
||||
'.el-checkbox__input',
|
||||
'.el-checkbox',
|
||||
'label[class*="checkbox"]',
|
||||
'[class*="checkbox"]',
|
||||
];
|
||||
const MAIL_ACTION_CANDIDATE_SELECTORS = 'button, [role="button"], a, label, span, div';
|
||||
|
||||
function normalizeNodeText(value) {
|
||||
return String(value || '').replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
function isVisibleNode(node) {
|
||||
if (!node) return false;
|
||||
if (node.hidden) return false;
|
||||
|
||||
const style = typeof window.getComputedStyle === 'function'
|
||||
? window.getComputedStyle(node)
|
||||
: null;
|
||||
if (style && (style.display === 'none' || style.visibility === 'hidden')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rect = typeof node.getBoundingClientRect === 'function'
|
||||
? node.getBoundingClientRect()
|
||||
: null;
|
||||
if (rect && rect.width <= 0 && rect.height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isMailItemNode(node) {
|
||||
return Boolean(node?.closest?.(MAIL_ITEM_SELECTOR_GROUP));
|
||||
}
|
||||
|
||||
function resolveActionTarget(node) {
|
||||
return node?.closest?.('button, [role="button"], a, label, .el-checkbox, .el-checkbox__input') || node || null;
|
||||
}
|
||||
|
||||
function findMailItems() {
|
||||
for (const selector of MAIL_ITEM_SELECTORS) {
|
||||
@@ -82,20 +145,81 @@ function findMailItems() {
|
||||
return [];
|
||||
}
|
||||
|
||||
function findRefreshButton() {
|
||||
return document.querySelector(MAIL_REFRESH_SELECTOR);
|
||||
}
|
||||
|
||||
function findInboxLink() {
|
||||
for (const selector of MAIL_INBOX_SELECTORS) {
|
||||
const node = document.querySelector(selector);
|
||||
if (node) {
|
||||
return node;
|
||||
function findActionBySelectors(selectors = []) {
|
||||
for (const selector of selectors) {
|
||||
const candidates = document.querySelectorAll(selector);
|
||||
for (const candidate of candidates) {
|
||||
const target = resolveActionTarget(candidate);
|
||||
if (!isVisibleNode(target) || isMailItemNode(target)) {
|
||||
continue;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findToolbarActionButton(patterns = [], selectors = []) {
|
||||
const directMatch = findActionBySelectors(selectors);
|
||||
if (directMatch) {
|
||||
return directMatch;
|
||||
}
|
||||
|
||||
const candidates = document.querySelectorAll(MAIL_ACTION_CANDIDATE_SELECTORS);
|
||||
for (const candidate of candidates) {
|
||||
const target = resolveActionTarget(candidate);
|
||||
if (!isVisibleNode(target) || isMailItemNode(target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const text = normalizeNodeText(target.innerText || target.textContent || '');
|
||||
const label = normalizeNodeText(target.getAttribute?.('aria-label') || target.getAttribute?.('title') || '');
|
||||
if (patterns.some((pattern) => pattern.test(text) || pattern.test(label))) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function findRefreshButton() {
|
||||
return findToolbarActionButton([
|
||||
/刷新/i,
|
||||
/refresh/i,
|
||||
], MAIL_REFRESH_SELECTORS);
|
||||
}
|
||||
|
||||
function findInboxLink() {
|
||||
return findActionBySelectors(MAIL_INBOX_SELECTORS);
|
||||
}
|
||||
|
||||
function findDeleteButton() {
|
||||
return findToolbarActionButton([
|
||||
/删除/i,
|
||||
/delete/i,
|
||||
], MAIL_DELETE_SELECTORS);
|
||||
}
|
||||
|
||||
function findSelectAllControl() {
|
||||
return findActionBySelectors(MAIL_SELECT_ALL_SELECTORS);
|
||||
}
|
||||
|
||||
function isCheckboxChecked(node) {
|
||||
const checkbox = node?.matches?.('input[type="checkbox"], [role="checkbox"]')
|
||||
? node
|
||||
: node?.querySelector?.('input[type="checkbox"], [role="checkbox"]');
|
||||
if (checkbox?.checked === true) {
|
||||
return true;
|
||||
}
|
||||
if (String(checkbox?.getAttribute?.('aria-checked') || '').toLowerCase() === 'true') {
|
||||
return true;
|
||||
}
|
||||
return Boolean(
|
||||
node?.classList?.contains('is-checked')
|
||||
|| node?.classList?.contains('checked')
|
||||
);
|
||||
}
|
||||
|
||||
function getMailItemText(item) {
|
||||
if (!item) return '';
|
||||
const contentCell = item.querySelector('td.content, .content, .mail-content');
|
||||
@@ -112,11 +236,11 @@ function getMailItemText(item) {
|
||||
|
||||
function getMailItemTimeText(item) {
|
||||
const timeEl = item?.querySelector('.date-time-text, [class*="date-time"], [class*="time"], td.time');
|
||||
return (timeEl?.textContent || '').replace(/\s+/g, ' ').trim();
|
||||
return normalizeNodeText(timeEl?.textContent || '');
|
||||
}
|
||||
|
||||
function normalizeMailIdentityPart(value) {
|
||||
return (value || '').replace(/\s+/g, ' ').trim().toLowerCase();
|
||||
return normalizeNodeText(value).toLowerCase();
|
||||
}
|
||||
|
||||
function getMailItemId(item, index = 0) {
|
||||
@@ -148,82 +272,36 @@ function getCurrentMailIds(items = []) {
|
||||
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 matchesMailFilters(text, senderFilters, subjectFilters) {
|
||||
const lower = (text || '').toLowerCase();
|
||||
const senderMatch = senderFilters.some(filter => lower.includes(filter.toLowerCase()));
|
||||
const subjectMatch = subjectFilters.some(filter => lower.includes(filter.toLowerCase()));
|
||||
const lower = String(text || '').toLowerCase();
|
||||
const senderMatch = senderFilters.some((filter) => lower.includes(String(filter || '').toLowerCase()));
|
||||
const subjectMatch = subjectFilters.some((filter) => lower.includes(String(filter || '').toLowerCase()));
|
||||
return senderMatch || subjectMatch;
|
||||
}
|
||||
|
||||
function extractVerificationCode(text, strictChatGPTCodeOnly = false) {
|
||||
if (strictChatGPTCodeOnly) {
|
||||
const strictMatch = text.match(/your\s+chatgpt\s+code\s+is\s+(\d{6})/i);
|
||||
const strictMatch = String(text || '').match(/your\s+chatgpt\s+code\s+is\s+(\d{6})/i);
|
||||
return strictMatch ? strictMatch[1] : null;
|
||||
}
|
||||
|
||||
const matchCn = text.match(/(?:代码为|验证码[^0-9]*?)[\s::]*(\d{6})/);
|
||||
const normalized = String(text || '');
|
||||
|
||||
const matchCn = normalized.match(/(?:代码为|验证码[^0-9]*?)[\s::]*(\d{6})/);
|
||||
if (matchCn) return matchCn[1];
|
||||
|
||||
const matchChatGPT = text.match(/your\s+chatgpt\s+code\s+is\s+(\d{6})/i);
|
||||
const matchChatGPT = normalized.match(/your\s+chatgpt\s+code\s+is\s+(\d{6})/i);
|
||||
if (matchChatGPT) return matchChatGPT[1];
|
||||
|
||||
const matchEn = text.match(/code[:\s]+is[:\s]+(\d{6})|code[:\s]+(\d{6})/i);
|
||||
const matchEn = normalized.match(/code[:\s]+is[:\s]+(\d{6})|code[:\s]+(\d{6})/i);
|
||||
if (matchEn) return matchEn[1] || matchEn[2];
|
||||
|
||||
const match6 = text.match(/\b(\d{6})\b/);
|
||||
const match6 = normalized.match(/\b(\d{6})\b/);
|
||||
if (match6) return match6[1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractEmails(text) {
|
||||
const matches = text.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/ig) || [];
|
||||
return [...new Set(matches.map(item => item.toLowerCase()))];
|
||||
}
|
||||
|
||||
function emailMatchesTarget(candidate, targetEmail) {
|
||||
const normalizedCandidate = String(candidate || '').trim().toLowerCase();
|
||||
const normalizedTarget = String(targetEmail || '').trim().toLowerCase();
|
||||
return Boolean(normalizedCandidate && normalizedTarget && normalizedCandidate === normalizedTarget);
|
||||
}
|
||||
|
||||
function getTargetEmailMatchState(text, targetEmail) {
|
||||
const normalizedTarget = String(targetEmail || '').trim().toLowerCase();
|
||||
if (!normalizedTarget) {
|
||||
return { matches: true, hasExplicitEmail: false };
|
||||
}
|
||||
|
||||
const normalizedText = String(text || '').toLowerCase();
|
||||
if (normalizedText.includes(normalizedTarget)) {
|
||||
return { matches: true, hasExplicitEmail: true };
|
||||
}
|
||||
|
||||
const atIndex = normalizedTarget.indexOf('@');
|
||||
if (atIndex > 0) {
|
||||
const encodedTarget = `${normalizedTarget.slice(0, atIndex)}=${normalizedTarget.slice(atIndex + 1)}`;
|
||||
if (normalizedText.includes(encodedTarget)) {
|
||||
return { matches: true, hasExplicitEmail: true };
|
||||
}
|
||||
}
|
||||
|
||||
const emails = extractEmails(text);
|
||||
if (!emails.length) {
|
||||
return { matches: false, hasExplicitEmail: false };
|
||||
}
|
||||
|
||||
return {
|
||||
matches: emails.some(email => emailMatchesTarget(email, normalizedTarget)),
|
||||
hasExplicitEmail: true,
|
||||
};
|
||||
}
|
||||
|
||||
function parseMailItemTimestamp(item) {
|
||||
const timeText = getMailItemTimeText(item);
|
||||
if (!timeText) return null;
|
||||
@@ -236,7 +314,7 @@ function parseMailItemTimestamp(item) {
|
||||
return now.getTime();
|
||||
}
|
||||
|
||||
match = timeText.match(/(\d+)\s*分(?:钟)?前/);
|
||||
match = timeText.match(/(\d+)\s*分钟前/);
|
||||
if (match) {
|
||||
return now.getTime() - Number(match[1]) * 60 * 1000;
|
||||
}
|
||||
@@ -324,19 +402,70 @@ async function openMailAndGetMessageText(item) {
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteCurrentMailboxEmail(step) {
|
||||
try {
|
||||
const deleteButton = findDeleteButton();
|
||||
if (!deleteButton) {
|
||||
return false;
|
||||
}
|
||||
|
||||
simulateClick(deleteButton);
|
||||
await sleepRandom(200, 500);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn(MAIL2925_PREFIX, `Step ${step}: delete-current cleanup failed:`, err?.message || err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function openMailAndDeleteAfterRead(item, step) {
|
||||
simulateClick(item);
|
||||
try {
|
||||
await sleepRandom(1200, 2200);
|
||||
return document.body?.textContent || '';
|
||||
} finally {
|
||||
await deleteCurrentMailboxEmail(step);
|
||||
await returnToInbox();
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteAllMailboxEmails(step) {
|
||||
try {
|
||||
await returnToInbox();
|
||||
|
||||
const selectAllControl = findSelectAllControl();
|
||||
if (!selectAllControl) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isCheckboxChecked(selectAllControl)) {
|
||||
simulateClick(selectAllControl);
|
||||
await sleepRandom(200, 500);
|
||||
}
|
||||
|
||||
const deleteButton = findDeleteButton();
|
||||
if (!deleteButton) {
|
||||
return false;
|
||||
}
|
||||
|
||||
simulateClick(deleteButton);
|
||||
await sleepRandom(200, 500);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.warn(MAIL2925_PREFIX, `Step ${step}: delete-all cleanup failed:`, err?.message || err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshInbox() {
|
||||
const refreshBtn = document.querySelector(
|
||||
'[class*="refresh"], [title*="刷新"], [aria-label*="刷新"], [class*="Refresh"]'
|
||||
);
|
||||
const refreshBtn = findRefreshButton();
|
||||
if (refreshBtn) {
|
||||
simulateClick(refreshBtn);
|
||||
await sleepRandom(700, 1200);
|
||||
return;
|
||||
}
|
||||
|
||||
const inboxLink = document.querySelector(
|
||||
'a[href*="mailList"], [class*="inbox"], [class*="Inbox"], [title*="收件箱"]'
|
||||
);
|
||||
const inboxLink = findInboxLink();
|
||||
if (inboxLink) {
|
||||
simulateClick(inboxLink);
|
||||
await sleepRandom(700, 1200);
|
||||
@@ -349,27 +478,26 @@ async function handlePollEmail(step, payload) {
|
||||
subjectFilters,
|
||||
maxAttempts,
|
||||
intervalMs,
|
||||
filterAfterTimestamp = 0,
|
||||
excludeCodes = [],
|
||||
strictChatGPTCodeOnly = false,
|
||||
targetEmail = '',
|
||||
} = payload;
|
||||
} = payload || {};
|
||||
const excludedCodeSet = new Set(excludeCodes.filter(Boolean));
|
||||
const filterAfterMinute = normalizeMinuteTimestamp(Number(filterAfterTimestamp) || 0);
|
||||
|
||||
log(`步骤 ${step}:开始轮询 2925 邮箱(最多 ${maxAttempts} 次)`);
|
||||
if (filterAfterMinute) {
|
||||
log(`步骤 ${step}:仅尝试 ${new Date(filterAfterMinute).toLocaleString('zh-CN', { hour12: false })} 及之后时间的邮件。`);
|
||||
}
|
||||
|
||||
let initialItems = [];
|
||||
for (let i = 0; i < 20; i++) {
|
||||
let initialLoadUsedRefresh = false;
|
||||
|
||||
for (let i = 0; i < 20; i += 1) {
|
||||
initialItems = findMailItems();
|
||||
if (initialItems.length > 0) break;
|
||||
if (initialItems.length > 0) {
|
||||
break;
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
if (initialItems.length === 0) {
|
||||
initialLoadUsedRefresh = true;
|
||||
await returnToInbox();
|
||||
await refreshInbox();
|
||||
await sleep(2000);
|
||||
@@ -380,16 +508,16 @@ async function handlePollEmail(step, payload) {
|
||||
throw new Error('2925 邮箱列表未加载完成,请确认当前已打开收件箱。');
|
||||
}
|
||||
|
||||
const existingMailIds = getCurrentMailIds(initialItems);
|
||||
const knownMailIds = getCurrentMailIds(initialItems);
|
||||
log(`步骤 ${step}:邮件列表已加载,共 ${initialItems.length} 封邮件`);
|
||||
log(`步骤 ${step}:已记录当前 ${existingMailIds.size} 封旧邮件快照`);
|
||||
log(`步骤 ${step}:已记录当前 ${knownMailIds.size} 封旧邮件快照`);
|
||||
|
||||
const FALLBACK_AFTER = 3;
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
log(`步骤 ${step}:正在轮询 2925 邮箱,第 ${attempt}/${maxAttempts} 次`);
|
||||
|
||||
if (attempt > 1) {
|
||||
if (attempt > 1 || !initialLoadUsedRefresh) {
|
||||
await returnToInbox();
|
||||
await refreshInbox();
|
||||
await sleepRandom(900, 1500);
|
||||
@@ -398,78 +526,61 @@ async function handlePollEmail(step, payload) {
|
||||
const items = findMailItems();
|
||||
if (items.length > 0) {
|
||||
const useFallback = attempt > FALLBACK_AFTER;
|
||||
const newMailIds = new Set();
|
||||
|
||||
for (let index = 0; index < items.length; index++) {
|
||||
items.forEach((item, index) => {
|
||||
const itemId = getMailItemId(item, index);
|
||||
if (!knownMailIds.has(itemId)) {
|
||||
newMailIds.add(itemId);
|
||||
}
|
||||
});
|
||||
|
||||
for (let index = 0; index < items.length; index += 1) {
|
||||
const item = items[index];
|
||||
const itemId = getMailItemId(item, index);
|
||||
const isNewMail = newMailIds.has(itemId);
|
||||
const itemTimestamp = parseMailItemTimestamp(item);
|
||||
const itemMinute = normalizeMinuteTimestamp(itemTimestamp || 0);
|
||||
const passesTimeFilter = !filterAfterMinute || (itemMinute && itemMinute >= filterAfterMinute);
|
||||
const shouldBypassOldSnapshot = Boolean(filterAfterMinute && passesTimeFilter && itemMinute > 0);
|
||||
|
||||
if (!passesTimeFilter) {
|
||||
if (!useFallback && !isNewMail) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!useFallback && !shouldBypassOldSnapshot && existingMailIds.has(itemId)) {
|
||||
const previewText = getMailItemText(item);
|
||||
if (!matchesMailFilters(previewText, senderFilters, subjectFilters)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const text = getMailItemText(item);
|
||||
if (!matchesMailFilters(text, senderFilters, subjectFilters)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const previewEmails = extractEmails(text);
|
||||
const previewTargetState = getTargetEmailMatchState(text, targetEmail);
|
||||
const previewMatchesTarget = previewTargetState.matches;
|
||||
if (targetEmail && previewEmails.length > 0 && !previewMatchesTarget) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const code = extractVerificationCode(text, strictChatGPTCodeOnly);
|
||||
if (code && previewMatchesTarget) {
|
||||
if (excludedCodeSet.has(code)) {
|
||||
log(`步骤 ${step}:跳过排除的验证码:${code}`, 'info');
|
||||
continue;
|
||||
}
|
||||
if (seenCodes.has(code)) {
|
||||
log(`步骤 ${step}:跳过已处理过的验证码:${code}`, 'info');
|
||||
continue;
|
||||
}
|
||||
seenCodes.add(code);
|
||||
persistSeenCodes();
|
||||
const source = useFallback && existingMailIds.has(itemId) ? '回退匹配邮件' : '新邮件';
|
||||
const timeLabel = itemTimestamp ? `,时间:${new Date(itemTimestamp).toLocaleString('zh-CN', { hour12: false })}` : '';
|
||||
log(`步骤 ${step}:已找到验证码:${code}(来源:${source}${timeLabel})`, 'ok');
|
||||
await sleep(1000);
|
||||
return { ok: true, code, emailTimestamp: Date.now() };
|
||||
}
|
||||
|
||||
const openedText = await openMailAndGetMessageText(item);
|
||||
const previewCode = extractVerificationCode(previewText, strictChatGPTCodeOnly);
|
||||
const openedText = await openMailAndDeleteAfterRead(item, step);
|
||||
const bodyCode = extractVerificationCode(openedText, strictChatGPTCodeOnly);
|
||||
const openedTargetState = getTargetEmailMatchState(openedText, targetEmail);
|
||||
if (targetEmail && openedTargetState.hasExplicitEmail && !openedTargetState.matches) {
|
||||
const candidateCode = bodyCode || previewCode;
|
||||
|
||||
if (!candidateCode) {
|
||||
continue;
|
||||
}
|
||||
if (bodyCode) {
|
||||
if (excludedCodeSet.has(bodyCode)) {
|
||||
log(`步骤 ${step}:跳过排除的验证码:${bodyCode}`, 'info');
|
||||
continue;
|
||||
}
|
||||
if (seenCodes.has(bodyCode)) {
|
||||
log(`步骤 ${step}:跳过已处理过的验证码:${bodyCode}`, 'info');
|
||||
continue;
|
||||
}
|
||||
seenCodes.add(bodyCode);
|
||||
persistSeenCodes();
|
||||
const source = useFallback && existingMailIds.has(itemId) ? '回退匹配邮件正文' : '新邮件正文';
|
||||
const timeLabel = itemTimestamp ? `,时间:${new Date(itemTimestamp).toLocaleString('zh-CN', { hour12: false })}` : '';
|
||||
log(`步骤 ${step}:已在邮件正文中找到验证码:${bodyCode}(来源:${source}${timeLabel})`, 'ok');
|
||||
await sleep(1000);
|
||||
return { ok: true, code: bodyCode, emailTimestamp: Date.now() };
|
||||
|
||||
if (excludedCodeSet.has(candidateCode)) {
|
||||
log(`步骤 ${step}:跳过排除的验证码:${candidateCode}`, 'info');
|
||||
continue;
|
||||
}
|
||||
if (seenCodes.has(candidateCode)) {
|
||||
log(`步骤 ${step}:跳过已处理过的验证码:${candidateCode}`, 'info');
|
||||
continue;
|
||||
}
|
||||
|
||||
seenCodes.add(candidateCode);
|
||||
persistSeenCodes();
|
||||
const source = useFallback && !isNewMail
|
||||
? (bodyCode ? '回退匹配邮件正文' : '回退匹配邮件')
|
||||
: (bodyCode ? '新邮件正文' : '新邮件');
|
||||
const timeLabel = itemTimestamp ? `,时间:${new Date(itemTimestamp).toLocaleString('zh-CN', { hour12: false })}` : '';
|
||||
log(`步骤 ${step}:已找到验证码:${candidateCode}(来源:${source}${timeLabel})`, 'ok');
|
||||
return { ok: true, code: candidateCode, emailTimestamp: Date.now() };
|
||||
}
|
||||
|
||||
items.forEach((item, index) => {
|
||||
knownMailIds.add(getMailItemId(item, index));
|
||||
});
|
||||
}
|
||||
|
||||
if (attempt === FALLBACK_AFTER + 1) {
|
||||
|
||||
@@ -695,6 +695,12 @@ function getPageTextSnapshot() {
|
||||
.trim();
|
||||
}
|
||||
|
||||
function getLoginVerificationDisplayedEmail() {
|
||||
const pageText = getPageTextSnapshot();
|
||||
const matches = pageText.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/ig) || [];
|
||||
return matches[0] ? String(matches[0]).trim().toLowerCase() : '';
|
||||
}
|
||||
|
||||
function getOAuthConsentForm() {
|
||||
return document.querySelector(OAUTH_CONSENT_FORM_SELECTOR);
|
||||
}
|
||||
@@ -1076,6 +1082,7 @@ function inspectLoginAuthState() {
|
||||
state: 'unknown',
|
||||
url: location.href,
|
||||
path: location.pathname || '',
|
||||
displayedEmail: getLoginVerificationDisplayedEmail(),
|
||||
retryButton: retryState?.retryButton || null,
|
||||
retryEnabled: Boolean(retryState?.retryEnabled),
|
||||
titleMatched: Boolean(retryState?.titleMatched),
|
||||
@@ -1141,6 +1148,7 @@ function serializeLoginAuthState(snapshot) {
|
||||
state: snapshot?.state || 'unknown',
|
||||
url: snapshot?.url || location.href,
|
||||
path: snapshot?.path || location.pathname || '',
|
||||
displayedEmail: snapshot?.displayedEmail || '',
|
||||
retryEnabled: Boolean(snapshot?.retryEnabled),
|
||||
titleMatched: Boolean(snapshot?.titleMatched),
|
||||
detailMatched: Boolean(snapshot?.detailMatched),
|
||||
|
||||
Reference in New Issue
Block a user