@@ -149,6 +149,88 @@ class ProxySettings(_ProxySettingsRequired, total=False):
149149 password : str
150150
151151
152+ def build_launch_options (
153+ headless : bool = True ,
154+ proxy : str | ProxySettings | None = None ,
155+ args : list [str ] | None = None ,
156+ stealth_args : bool = True ,
157+ timezone : str | None = None ,
158+ locale : str | None = None ,
159+ geoip : bool = False ,
160+ extension_paths : list [str ] | None = None ,
161+ license_key : str | None = None ,
162+ browser_version : str | None = None ,
163+ _suppress_maximize : bool = False ,
164+ ** kwargs : Any ,
165+ ) -> dict [str , Any ]:
166+ """Build the kwargs dict that ``launch()`` passes to ``chromium.launch()``.
167+
168+ Use this when you already manage a Playwright instance and want to compose
169+ CloakBrowser's binary, proxy, environment, and stealth arguments yourself:
170+ ``pw.chromium.launch(**build_launch_options(...))``.
171+ """
172+ _check_removed_kwargs (kwargs )
173+
174+ binary_path = ensure_binary (license_key = license_key , browser_version = browser_version )
175+ timezone , locale , exit_ip = maybe_resolve_geoip (geoip , proxy , timezone , locale )
176+ proxy_kwargs , proxy_extra_args = _resolve_proxy_config (proxy , browser_version )
177+ args = _resolve_webrtc_args (args , proxy )
178+ args = _append_webrtc_exit_ip (args , exit_ip )
179+
180+ chrome_args = build_args (
181+ stealth_args ,
182+ (args or []) + proxy_extra_args ,
183+ timezone = timezone ,
184+ locale = locale ,
185+ headless = headless ,
186+ extension_paths = extension_paths ,
187+ start_maximized = (
188+ binary_supports_maximized_window (license_key , browser_version )
189+ and not _suppress_maximize
190+ ),
191+ )
192+ _maybe_warn_windows_fonts (chrome_args )
193+
194+ launch_env = build_launch_env (license_key , user_env = kwargs .pop ("env" , None ))
195+ env_kwargs = {} if launch_env is None else {"env" : launch_env }
196+
197+ return {
198+ "executable_path" : binary_path ,
199+ "headless" : headless ,
200+ "args" : chrome_args ,
201+ "ignore_default_args" : IGNORE_DEFAULT_ARGS ,
202+ ** env_kwargs ,
203+ ** proxy_kwargs ,
204+ ** kwargs ,
205+ }
206+
207+
208+ def humanize_browser (
209+ browser : Any ,
210+ human_preset : HumanPreset = "default" ,
211+ human_config : HumanConfigOverrides | None = None ,
212+ ) -> None :
213+ """Apply the sync humanize layer to an existing Playwright Browser."""
214+ from .human import patch_browser
215+ from .human .config import resolve_config
216+
217+ cfg = resolve_config (human_preset , human_config )
218+ patch_browser (browser , cfg )
219+
220+
221+ def humanize_browser_async (
222+ browser : Any ,
223+ human_preset : HumanPreset = "default" ,
224+ human_config : HumanConfigOverrides | None = None ,
225+ ) -> None :
226+ """Apply the async humanize layer to an existing Playwright Browser."""
227+ from .human import patch_browser_async
228+ from .human .config import resolve_config
229+
230+ cfg = resolve_config (human_preset , human_config )
231+ patch_browser_async (browser , cfg )
232+
233+
152234def launch (
153235 headless : bool = True ,
154236 proxy : str | ProxySettings | None = None ,
@@ -204,31 +286,26 @@ def launch(
204286
205287 from playwright .sync_api import sync_playwright
206288
207- binary_path = ensure_binary (license_key = license_key , browser_version = browser_version )
208- timezone , locale , exit_ip = maybe_resolve_geoip (geoip , proxy , timezone , locale )
209- proxy_kwargs , proxy_extra_args = _resolve_proxy_config (proxy , browser_version )
210- args = _resolve_webrtc_args (args , proxy )
211- args = _append_webrtc_exit_ip (args , exit_ip )
212-
213- chrome_args = build_args (stealth_args , (args or []) + proxy_extra_args , timezone = timezone , locale = locale , headless = headless , extension_paths = extension_paths , start_maximized = binary_supports_maximized_window (license_key , browser_version ) and not _suppress_maximize )
214- _maybe_warn_windows_fonts (chrome_args )
215-
216- logger .debug ("Launching stealth Chromium (headless=%s, args=%d)" , headless , len (chrome_args ))
217-
218- launch_env = build_launch_env (license_key , user_env = kwargs .pop ("env" , None ))
219- env_kwargs = {} if launch_env is None else {"env" : launch_env }
220-
221- pw = sync_playwright ().start ()
222- browser = pw .chromium .launch (
223- executable_path = binary_path ,
289+ launch_options = build_launch_options (
224290 headless = headless ,
225- args = chrome_args ,
226- ignore_default_args = IGNORE_DEFAULT_ARGS ,
227- ** env_kwargs ,
228- ** proxy_kwargs ,
291+ proxy = proxy ,
292+ args = args ,
293+ stealth_args = stealth_args ,
294+ timezone = timezone ,
295+ locale = locale ,
296+ geoip = geoip ,
297+ extension_paths = extension_paths ,
298+ license_key = license_key ,
299+ browser_version = browser_version ,
300+ _suppress_maximize = _suppress_maximize ,
229301 ** kwargs ,
230302 )
231303
304+ logger .debug ("Launching stealth Chromium (headless=%s, args=%d)" , headless , len (launch_options ["args" ]))
305+
306+ pw = sync_playwright ().start ()
307+ browser = pw .chromium .launch (** launch_options )
308+
232309 # Patch close() to also stop the Playwright instance
233310 _original_close = browser .close
234311
@@ -249,10 +326,7 @@ def _close_with_cleanup() -> None:
249326
250327 # Human-like behavioral patching
251328 if humanize :
252- from .human import patch_browser
253- from .human .config import resolve_config
254- cfg = resolve_config (human_preset , human_config )
255- patch_browser (browser , cfg )
329+ humanize_browser (browser , human_preset , human_config )
256330
257331 return browser
258332
@@ -310,30 +384,26 @@ async def launch_async( # noqa: C901
310384
311385 from playwright .async_api import async_playwright
312386
313- binary_path = ensure_binary (license_key = license_key , browser_version = browser_version )
314- timezone , locale , exit_ip = maybe_resolve_geoip (geoip , proxy , timezone , locale )
315- proxy_kwargs , proxy_extra_args = _resolve_proxy_config (proxy , browser_version )
316- args = _resolve_webrtc_args (args , proxy )
317- args = _append_webrtc_exit_ip (args , exit_ip )
318- chrome_args = build_args (stealth_args , (args or []) + proxy_extra_args , timezone = timezone , locale = locale , headless = headless , extension_paths = extension_paths , start_maximized = binary_supports_maximized_window (license_key , browser_version ) and not _suppress_maximize )
319- _maybe_warn_windows_fonts (chrome_args )
320-
321- logger .debug ("Launching stealth Chromium async (headless=%s, args=%d)" , headless , len (chrome_args ))
322-
323- launch_env = build_launch_env (license_key , user_env = kwargs .pop ("env" , None ))
324- env_kwargs = {} if launch_env is None else {"env" : launch_env }
325-
326- pw = await async_playwright ().start ()
327- browser = await pw .chromium .launch (
328- executable_path = binary_path ,
387+ launch_options = build_launch_options (
329388 headless = headless ,
330- args = chrome_args ,
331- ignore_default_args = IGNORE_DEFAULT_ARGS ,
332- ** env_kwargs ,
333- ** proxy_kwargs ,
389+ proxy = proxy ,
390+ args = args ,
391+ stealth_args = stealth_args ,
392+ timezone = timezone ,
393+ locale = locale ,
394+ geoip = geoip ,
395+ extension_paths = extension_paths ,
396+ license_key = license_key ,
397+ browser_version = browser_version ,
398+ _suppress_maximize = _suppress_maximize ,
334399 ** kwargs ,
335400 )
336401
402+ logger .debug ("Launching stealth Chromium async (headless=%s, args=%d)" , headless , len (launch_options ["args" ]))
403+
404+ pw = await async_playwright ().start ()
405+ browser = await pw .chromium .launch (** launch_options )
406+
337407 # Patch close() to also stop the Playwright instance
338408 _original_close = browser .close
339409
@@ -352,10 +422,7 @@ async def _close_with_cleanup() -> None:
352422
353423 # Human-like behavioral patching (async variant)
354424 if humanize :
355- from .human import patch_browser_async
356- from .human .config import resolve_config
357- cfg = resolve_config (human_preset , human_config )
358- patch_browser_async (browser , cfg )
425+ humanize_browser_async (browser , human_preset , human_config )
359426
360427 return browser
361428
0 commit comments