Files
antigravity-skills-reference/web-app/public/skills/notebooklm/scripts/browser_utils.py

108 lines
3.4 KiB
Python

"""
Browser Utilities for NotebookLM Skill
Handles browser launching, stealth features, and common interactions
"""
import json
import time
import random
from typing import Optional, List
from patchright.sync_api import Playwright, BrowserContext, Page
from config import BROWSER_PROFILE_DIR, STATE_FILE, BROWSER_ARGS, USER_AGENT
class BrowserFactory:
"""Factory for creating configured browser contexts"""
@staticmethod
def launch_persistent_context(
playwright: Playwright,
headless: bool = True,
user_data_dir: str = str(BROWSER_PROFILE_DIR)
) -> BrowserContext:
"""
Launch a persistent browser context with anti-detection features
and cookie workaround.
"""
# Launch persistent context
context = playwright.chromium.launch_persistent_context(
user_data_dir=user_data_dir,
channel="chrome", # Use real Chrome
headless=headless,
no_viewport=True,
ignore_default_args=["--enable-automation"],
user_agent=USER_AGENT,
args=BROWSER_ARGS
)
# Cookie Workaround for Playwright bug #36139
# Session cookies (expires=-1) don't persist in user_data_dir automatically
BrowserFactory._inject_cookies(context)
return context
@staticmethod
def _inject_cookies(context: BrowserContext):
"""Inject cookies from state.json if available"""
if STATE_FILE.exists():
try:
with open(STATE_FILE, 'r') as f:
state = json.load(f)
if 'cookies' in state and len(state['cookies']) > 0:
context.add_cookies(state['cookies'])
# print(f" 🔧 Injected {len(state['cookies'])} cookies from state.json")
except Exception as e:
print(f" ⚠️ Could not load state.json: {e}")
class StealthUtils:
"""Human-like interaction utilities"""
@staticmethod
def random_delay(min_ms: int = 100, max_ms: int = 500):
"""Add random delay"""
time.sleep(random.uniform(min_ms / 1000, max_ms / 1000))
@staticmethod
def human_type(page: Page, selector: str, text: str, wpm_min: int = 320, wpm_max: int = 480):
"""Type with human-like speed"""
element = page.query_selector(selector)
if not element:
# Try waiting if not immediately found
try:
element = page.wait_for_selector(selector, timeout=2000)
except:
pass
if not element:
print(f"⚠️ Element not found for typing: {selector}")
return
# Click to focus
element.click()
# Type
for char in text:
element.type(char, delay=random.uniform(25, 75))
if random.random() < 0.05:
time.sleep(random.uniform(0.15, 0.4))
@staticmethod
def realistic_click(page: Page, selector: str):
"""Click with realistic movement"""
element = page.query_selector(selector)
if not element:
return
# Optional: Move mouse to element (simplified)
box = element.bounding_box()
if box:
x = box['x'] + box['width'] / 2
y = box['y'] + box['height'] / 2
page.mouse.move(x, y, steps=5)
StealthUtils.random_delay(100, 300)
element.click()
StealthUtils.random_delay(100, 300)