| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- """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()))
|