"""Post-login: find 玖扬复古176 on the 996box main page and click 启动. Assumes: - 996box logged in (window = main page) - capture running in background - CDP on 9222 Drives the REAL launch: game page -> 启动 button -> cq.exe -> cq2.exe -> TCP. """ import asyncio import base64 import json import subprocess import sys import time import httpx import websockets CDP = "http://127.0.0.1:9222" async def get_targets(): async with httpx.AsyncClient(timeout=5) as c: r = await c.get(f"{CDP}/json/list") return r.json() class Page: def __init__(self, ws): self.ws = ws self.mid = 0 async def call(self, method, params=None): self.mid += 1 await self.ws.send(json.dumps({"id": self.mid, "method": method, "params": params or {}})) while True: msg = json.loads(await self.ws.recv()) if msg.get("id") == self.mid: return msg.get("result", {}) async def eval(self, expr): r = await self.call("Runtime.evaluate", {"expression": expr, "returnByValue": True}) return r.get("result", {}).get("value") async def click(self, x, y): await self.call("Input.dispatchMouseEvent", {"type": "mousePressed", "x": x, "y": y, "button": "left", "clickCount": 1, "buttons": 1}) await asyncio.sleep(0.05) await self.call("Input.dispatchMouseEvent", {"type": "mouseReleased", "x": x, "y": y, "button": "left", "clickCount": 1, "buttons": 0}) def cq_pids(): try: out = subprocess.run( ["powershell", "-NoProfile", "-Command", "Get-Process | Where-Object { $_.Name -match '^cq' } | ForEach-Object { \"$($_.Name):$($_.Id):$($_.MainWindowTitle)\" }"], capture_output=True, text=True, timeout=5) return [l.strip() for l in out.stdout.splitlines() if l.strip()] or [] except Exception: return [] def gateway_conns(): try: out = subprocess.run( ["powershell", "-NoProfile", "-Command", "netstat -ano | Select-String ':12000'"], capture_output=True, text=True, timeout=5) return [l.strip() for l in out.stdout.splitlines() if l.strip()] except Exception: return [] def capture_lines(): try: out = subprocess.run( ["powershell", "-NoProfile", "-Command", "(Get-Content 'D:\\传奇\\cq2_sdk\\real_login.jsonl' -ErrorAction SilentlyContinue | Measure-Object).Count"], capture_output=True, text=True, timeout=5) return int(out.stdout.strip() or 0) except Exception: return 0 async def main(): targets = await get_targets() print("=== CDP targets ===") for t in targets: print(f" [{t['type']}] {t.get('title', '')[:35]:<35} {t['url'][:70]}") # find the main web page (not login, not file://) page_t = next( (t for t in targets if t["type"] == "page" and ("hzwlan" in t["url"] or "996box.com" in t["url"] or "h5qfdt" in t["url"]) and "login" not in t["url"]), None, ) if not page_t: print("no game page found (still on login?)") return 1 print(f"\nusing: {page_t['url'][:70]}") async with websockets.connect(page_t["webSocketDebuggerUrl"], max_size=10**7) as ws: page = Page(ws) # Page state state = await page.eval(""" JSON.stringify({ url: location.href.slice(0,80), title: document.title, bodyHead: document.body ? document.body.innerText.slice(0,200) : '' }) """) try: st = json.loads(state or "{}") print(f"url: {st.get('url')}") print(f"title: {st.get('title')}") print(f"body: {st.get('bodyHead','')[:150]}") except Exception: print(state[:200]) # Search for the game (玖扬复古176 / gameId 206923) game = await page.eval(""" (function() { const results = []; // search game cards / names const els = document.querySelectorAll('*'); for (const el of els) { if (el.children.length <= 2) { const t = (el.innerText || '').trim(); if (t && (t.includes('玖扬') || t.includes('复古176')) && t.length < 60 && !results.some(r => r.text === t)) { const r = el.getBoundingClientRect(); if (r.width > 0 && r.height > 0) { results.push({text: t, x: r.x + r.width/2, y: r.y + r.height/2, w: r.width, h: r.height}); } } } if (results.length >= 8) break; } return JSON.stringify(results); })() """) print(f"\n=== 玖扬/复古 matches ===") try: games = json.loads(game or "[]") if not games: print(" none found on this page — searching input?") # maybe need to search sr = await page.eval(""" (function() { const inp = document.querySelector('input[type=text], input[placeholder*=搜索], input[placeholder*=游戏]'); if (!inp) return 'no search input'; return JSON.stringify({ph: inp.placeholder, x: inp.getBoundingClientRect().x, y: inp.getBoundingClientRect().y}); })() """) print(f" search input: {sr}") for g in games: print(f" '{g['text'][:30]}' @ ({g['x']:.0f},{g['y']:.0f}) {g['w']:.0f}x{g['h']:.0f}") except Exception: print(game[:300]) # Screenshot for the record shot = await page.call("Page.captureScreenshot", {"format": "png"}) if shot.get("data"): with open("cdp_main_page.png", "wb") as f: f.write(base64.b64decode(shot["data"])) print("\nscreenshot: cdp_main_page.png") # If a game element was found, click it then find 启动 try: games = json.loads(game or "[]") except Exception: games = [] if games: g0 = games[0] print(f"\nclicking game card '{g0['text'][:20]}'...") await page.click(g0["x"], g0["y"]) await asyncio.sleep(3) # look for 启动 button launch = await page.eval(""" (function() { const btns = document.querySelectorAll('button, [class*=btn], [class*=start], [class*=launch]'); for (const b of btns) { const t = (b.innerText || '').trim(); if (/^(启动|开始游戏|进入游戏|继续游戏)$/.test(t) && b.offsetParent) { const r = b.getBoundingClientRect(); return JSON.stringify({text: t, x: r.x + r.width/2, y: r.y + r.height/2}); } } return null; })() """) if launch: l = json.loads(launch) print(f"LAUNCH button found: '{l['text']}' @ ({l['x']:.0f},{l['y']:.0f})") await page.click(l["x"], l["y"]) print("*** 启动 CLICKED — cq.exe spawning ***") else: print("no 启动 button yet — page may need navigation") # Monitor game launch + traffic print("\n=== monitoring 180s ===") t0 = time.time() while time.time() - t0 < 180: await asyncio.sleep(5) el = int(time.time() - t0) procs = cq_pids() conns = gateway_conns() lines = capture_lines() flags = [] if procs: flags.append("procs=" + ",".join(p.split(":")[0] for p in procs)) if conns: flags.append(f"gw_conns={len(conns)}") if lines: flags.append(f"cap={lines}") print(f" t+{el:>3}s {' '.join(flags) or '...'}") if lines >= 2: print("\n*** TRAFFIC CAPTURED ***") return 0 if procs and conns and el > 40: print("\n*** game connected; letting capture accumulate 30s ***") await asyncio.sleep(30) return 0 return 1 sys.exit(asyncio.run(main()))