Initial commit: The Ultimate Antigravity Skills Collection (58 Skills)
This commit is contained in:
107
skills/notebooklm/scripts/browser_utils.py
Executable file
107
skills/notebooklm/scripts/browser_utils.py
Executable file
@@ -0,0 +1,107 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user