You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
2.8 KiB
Python

"""BrowserManager: manages Playwright persistent Chrome profile contexts."""
from __future__ import annotations
from pathlib import Path
from typing import Optional
from loguru import logger
class BrowserManager:
"""Manages Playwright browser contexts using persistent Chrome profiles."""
def __init__(self, profile_name: str = "JobAgent", headless: bool = True, slow_mo: int = 0):
self.profile_name = profile_name
self.headless = headless
self.slow_mo = slow_mo
self._playwright = None
self._context = None
def open_context(
self,
profile_name: Optional[str] = None,
headless: Optional[bool] = None,
slow_mo: Optional[int] = None,
):
"""Open a persistent browser context. Returns the BrowserContext."""
from playwright.sync_api import sync_playwright
from gimme_job.utils.paths import chrome_profile_dir
name = profile_name or self.profile_name
hl = headless if headless is not None else self.headless
sm = slow_mo if slow_mo is not None else self.slow_mo
profile_path = chrome_profile_dir(name)
profile_path.mkdir(parents=True, exist_ok=True)
logger.info(f"Opening browser context: profile={name}, headless={hl}")
self._playwright = sync_playwright().start()
self._context = self._playwright.chromium.launch_persistent_context(
user_data_dir=str(profile_path),
headless=hl,
slow_mo=sm,
channel="chrome",
args=[
"--disable-blink-features=AutomationControlled",
"--no-sandbox",
],
viewport={"width": 1280, "height": 900},
locale="en-US",
)
return self._context
def close(self) -> None:
if self._context:
try:
self._context.close()
except Exception:
pass
self._context = None
if self._playwright:
try:
self._playwright.stop()
except Exception:
pass
self._playwright = None
def save_trace(self, trace_path: Path) -> None:
if self._context:
try:
self._context.tracing.stop(path=str(trace_path))
logger.debug(f"Trace saved: {trace_path}")
except Exception as e:
logger.warning(f"Failed to save trace: {e}")
def start_tracing(self) -> None:
if self._context:
try:
self._context.tracing.start(screenshots=True, snapshots=True)
except Exception as e:
logger.warning(f"Failed to start tracing: {e}")
def __enter__(self):
return self
def __exit__(self, *args):
self.close()