"""Weg B — CDPBridge: an das BEREITS eingeloggte Chrome auf gpu-pc (CDP :9223) andocken, statt einen eigenen Browser (launch_persistent_context) mit injizierten Cookies zu starten. suno.py macht das bereits (eigenes get_page() mit connect_over_cdp). Dieses Modul verallgemeinert exakt dieses erprobte Muster, damit gemini.py und qolaba.py denselben Weg nutzen, ohne ihre Selector-/Ablauf-Logik anzufassen. Die Session MUSS auf gpu-pc eingeloggt sein (sonst [BAER - PWA-Login]). Auto-Relogin aus dem Bridge-Prozess ist bei geteiltem CDP-Context nicht moeglich (relogin_supported=False). """ import asyncio, os, socket from urllib.parse import urlparse, urlunparse from patchright.async_api import async_playwright as _patchright_async_playwright from .base import PWABridge CDP_URL = os.environ.get("PWA_CDP_URL") or os.environ.get("SUNO_CDP_URL") \ or "http://host.docker.internal:9223" _cdp_pw = None _cdp_browser = None def _resolve_cdp_url(url: str) -> str: try: parsed = urlparse(url) if parsed.hostname in ("host.docker.internal", "localhost"): ip = socket.gethostbyname(parsed.hostname) netloc = f"{ip}:{parsed.port}" if parsed.port else ip return urlunparse(parsed._replace(netloc=netloc)) except Exception as e: print(f"[cdp] _resolve_cdp_url err ({e}), using raw CDP_URL", flush=True) return url async def _cdp_connect(): global _cdp_pw, _cdp_browser if _cdp_pw is None: _cdp_pw = await _patchright_async_playwright().start() if _cdp_browser is not None: try: _ = _cdp_browser.contexts except Exception: _cdp_browser = None if _cdp_browser is None: resolved = _resolve_cdp_url(CDP_URL) _cdp_browser = await asyncio.wait_for( _cdp_pw.chromium.connect_over_cdp(resolved), timeout=12) return _cdp_browser class CDPBridge(PWABridge): match_host: str = "" relogin_supported = False async def get_ctx(self): b = await _cdp_connect() return b.contexts[0] if b.contexts else await b.new_context() async def get_page(self): global _cdp_browser try: b = await _cdp_connect() ctx = b.contexts[0] if b.contexts else await b.new_context() except Exception as e: print(f"[{self.name}] CDP stale handle ({e}), forcing reconnect", flush=True) _cdp_browser = None b = await _cdp_connect() ctx = b.contexts[0] if b.contexts else await b.new_context() host = self.match_host or (urlparse(self.url).hostname or "") for p in ctx.pages: try: if host and host in (p.url or ""): return p except Exception: pass p = await ctx.new_page() if self.url: try: await p.goto(self.url, wait_until="domcontentloaded", timeout=30000) except Exception as e: print(f"[{self.name}] CDP initial goto err: {e}", flush=True) return p