# -*- coding: utf-8 -*- """把新的中转管理页渲染出来并截图。 做法: 起一个本地中转 -> 造两台测试设备 -> 登录拿 Cookie -> 抓管理页 HTML -> 存成文件 -> 用 Edge 无头模式截图 (存成文件后 JS 调接口会失败,但看清楚界面长什么样足够了。) """ from __future__ import annotations import http.cookiejar import json import os import shutil import subprocess import sys import tempfile import time import urllib.error import urllib.parse import urllib.request from pathlib import Path # 从环境变量或 _build/.admin_password(已 gitignore)读管理密码。 # 不再写死在脚本里 —— 这个仓库是公开的。 def _admin_password() -> str: import os env = os.environ.get("YKXMZ_ADMIN_PASSWORD", "").strip() if env: return env f = Path(__file__).resolve().parent / ".admin_password" if f.is_file(): return f.read_text(encoding="utf-8").strip() raise SystemExit( "没拿到管理密码:设 YKXMZ_ADMIN_PASSWORD,或写 _build/.admin_password") ROOT = Path(__file__).resolve().parent.parent UA = {"User-Agent": "LanRemote/1.4.0"} PORT = 8110 BASE = f"http://127.0.0.1:{PORT}" EDGE_CANDIDATES = [ Path(r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"), Path(r"C:\Program Files\Microsoft\Edge\Application\msedge.exe"), ] def main() -> int: work = Path(tempfile.mkdtemp(prefix="admin_shot_")) relay = None try: data = work / "d" data.mkdir(parents=True, exist_ok=True) env = dict(os.environ) env.update({"RELAY_PORT": str(PORT), "RELAY_BIND": "127.0.0.1", "RELAY_DATA": str(data), "PYTHONIOENCODING": "utf-8", "PYTHONUNBUFFERED": "1"}) relay = subprocess.Popen( [sys.executable, "-u", str(ROOT / "relay" / "relay.py")], env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) for _ in range(40): time.sleep(0.5) try: urllib.request.urlopen(urllib.request.Request( BASE + "/v1/health", headers=UA), timeout=2) break except Exception: # noqa: BLE001 continue # 造几台设备,其中一台"在线" for index, (name, code) in enumerate( [("书房台式机", "482913"), ("笔记本", "771204"), ("办公电脑", "356180")], start=1): body = json.dumps({"deviceId": f"pc-{index}", "code": code, "name": name, "version": "1.4.0"}).encode() urllib.request.urlopen(urllib.request.Request( BASE + "/v1/agent/register", data=body, method="POST", headers={**UA, "Content-Type": "application/json"}), timeout=10).read() jar = http.cookiejar.CookieJar() opener = urllib.request.build_opener( urllib.request.HTTPCookieProcessor(jar)) form = urllib.parse.urlencode({"password": _admin_password()}).encode() req = urllib.request.Request(BASE + "/admin/login", data=form, method="POST", headers=UA) req.add_header("Content-Type", "application/x-www-form-urlencoded") try: opener.open(req, timeout=15).read() except urllib.error.HTTPError: pass html = opener.open(urllib.request.Request(BASE + "/", headers=UA), timeout=15).read().decode("utf-8") page = work / "admin.html" page.write_text(html, encoding="utf-8") # 关键元素检查 print(" 页面检查:") for label, needle in ( ("退出登录", "退出登录"), ("公网地址卡片", "当前公网地址"), ("复制按钮", 'id=copyUrl'), ("统计卡片", 'class=stat'), ("批量删除按钮", 'id=delPicked'), ("全选", 'id=pickAll'), ("自动刷新", 'id=autoRef'), ("每行复选框", 'class=pick value'), ("空状态/表格", "")): print(f" {'✓' if needle in html else '✗'} {label}") print(f" 页面大小 {len(html)} 字节") edge = next((p for p in EDGE_CANDIDATES if p.is_file()), None) if not edge: print(" 没找到 Edge,跳过截图") print(f" HTML 已存到 {page}") return 0 shot = ROOT / "_build" / "admin_preview.png" cmd = [str(edge), "--headless=new", "--disable-gpu", "--hide-scrollbars", "--force-device-scale-factor=1", "--window-size=1180,940", f"--screenshot={shot}", page.as_uri()] proc = subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=90) if shot.is_file(): print(f" 截图: {shot} {shot.stat().st_size // 1024} KB") else: print(f" 截图失败: {proc.stderr[:200]}") # 顺手截一张窄屏(手机)效果 shot2 = ROOT / "_build" / "admin_preview_mobile.png" cmd2 = [str(edge), "--headless=new", "--disable-gpu", "--hide-scrollbars", "--force-device-scale-factor=1", "--window-size=420,1100", f"--screenshot={shot2}", page.as_uri()] subprocess.run(cmd2, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=90) if shot2.is_file(): print(f" 窄屏截图: {shot2} {shot2.stat().st_size // 1024} KB") return 0 finally: if relay is not None: try: relay.terminate() relay.wait(timeout=8) except Exception: # noqa: BLE001 try: relay.kill() except Exception: # noqa: BLE001 pass time.sleep(0.5) shutil.rmtree(work, ignore_errors=True) if __name__ == "__main__": sys.exit(main())