File size: 4,314 Bytes
bf3e07d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# -*- coding: utf-8 -*-
# @Time    : 2025/1/2
# @Author  : nipurnagarwal
# @ProjectName: browser-use-100XPrompt
# @FileName: browser.py

import asyncio
import os
import platform
import subprocess
import requests
import logging

from playwright.async_api import Browser as PlaywrightBrowser
from playwright.async_api import (
	BrowserContext as PlaywrightBrowserContext,
	Playwright,
	async_playwright,
)
from browser_use.browser.browser import Browser
from browser_use.browser.context import BrowserContext, BrowserContextConfig

from .config import BrowserPersistenceConfig
from .custom_context import CustomBrowserContext

logger = logging.getLogger(__name__)

class CustomBrowser(Browser):

	async def new_context(
		self,
		config: BrowserContextConfig = BrowserContextConfig()
	) -> CustomBrowserContext:
		return CustomBrowserContext(config=config, browser=self)

	async def _setup_browser(self, playwright: Playwright) -> PlaywrightBrowser:
		"""Sets up and returns a Playwright Browser instance."""
		try:
			# Always check for Arc first on macOS
			arc_path = "/Applications/Arc.app/Contents/MacOS/Arc"
			using_arc = platform.system() == "Darwin" and os.path.exists(arc_path)
			
			# If we're on macOS and Arc exists, use it instead of chrome_instance_path
			if using_arc:
				browser_path = arc_path
			else:
				browser_path = self.config.chrome_instance_path

			if self.config.wss_url:
				browser = await playwright.chromium.connect(self.config.wss_url)
				return browser

			# Try to connect to existing browser instance
			try:
				response = requests.get('http://localhost:9222/json/version', timeout=2)
				if response.status_code == 200:
					logger.info('Reusing existing browser instance')
					browser = await playwright.chromium.connect_over_cdp(
						endpoint_url='http://localhost:9222',
						timeout=20000,
					)
					return browser
			except requests.ConnectionError:
				logger.debug('No existing browser instance found, starting new one')

			if browser_path:
				# Kill any existing browser processes that might interfere
				if platform.system() == "Darwin":
					os.system("pkill 'Arc'")
					await asyncio.sleep(1)  # Give it time to close

				# Launch the browser with debugging port
				subprocess.Popen(
					[
						browser_path,
						'--remote-debugging-port=9222',
						'--no-first-run',
						'--no-default-browser-check',
						'--disable-features=Translate',
						'--enable-automation',
						'--disable-blink-features=AutomationControlled',
					] + self.config.extra_chromium_args,
					stdout=subprocess.DEVNULL,
					stderr=subprocess.DEVNULL,
				)

				# Wait for browser to be ready
				for _ in range(10):
					try:
						response = requests.get('http://localhost:9222/json/version', timeout=2)
						if response.status_code == 200:
							break
					except requests.ConnectionError:
						pass
					await asyncio.sleep(1)

				try:
					browser = await playwright.chromium.connect_over_cdp(
						endpoint_url='http://localhost:9222',
						timeout=20000,
					)
					if using_arc:
						logger.info('Successfully connected to Arc browser')
					return browser
				except Exception as e:
					logger.error(f'Failed to connect to browser: {str(e)}')
					raise RuntimeError(
						'Failed to connect to browser. Please ensure all instances are closed and try again.'
					)

			# Fallback to launching regular chromium if no specific browser path
			disable_security_args = []
			if self.config.disable_security:
				disable_security_args = [
					'--disable-web-security',
					'--disable-site-isolation-trials',
					'--disable-features=IsolateOrigins,site-per-process',
				]

			browser = await playwright.chromium.launch(
				headless=self.config.headless,
				executable_path=None,  # Let Playwright use its bundled Chromium
				args=[
					'--no-sandbox',
					'--disable-blink-features=AutomationControlled',
					'--disable-infobars',
					'--disable-background-timer-throttling',
					'--disable-popup-blocking',
					'--disable-backgrounding-occluded-windows',
					'--disable-renderer-backgrounding',
					'--enable-automation',
				] + disable_security_args + self.config.extra_chromium_args,
				proxy=self.config.proxy,
			)

			return browser

		except Exception as e:
			logger.error(f'Failed to initialize browser: {str(e)}')
			raise