后端迁移会话QQ登录模块

This commit is contained in:
yml
2026-05-21 15:33:24 +08:00
parent c7726dde32
commit 07a58343c9
3 changed files with 64 additions and 13 deletions
@@ -13,14 +13,18 @@ type LocatorLike = {
count: () => Promise<number>
first: () => LocatorLike
click: (options?: { timeout?: number }) => Promise<void>
waitFor: (options?: { state?: string; timeout?: number }) => Promise<void>
screenshot: (options: { path: string }) => Promise<void>
}
type BrowserPageLike = {
frames: () => any[]
locator: (selector: string) => LocatorLike
waitForTimeout: (milliseconds: number) => Promise<void>
evaluate: <T = any>(callback: any) => Promise<T>
reload: (options?: { waitUntil?: string }) => Promise<unknown>
goto: (url: string, options?: { waitUntil?: string }) => Promise<unknown>
context: () => any
}
type SessionForQrCapture = {
@@ -1,4 +1,4 @@
// @ts-nocheck
/// <reference lib="dom" />
import fs from 'node:fs/promises'
@@ -6,9 +6,48 @@ import { downloadRemoteQrImage, logBrowserSessionDebug, waitForFrame } from './s
const QQ_QR_TARGET_SIZE = 144
export async function ensureQqLoginReady(page) {
type LocatorLike = {
count: () => Promise<number>
click: (options?: { timeout?: number }) => Promise<void>
waitFor: (options?: { state?: string; timeout?: number }) => Promise<void>
screenshot: (options: { path: string }) => Promise<void>
first: () => LocatorLike
}
type FrameLike = {
url: () => string
locator: (selector: string) => LocatorLike
waitForTimeout: (milliseconds: number) => Promise<void>
evaluate: <T = any>(callback: any) => Promise<T>
}
type PageLike = {
frames: () => FrameLike[]
waitForTimeout: (milliseconds: number) => Promise<void>
locator: (selector: string) => LocatorLike
context: () => {
request: {
get: (url: string, options?: any) => Promise<{
ok: () => boolean
status: () => number
body: () => Promise<Buffer>
}>
}
}
}
type QqQrState = {
visible: boolean
qrVisible?: boolean
scanned: boolean
expired: boolean
message: string
frameUrl?: string
}
export async function ensureQqLoginReady(page: PageLike): Promise<void> {
try {
const frame = await waitForFrame(
const frame = await waitForFrame<FrameLike>(
page,
(item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'),
10_000,
@@ -26,8 +65,8 @@ export async function ensureQqLoginReady(page) {
}
}
export async function captureQqQrImage(page, qrImagePath) {
const frame = await waitForFrame(
export async function captureQqQrImage(page: PageLike, qrImagePath: string): Promise<void> {
const frame = await waitForFrame<FrameLike>(
page,
(item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'),
10_000,
@@ -45,11 +84,11 @@ export async function captureQqQrImage(page, qrImagePath) {
const body = await downloadRemoteQrImage(page, effectiveQrUrl, qrImagePath, frame.url(), 'qq')
logBrowserSessionDebug('qq.capture.downloadResult', {
qrUrl: effectiveQrUrl,
downloaded: Boolean(body?.length),
downloaded: Buffer.isBuffer(body) && body.length > 0,
qrImagePath,
})
if (body?.length) {
if (Buffer.isBuffer(body) && body.length > 0) {
await fs.writeFile(qrImagePath, body)
return
}
@@ -71,10 +110,10 @@ export async function captureQqQrImage(page, qrImagePath) {
}
}
export async function findQqQrLocator(page, frame = null) {
export async function findQqQrLocator(page: PageLike, frame: FrameLike | null = null): Promise<LocatorLike> {
const effectiveFrame =
frame ||
await waitForFrame(page, (item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'))
await waitForFrame<FrameLike>(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', {
@@ -83,7 +122,7 @@ export async function findQqQrLocator(page, frame = null) {
return locator
}
export async function extractQqQrState(page) {
export async function extractQqQrState(page: Pick<PageLike, 'frames'>): Promise<QqQrState> {
const frame = page.frames().find((item) => item.url().includes('xui.ptlogin2.qq.com/cgi-bin/xlogin'))
if (!frame) {
@@ -98,7 +137,7 @@ export async function extractQqQrState(page) {
try {
const { qrVisible, bodyText } = await frame
.evaluate(() => {
const isVisible = (element) => {
const isVisible = (element: Element | null) => {
if (!(element instanceof HTMLElement)) {
return false
}
@@ -151,7 +190,7 @@ export async function extractQqQrState(page) {
}
}
async function resolveQqQrImageUrl(frame) {
async function resolveQqQrImageUrl(frame: FrameLike): Promise<string> {
return frame
.evaluate(() => {
const qrImage = document.querySelector('#qrlogin_img')
@@ -176,7 +215,7 @@ async function resolveQqQrImageUrl(frame) {
.catch(() => '')
}
function upgradeQqQrImageUrl(qrUrl) {
function upgradeQqQrImageUrl(qrUrl: string): string {
if (!qrUrl) {
return ''
}