Files
ycode/scripts/wb-shell.mjs
T

152 lines
4.9 KiB
JavaScript
Raw 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.
import './wb-legacy-disabled.mjs'
/**
* 完整采集对标外围结构:侧栏(品牌/导航/分组/账号)、搜索、通知、设置入口。
*
* 用法:node scripts/wb-shell.mjs <port> [outJson]
*/
import { writeFile } from 'node:fs/promises'
const port = Number(process.argv[2] ?? 9223)
const outJson = process.argv[3] ?? null
const PROPS = [
'display',
'flex-direction',
'align-items',
'justify-content',
'width',
'height',
'min-height',
'padding-top',
'padding-right',
'padding-bottom',
'padding-left',
'margin-top',
'margin-bottom',
'gap',
'background-color',
'color',
'border-top-width',
'border-top-color',
'border-radius',
'font-size',
'font-weight',
'line-height',
'opacity',
'position'
]
async function main() {
const list = await (await fetch(`http://127.0.0.1:${port}/json/list`)).json()
const page = list.filter((t) => t.type === 'page')[0]
if (!page) throw new Error('未找到页面')
const ws = new WebSocket(page.webSocketDebuggerUrl)
await new Promise((r, j) => {
const t = setTimeout(() => j(new Error('连接超时')), 8000)
ws.addEventListener('open', () => {
clearTimeout(t)
r()
})
ws.addEventListener('error', () => {
clearTimeout(t)
j(new Error('连接失败'))
})
})
const send = (method, params = {}) =>
new Promise((res, rej) => {
const id = Math.floor(Math.random() * 1e9)
const timer = setTimeout(() => rej(new Error(`超时 ${method}`)), 25000)
const h = (ev) => {
const m = JSON.parse(ev.data)
if (m.id === id) {
clearTimeout(timer)
ws.removeEventListener('message', h)
res(m.result)
}
}
ws.addEventListener('message', h)
ws.send(JSON.stringify({ id, method, params }))
})
const expr = `(() => {
const PROPS = ${JSON.stringify(PROPS)};
const clean = (v) => (v == null ? '' : String(v).replace(/\\s+/g, ' ').trim());
const picked = (el) => {
const cs = getComputedStyle(el);
const o = {};
for (const p of PROPS) {
const v = clean(cs.getPropertyValue(p));
if (v && v !== 'normal' && v !== 'auto' && v !== 'none' && v !== '0px' && v !== 'rgba(0, 0, 0, 0)') o[p] = v;
}
return o;
};
const rect = (el) => { const r = el.getBoundingClientRect(); return [Math.round(r.x), Math.round(r.y), Math.round(r.width), Math.round(r.height)]; };
// 1) 侧栏完整子树(含文字节点)
const side = document.querySelector('.conversation-sidebar') || document.querySelector('[class*="sidebar"]');
const sidebar = [];
if (side) {
const walk = (el, depth) => {
if (depth > 12) return;
const r = el.getBoundingClientRect();
if (r.width < 1 || r.height < 1) return;
const kids = [...el.children];
const ownText = kids.length === 0 ? clean(el.textContent).slice(0, 60) : '';
sidebar.push({ d: depth, tag: el.tagName.toLowerCase(), cls: clean(el.className).slice(0, 90), text: ownText, rect: rect(el), st: picked(el) });
kids.forEach((c) => walk(c, depth + 1));
};
walk(side, 0);
}
// 2) 全局搜外围相关元素(搜索/通知/账号/设置)
const keyword = /search|notif|account|avatar|user|profile|setting|login|inbox|message|bell/i;
const found = [];
document.querySelectorAll('[class]').forEach((el) => {
if (typeof el.className !== 'string') return;
if (!keyword.test(el.className)) return;
const r = el.getBoundingClientRect();
if (r.width < 8 || r.height < 8) return;
found.push({ cls: clean(el.className).slice(0, 100), rect: rect(el), text: clean(el.textContent).slice(0, 60), st: picked(el) });
});
return JSON.stringify({
viewport: { w: innerWidth, h: innerHeight },
sidebar,
found: found.slice(0, 60)
});
})()`
const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true })
const data = JSON.parse(r.result.value)
console.log(`viewport ${data.viewport.w}x${data.viewport.h}`)
console.log(`\n===== 侧栏子树(${data.sidebar.length} 节点)=====`)
for (const n of data.sidebar) {
const cls = n.cls ? '.' + n.cls.split(/\s+/).slice(0, 2).join('.') : ''
const txt = n.text ? ` "${n.text}"` : ''
console.log(`${' '.repeat(n.d)}${n.tag}${cls} [${n.rect.join(',')}]${txt}`)
const keys = Object.keys(n.st)
if (keys.length) console.log(`${' '.repeat(n.d)} ${JSON.stringify(n.st)}`)
}
console.log(`\n===== 外围相关元素(${data.found.length})=====`)
for (const f of data.found) {
console.log(` .${f.cls.split(/\s+/).slice(0, 2).join('.')} [${f.rect.join(',')}] "${f.text}"`)
}
if (outJson) {
await writeFile(outJson, JSON.stringify(data, null, 2), 'utf8')
console.log(`\n已写出 ${outJson}`)
}
ws.close()
}
main().catch((e) => {
console.error('失败:', e.message)
process.exit(1)
})