Files
NASOpenClawRunTime/browserless-qr.cjs
2026-04-25 01:38:03 +00:00

112 lines
3.7 KiB
JavaScript

// Direct browserless CDP access - navigate to GitHub, screenshot QR code
const WebSocket = require('/home/node/.openclaw/extensions/openclaw-weixin/node_modules/ws/index.js');
const http = require('http');
const fs = require('fs');
// Create a new browser session
async function createSession(url) {
return new Promise((resolve, reject) => {
const postData = JSON.stringify({ url, headless: true });
const opts = {
hostname: 'browserless',
port: 3000,
path: '/session',
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length }
};
const req = http.request(opts, (res) => {
let data = '';
res.on('data', c => data += c);
res.on('end', () => {
try { resolve(JSON.parse(data)); } catch(e) { reject(e); }
});
});
req.on('error', reject);
req.write(postData);
req.end();
});
}
// Send CDP command over WebSocket
function sendWS(ws, id, method, params) {
return new Promise((resolve, reject) => {
const msg = JSON.stringify({ id, method, params });
const timeout = setTimeout(() => reject('timeout'), 15000);
ws.on('message', (data) => {
const resp = JSON.parse(data.toString());
if (resp.id === id) { clearTimeout(timeout); resolve(resp.result); }
});
ws.send(msg);
});
}
async function main() {
const text = process.argv[2] || 'https://github.com/login/device';
const outFile = process.argv[3] || '/home/node/.openclaw/workspace/assets/browserless-qr.png';
// Step 1: create session
console.log('Creating session at', text);
const session = await createSession(text);
console.log('Session:', Object.keys(session));
if (session.error) throw new Error(session.error);
const wsUrl = session.wsUri || session.webSocketDebuggerUrl;
console.log('WS URL:', wsUrl);
const ws = new WebSocket(wsUrl);
await new Promise((res, rej) => { ws.on('open', res); ws.on('error', rej); });
let id = 1;
const send = (method, params) => sendWS(ws, id++, method, params);
// Wait for page to load
await send('Page.enable');
await send('Runtime.enable');
// Wait for network idle
try {
await send('Page.waitForNavigation', { waitUntil: 'networkidle2', timeout: 10000 });
} catch(e) {
console.log('Nav wait:', e.message);
}
// Try to find QR code element
const qrResult = await send('Runtime.evaluate', {
expression: `
(function() {
// Try multiple selectors
const selectors = [
'.qr-code img', '.qrcode img', '#qr-code img',
'img[alt*="QR"]', 'img[src*="qrcode"]', '.setup-qr-code img',
'div[data-qr] img', '[class*="qr"] img', 'img[class*="qr"]'
];
for (const sel of selectors) {
const el = document.querySelector(sel);
if (el) return { src: el.src, w: el.width, h: el.height, sel };
}
// Fall back to any large image
const imgs = Array.from(document.querySelectorAll('img'));
for (const img of imgs) {
if (img.width > 100 && img.height > 100) {
return { src: img.src, w: img.width, h: img.height, sel: 'fallback-large' };
}
}
// Get all images
return imgs.map(img => ({ src: img.src.substring(0, 100), w: img.width, h: img.height, class: img.className }));
})()
`
});
console.log('QR elements:', JSON.stringify(qrResult.result, null, 2));
// Take screenshot of the page
const screenshot = await send('Page.captureScreenshot', { type: 'png' });
const buf = Buffer.from(screenshot.data, 'base64');
fs.writeFileSync(outFile, buf);
console.log('Screenshot saved:', buf.length, 'bytes to', outFile);
ws.close();
}
main().catch(e => { console.error('Error:', e.message); process.exit(1); });