Files
antigravity-skills-reference/skills/notebooklm/scripts/browser_utils.py

107 lines
3.4 KiB
Python
Executable File

"""
Browser Utilities for NotebookLM Skill
Handles browser launching, stealth features, and common interactions
"""
import json
import time
import random
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)