Files

103 lines
3.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 通过 CDP 截图,用于无人值守环境下的界面功能验证。
*
* 用法:
* node scripts/shot.mjs <port> <outfile>
*/
import { writeFile } from 'node:fs/promises'
const port = Number(process.argv[2] ?? 9335)
const outFile = process.argv[3] ?? 'shot.png'
async function main() {
const listRes = await fetch(`http://127.0.0.1:${port}/json/list`)
const targets = await listRes.json()
const page = targets.find((t) => t.type === 'page')
if (!page) {
console.error('未找到 page 目标。当前目标:', targets.map((t) => `${t.type}:${t.url}`).join(', '))
process.exit(1)
}
console.log('目标页面:', page.url)
const ws = new WebSocket(page.webSocketDebuggerUrl)
let id = 0
const pending = new Map()
const send = (method, params = {}) =>
new Promise((resolve, reject) => {
const msgId = ++id
const timer = setTimeout(() => {
pending.delete(msgId)
reject(new Error(`CDP 调用超时: ${method}`))
}, 8000)
pending.set(msgId, (value) => {
clearTimeout(timer)
resolve(value)
})
ws.send(JSON.stringify({ id: msgId, method, params }))
})
await new Promise((resolve, reject) => {
const timer = setTimeout(() => reject(new Error('WebSocket 连接超时(8s)')), 8000)
ws.addEventListener('open', () => {
clearTimeout(timer)
resolve()
})
ws.addEventListener('error', (e) => {
clearTimeout(timer)
reject(new Error(`WebSocket 错误: ${e?.message ?? 'unknown'}`))
})
})
console.log('CDP 已连接')
ws.addEventListener('message', (ev) => {
const msg = JSON.parse(ev.data)
if (msg.id && pending.has(msg.id)) {
pending.get(msg.id)(msg.result)
pending.delete(msg.id)
}
})
await send('Page.enable')
// 等首屏与字体稳定
await new Promise((r) => setTimeout(r, 2500))
const metrics = await send('Runtime.evaluate', {
expression: `(() => {
const c = document.createElement('canvas')
const gl = c.getContext('webgl2') || c.getContext('webgl')
const dbg = gl && gl.getExtension('WEBGL_debug_renderer_info')
return JSON.stringify({
title: document.title,
theme: document.documentElement.dataset.theme,
hasApi: typeof window.ycode === 'object',
gpuRenderer: dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) : (gl ? 'webgl(no-debug-ext)' : 'NO WEBGL'),
bodyText: (document.body.innerText || '').slice(0, 400),
shell: !!document.querySelector('.app-shell'),
columns: document.querySelector('.app-shell')
? getComputedStyle(document.querySelector('.app-shell')).gridTemplateColumns : null,
composer: !!document.querySelector('.composer__input'),
sessionItems: document.querySelectorAll('.sidebar__item-title').length,
panels: document.querySelectorAll('.panel').length
})
})()`,
returnByValue: true
})
console.log('DOM 状态:', metrics?.result?.value)
const shot = await send('Page.captureScreenshot', { format: 'png' })
if (!shot?.data) {
console.error('截图失败')
process.exit(1)
}
await writeFile(outFile, Buffer.from(shot.data, 'base64'))
console.log('已保存:', outFile)
ws.close()
}
main().catch((err) => {
console.error('异常:', err.message)
process.exit(1)
})