84 lines
3 KiB
Python
84 lines
3 KiB
Python
"""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
|