优化了一些文件 增加多店铺

This commit is contained in:
yml
2026-04-09 01:31:47 +08:00
parent c2ec3aa6d2
commit e4ab1f559e
43 changed files with 1839 additions and 91 deletions
@@ -0,0 +1,171 @@
import fs from 'node:fs/promises'
import { downloadRemoteQrImage, logBrowserSessionDebug, waitForFrame } from './session-login-shared.js'
const QQ_QR_TARGET_SIZE = 144
export async function ensureQqLoginReady(page) {
try {
const frame = await waitForFrame(
page,
(item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'),
10_000,
)
const switcher = frame.locator('#switcher_qlogin')
if (!(await switcher.count())) {
return
}
await switcher.click({ timeout: 3_000 }).catch(() => null)
await frame.waitForTimeout(250)
} catch {
// ignore qq inner tab switch failures; the screenshot retry path will try again
}
}
export async function captureQqQrImage(page, qrImagePath) {
const frame = await waitForFrame(
page,
(item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'),
10_000,
)
const qrUrl = await resolveQqQrImageUrl(frame)
const effectiveQrUrl = upgradeQqQrImageUrl(qrUrl)
logBrowserSessionDebug('qq.capture.qrUrl', {
qrUrl,
effectiveQrUrl,
frameUrl: frame.url(),
})
if (effectiveQrUrl) {
const body = await downloadRemoteQrImage(page, effectiveQrUrl, qrImagePath, frame.url(), 'qq')
logBrowserSessionDebug('qq.capture.downloadResult', {
qrUrl: effectiveQrUrl,
downloaded: Boolean(body?.length),
qrImagePath,
})
if (body?.length) {
await fs.writeFile(qrImagePath, body)
return
}
}
logBrowserSessionDebug('qq.capture.fallbackScreenshot', {
qrImagePath,
})
const qrLocator = await findQqQrLocator(page, frame)
try {
await qrLocator.screenshot({ path: qrImagePath })
return
} catch {
const iframeLocator = page.locator('#milo-qcwx-frame-qc').first()
await iframeLocator.waitFor({ state: 'visible', timeout: 15_000 })
await iframeLocator.screenshot({ path: qrImagePath })
}
}
export async function findQqQrLocator(page, frame = null) {
const effectiveFrame =
frame ||
await waitForFrame(page, (item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'))
const locator = effectiveFrame.locator('#qrlogin_img')
await locator.waitFor({ state: 'visible', timeout: 15_000 })
logBrowserSessionDebug('qq.findQrLocator.visibleReady', {
frameUrl: effectiveFrame.url(),
})
return locator
}
export async function extractQqQrState(page) {
const frame = page.frames().find((item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'))
if (!frame) {
return {
visible: false,
scanned: false,
expired: false,
message: '',
}
}
try {
const qrVisible = await frame
.locator('#qrlogin_img')
.first()
.isVisible()
.catch(() => false)
const bodyText = String(await frame.locator('body').textContent()).replace(/\s+/g, ' ').trim()
return {
visible: true,
qrVisible,
scanned: !qrVisible && /扫描成功|请在手机上确认登录/.test(bodyText),
expired: qrVisible ? false : /二维码失效|已失效/.test(bodyText),
message: bodyText.slice(0, 200),
frameUrl: frame.url(),
}
} catch {
return {
visible: true,
qrVisible: false,
scanned: false,
expired: false,
message: '',
frameUrl: frame.url(),
}
}
}
async function resolveQqQrImageUrl(frame) {
return frame
.evaluate(() => {
const qrImage = document.querySelector('#qrlogin_img')
if (!(qrImage instanceof HTMLImageElement)) {
return ''
}
return String(qrImage.currentSrc || qrImage.src || qrImage.getAttribute('src') || '').trim()
})
.then((src) => {
if (!src) {
return ''
}
try {
return new URL(src, frame.url()).toString()
} catch {
return ''
}
})
.catch(() => '')
}
function upgradeQqQrImageUrl(qrUrl) {
if (!qrUrl) {
return ''
}
try {
const url = new URL(qrUrl)
if (!/xui\.ptlogin2\.qq\.com$/i.test(url.hostname) || !/\/ptqrshow$/i.test(url.pathname)) {
return qrUrl
}
const currentSize = Number(url.searchParams.get('d') || 0)
if (!Number.isFinite(currentSize) || currentSize < QQ_QR_TARGET_SIZE) {
url.searchParams.set('d', String(QQ_QR_TARGET_SIZE))
}
return url.toString()
} catch {
return qrUrl
}
}