d331128e88
- 问题: 30-collaplex-eq.conf 的 node.target 是安装时探测一次写死的。开机时设备若还没枚举 (USB 耳机晚到很常见: 09-24 实测开机 08:57、耳机 09:19:43 才出现; 09-23 是 21:01 → 21:03), 建链时目标不存在 → 末段连到别处或干脆不连, 设备出现后不会自己改回来 → 听感"双重混响", 只能 stop + start - 新增 web/output_route.py: 设备清单(pw-dump) + 选择落盘(output.json) + 守护线程(每 3 秒核对 collaplex_eq_out 只连选中设备, 不对就拆错的、按声道补对的) → 设备一出现自动挂上 - web/server.py: GET /api/devices, POST /api/device(落盘 + 立刻挂载), 快照带 output 段, main() 起守护线程 - web/index.html: 「输出设备」卡片(下拉 + 应用 + 状态 + 守护备注; 设备表变化才重建选项, 免得 60 Hz 重建打断点击) - 脚本/安装.sh: 优先用记住的设备(不在位也照样按它建链), 不再"猜第一个 digital" - 实测: 面板真点应用切走再切回 ✓ / 连错 2 秒自动纠回 ✓ / 全拆 3 秒自动挂回 ✓ / start 自检 打印 [在位] ✓ / 面板像素验收 ✓; pyright strict 0 errors 0 warnings - 坑: pw-dump 的 Link 键名是 output-port-id / input-port-id(写 output-port 一条连线都读不到); 面板服务 enable --now 不会重启已在运行的实例(改 web/*.py 必须 restart)
58 lines
2.3 KiB
Python
58 lines
2.3 KiB
Python
"""面板截图(CDP): 打开 http://127.0.0.1:8789/ 截图, 用于像素级验收。
|
|
|
|
用法: uv run --with websocket-client python 面板截图.py [输出png] [宽] [高]
|
|
前置: google-chrome --headless=new --disable-gpu --no-sandbox \
|
|
--remote-debugging-port=9333 --remote-allow-origins='*' about:blank &
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
import json
|
|
import sys
|
|
import time
|
|
import urllib.request
|
|
|
|
import websocket
|
|
|
|
OUT = sys.argv[1] if len(sys.argv) > 1 else "/tmp/panel.png"
|
|
W = int(sys.argv[2]) if len(sys.argv) > 2 else 1200
|
|
H = int(sys.argv[3]) if len(sys.argv) > 3 else 1400
|
|
URL = "http://127.0.0.1:8789/"
|
|
|
|
targets = json.load(urllib.request.urlopen("http://127.0.0.1:9333/json/list"))
|
|
page = [t for t in targets if t["type"] == "page"][0]
|
|
ws = websocket.create_connection(page["webSocketDebuggerUrl"], timeout=30)
|
|
_seq = [0]
|
|
|
|
|
|
def cmd(method: str, **params: object) -> dict[str, object]:
|
|
"""发一条 CDP 命令并等回包。"""
|
|
_seq[0] += 1
|
|
ws.send(json.dumps({"id": _seq[0], "method": method, "params": params}))
|
|
while True:
|
|
msg = json.loads(ws.recv())
|
|
if msg.get("id") == _seq[0]:
|
|
return msg
|
|
|
|
|
|
cmd("Page.enable")
|
|
cmd("Emulation.setDeviceMetricsOverride", width=W, height=H,
|
|
deviceScaleFactor=1, mobile=False)
|
|
cmd("Page.navigate", url=URL)
|
|
time.sleep(3.0) # 等页面 + SSE 首帧
|
|
|
|
# 顺手把新卡片里的文字读出来(和像素一起留证)
|
|
expr = ("JSON.stringify({sel:document.getElementById('outdev')?document.getElementById('outdev').options.length:-1,"
|
|
"value:document.getElementById('outdev')?document.getElementById('outdev').value:'',"
|
|
"state:document.getElementById('outstate')?document.getElementById('outstate').textContent:'',"
|
|
"hint:document.getElementById('outhint')?document.getElementById('outhint').textContent:'',"
|
|
"status:document.getElementById('status')?document.getElementById('status').textContent:''})")
|
|
got = cmd("Runtime.evaluate", expression=expr, returnByValue=True)
|
|
print("页面自述:", got.get("result", {}).get("result", {}).get("value"))
|
|
|
|
shot = cmd("Page.captureScreenshot", format="png", captureBeyondViewport=True)
|
|
data = base64.b64decode(str(shot["result"]["data"])) # type: ignore[index]
|
|
with open(OUT, "wb") as fh:
|
|
fh.write(data)
|
|
print("已保存:", OUT, len(data), "字节")
|