// @ts-nocheck import fs from 'node:fs/promises' import path from 'node:path' import { isRetryableQrCaptureError, logBrowserSessionDebug } from './session-login-shared.js' import { captureQqQrImage, ensureQqLoginReady, extractQqQrState } from './session-qq.js' import { captureWxQrImage, ensureWxLoginReady, extractWxQrState } from './session-wx.js' export async function captureSessionQr( session, { ensureLoginReady = true, ensureLoginTab: ensureLoginTabImpl = ensureLoginTab, captureQrImageWithRetry: captureQrImageWithRetryImpl = captureQrImageWithRetry, readFile = fs.readFile, now = () => new Date().toISOString(), } = {}, ) { if (ensureLoginReady) { await ensureLoginTabImpl(session.page, session.loginType) } const qrImagePath = path.join(session.sessionDir, `${session.loginType}-qr.png`) await captureQrImageWithRetryImpl(session.page, session.loginType, qrImagePath, { ensureLoginTab: ensureLoginTabImpl, }) session.qrImagePath = qrImagePath session.qrImageBase64 = await readFile(qrImagePath, 'base64') session.qrUpdatedAt = now() session.updatedAt = session.qrUpdatedAt } export async function captureQrImageWithRetry( page, loginType, qrImagePath, { captureQqQrImage: captureQqQrImageImpl = captureQqQrImage, captureWxQrImage: captureWxQrImageImpl = captureWxQrImage, ensureLoginTab: ensureLoginTabImpl = ensureLoginTab, isRetryableQrCaptureError: isRetryableQrCaptureErrorImpl = isRetryableQrCaptureError, logBrowserSessionDebug: logBrowserSessionDebugImpl = logBrowserSessionDebug, } = {}, ) { const maxAttempts = loginType === 'qq' ? 4 : 3 let lastError = null for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { try { logBrowserSessionDebugImpl('captureQrImageWithRetry.start', { loginType, attempt, maxAttempts, qrImagePath, }) if (loginType === 'qq') { await captureQqQrImageImpl(page, qrImagePath) } else { await captureWxQrImageImpl(page, qrImagePath) } logBrowserSessionDebugImpl('captureQrImageWithRetry.success', { loginType, attempt, qrImagePath, }) return } catch (error) { lastError = error logBrowserSessionDebugImpl('captureQrImageWithRetry.error', { loginType, attempt, message: error instanceof Error ? error.message : String(error), }) if (!isRetryableQrCaptureErrorImpl(error) || attempt === maxAttempts) { throw error } await page.waitForTimeout(500) await ensureLoginTabImpl(page, loginType) } } if (lastError) { throw lastError } throw new Error('二维码截图失败') } export async function ensureLoginTab( page, loginType, { ensureQqLoginReady: ensureQqLoginReadyImpl = ensureQqLoginReady, ensureWxLoginReady: ensureWxLoginReadyImpl = ensureWxLoginReady, } = {}, ) { const tabSelector = loginType === 'wx' ? '.wx-tab' : '.qc-tab' const loginButton = page.locator('#unlogin') let interacted = false if (await loginButton.count()) { try { await loginButton.first().click({ timeout: 2_000 }) interacted = true } catch { // ignore when the login layer is already open } } const tab = page.locator(tabSelector).first() if (await tab.count()) { try { await tab.click({ timeout: 2_000 }) interacted = true } catch { // ignore tab click failures } } if (interacted) { await page.waitForTimeout(250) } if (loginType === 'qq') { await ensureQqLoginReadyImpl(page) return } if (loginType === 'wx') { await ensureWxLoginReadyImpl(page) } } export async function extractHostState(page) { return page.evaluate(() => { const isVisible = (element) => { if (!element) { return false } const style = window.getComputedStyle(element) return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0' } const unlogin = document.querySelector('#unlogin') const logined = document.querySelector('#logined') return { unloginVisible: isVisible(unlogin), loginedVisible: isVisible(logined), loginText: String(logined?.textContent || '').trim(), } }) } export async function reloadActivityPageForPresentation(page, activityUrl) { try { await page.reload({ waitUntil: 'domcontentloaded' }) } catch { await page.goto(activityUrl, { waitUntil: 'domcontentloaded' }) } await page.waitForTimeout(2_500) } export async function extractQrState( page, loginType, { extractQqQrState: extractQqQrStateImpl = extractQqQrState, extractWxQrState: extractWxQrStateImpl = extractWxQrState, } = {}, ) { if (loginType === 'qq') { return extractQqQrStateImpl(page) } return extractWxQrStateImpl(page) }