capiumbrowser 1.2.1__tar.gz → 1.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {capiumbrowser-1.2.1/capiumbrowser.egg-info → capiumbrowser-1.2.2}/PKG-INFO +1 -1
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/_version.py +7 -6
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/browser.py +19 -7
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/browser_async.py +29 -0
- capiumbrowser-1.2.2/capiumbrowser/channels.json +40 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/config.py +10 -6
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2/capiumbrowser.egg-info}/PKG-INFO +1 -1
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/pyproject.toml +1 -1
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_config_args.py +5 -2
- capiumbrowser-1.2.1/capiumbrowser/channels.json +0 -36
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/LICENSE +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/MANIFEST.in +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/README.md +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/__init__.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/__main__.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/_driver.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/android-phones.json +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/browser-brands.json +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/desktop.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/errors.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/human/__init__.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/human/behavior.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/ios-phones.json +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/licensing/__init__.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/licensing/client.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/licensing/download.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/licensing/readiness.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/mobile.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/network/__init__.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser/network/proxy.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser.egg-info/SOURCES.txt +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser.egg-info/dependency_links.txt +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser.egg-info/entry_points.txt +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser.egg-info/requires.txt +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/capiumbrowser.egg-info/top_level.txt +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/setup.cfg +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_channels_manifest.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_desktop_brands.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_download_contract.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_geoip_flags.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_ios_profiles.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_launch_viewport.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_license_readiness.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_mobile_profiles.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_proxy.py +0 -0
- {capiumbrowser-1.2.1 → capiumbrowser-1.2.2}/tests/test_version_tables_consistent.py +0 -0
|
@@ -17,17 +17,18 @@ import json
|
|
|
17
17
|
import os
|
|
18
18
|
import platform as _platform
|
|
19
19
|
|
|
20
|
-
__version__ = "1.2.
|
|
20
|
+
__version__ = "1.2.2"
|
|
21
21
|
|
|
22
22
|
# Used only if channels.json can't be read (corrupt/removed install). ensure_binary() raises a
|
|
23
23
|
# clear error long before the "unsupported platform" case matters; this keeps lookups total.
|
|
24
|
+
# Reported version per platform: Windows .85, macOS/Linux .84 (engine 155.0.8059.84 on all).
|
|
24
25
|
_FALLBACK_VERSIONS = {
|
|
25
|
-
"windows-x64": "155.0.8059.
|
|
26
|
-
"macos-arm64": "155.0.8059.
|
|
27
|
-
"linux-x64": "155.0.8059.
|
|
28
|
-
"linux-arm64": "155.0.8059.
|
|
26
|
+
"windows-x64": "155.0.8059.85",
|
|
27
|
+
"macos-arm64": "155.0.8059.84",
|
|
28
|
+
"linux-x64": "155.0.8059.84",
|
|
29
|
+
"linux-arm64": "155.0.8059.84", # declared; not yet published (see channels.json)
|
|
29
30
|
}
|
|
30
|
-
_DEFAULT_BINARY_VERSION = "155.0.8059.
|
|
31
|
+
_DEFAULT_BINARY_VERSION = "155.0.8059.84"
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def _load_stable():
|
|
@@ -171,6 +171,7 @@ def _fit_window_to_screen(context):
|
|
|
171
171
|
(works for persistent contexts, which have no browser() object). This keeps screen~=viewport in
|
|
172
172
|
headless/container (avoids the browserscan 'screen != viewport' VM tell) AND stays coherent in
|
|
173
173
|
headed (Chrome clamps to the real display -> a normal viewport<screen window). Best-effort."""
|
|
174
|
+
s = None
|
|
174
175
|
try:
|
|
175
176
|
page = context.pages[0] if context.pages else None
|
|
176
177
|
if not page:
|
|
@@ -185,6 +186,12 @@ def _fit_window_to_screen(context):
|
|
|
185
186
|
"left": 0, "top": 0, "width": aw, "height": ah, "windowState": "normal"}})
|
|
186
187
|
except Exception:
|
|
187
188
|
pass
|
|
189
|
+
finally:
|
|
190
|
+
if s is not None:
|
|
191
|
+
try:
|
|
192
|
+
s.detach()
|
|
193
|
+
except Exception:
|
|
194
|
+
pass
|
|
188
195
|
|
|
189
196
|
|
|
190
197
|
def _wrap_close(obj, pw):
|
|
@@ -415,6 +422,13 @@ def launch_persistent_context(user_data_dir, seed=None, platform="windows", head
|
|
|
415
422
|
raise
|
|
416
423
|
_clear_status_file(status_path)
|
|
417
424
|
ctx._capium_seed = seed
|
|
425
|
+
# Fit every headed desktop brand before its engine check returns the context.
|
|
426
|
+
# Mobile profiles retain their catalog viewport and startup bounds.
|
|
427
|
+
# Size the window to the seed's screen for desktop personas -- in HEADLESS too, so the
|
|
428
|
+
# viewport is a coherent per-seed maximized size (e.g. 1920x1080 screen -> ~1904x911)
|
|
429
|
+
# instead of the tiny startup window. Mobile keeps its device viewport.
|
|
430
|
+
if not (platform in ("android", "ios") and stealth_args):
|
|
431
|
+
_fit_window_to_screen(ctx)
|
|
418
432
|
if desktop.normalize_brand(browser_brand) != "chrome":
|
|
419
433
|
ctx = _wrap_close(ctx, pw)
|
|
420
434
|
try:
|
|
@@ -431,11 +445,6 @@ def launch_persistent_context(user_data_dir, seed=None, platform="windows", head
|
|
|
431
445
|
ctx.close()
|
|
432
446
|
raise
|
|
433
447
|
return ctx
|
|
434
|
-
# Headed persistent launches fit the window to the selected screen. Headless
|
|
435
|
-
# keeps its startup bounds (800x600 by default) independent of the seeded screen;
|
|
436
|
-
# callers can choose larger window bounds explicitly.
|
|
437
|
-
if not headless:
|
|
438
|
-
_fit_window_to_screen(ctx)
|
|
439
448
|
return _wrap_close(ctx, pw)
|
|
440
449
|
|
|
441
450
|
|
|
@@ -457,8 +466,11 @@ def launch_context(seed=None, platform="windows", headless=False, url=None,
|
|
|
457
466
|
from . import human as _human
|
|
458
467
|
_human.humanize(context, preset=human_preset)
|
|
459
468
|
page = context.pages[0] if context.pages else context.new_page()
|
|
460
|
-
if not
|
|
461
|
-
|
|
469
|
+
if not getattr(browser, "_capium_mobile", False):
|
|
470
|
+
if headless:
|
|
471
|
+
_fit_window_to_screen(context) # per-seed screen fit (coherent viewport, not the tiny startup window)
|
|
472
|
+
else:
|
|
473
|
+
fit_window(browser, context, page) # modest window <= spoofed screen
|
|
462
474
|
if url:
|
|
463
475
|
page.goto(url, wait_until="domcontentloaded", timeout=60000)
|
|
464
476
|
return browser, context, page
|
|
@@ -163,6 +163,29 @@ async def _require_mobile_engine_async(context, mobile_device=None, seed=0, plat
|
|
|
163
163
|
await page.close()
|
|
164
164
|
|
|
165
165
|
|
|
166
|
+
async def _fit_window_to_screen_async(context):
|
|
167
|
+
"""Fit a headed desktop window to its available screen without emulation."""
|
|
168
|
+
session = None
|
|
169
|
+
try:
|
|
170
|
+
page = context.pages[0] if context.pages else await context.new_page()
|
|
171
|
+
screen = await page.evaluate("()=>({w:screen.availWidth,h:screen.availHeight})")
|
|
172
|
+
if not (screen and screen.get("w") and screen.get("h")):
|
|
173
|
+
return
|
|
174
|
+
session = await context.new_cdp_session(page)
|
|
175
|
+
window_id = (await session.send("Browser.getWindowForTarget"))["windowId"]
|
|
176
|
+
await session.send("Browser.setWindowBounds", {"windowId": window_id, "bounds": {
|
|
177
|
+
"left": 0, "top": 0, "width": int(screen["w"]),
|
|
178
|
+
"height": int(screen["h"]), "windowState": "normal"}})
|
|
179
|
+
except Exception:
|
|
180
|
+
pass
|
|
181
|
+
finally:
|
|
182
|
+
if session is not None:
|
|
183
|
+
try:
|
|
184
|
+
await session.detach()
|
|
185
|
+
except Exception:
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
|
|
166
189
|
async def launch_persistent_context_async(user_data_dir, seed=None, platform="windows",
|
|
167
190
|
headless=False, proxy=None, geoip=None, args=None,
|
|
168
191
|
stealth_args=True, timezone=None, locale=None,
|
|
@@ -220,6 +243,10 @@ async def launch_persistent_context_async(user_data_dir, seed=None, platform="wi
|
|
|
220
243
|
raise
|
|
221
244
|
_clear_status_file(status_path)
|
|
222
245
|
ctx._capium_seed = seed
|
|
246
|
+
# Desktop personas: fit to the seed's screen in HEADLESS too (coherent per-seed viewport,
|
|
247
|
+
# not the tiny startup window). Mobile keeps its device viewport.
|
|
248
|
+
if not (platform in ("android", "ios") and stealth_args):
|
|
249
|
+
await _fit_window_to_screen_async(ctx)
|
|
223
250
|
if desktop.normalize_brand(browser_brand) != "chrome":
|
|
224
251
|
ctx = _wrap_close_async(ctx, pw)
|
|
225
252
|
try:
|
|
@@ -251,6 +278,8 @@ async def launch_context_async(seed=None, platform="windows", headless=False, ur
|
|
|
251
278
|
from . import human as _human
|
|
252
279
|
_human.humanize(context, preset=human_preset)
|
|
253
280
|
page = context.pages[0] if context.pages else await context.new_page()
|
|
281
|
+
if not getattr(browser, "_capium_mobile", False):
|
|
282
|
+
await _fit_window_to_screen_async(context)
|
|
254
283
|
if url:
|
|
255
284
|
await page.goto(url, wait_until="domcontentloaded", timeout=60000)
|
|
256
285
|
return browser, context, page
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "SINGLE SOURCE OF TRUTH for the current stable Capium browser build per OS/arch. Each OS reaches stable independently -- edit one entry without touching the others. This file ships inside the wheel (the SDK reads it to pick each host's stable build) AND is published to the download server by the release pipeline. `version` is the reported Chromium version (what the browser reports to the customer, names the R2 folder); `engine_version` is the actual built Chromium engine (box_package verifies the binary against it) -- it differs from `version` when a platform reports a spoofed patch (Windows reports .85 on the .84 engine). `revision` is our packaging counter -- the served R2 folder is chromium-v<version>.<revision>/, ALWAYS dotted-suffixed starting at 1. A Chromium version bump resets revision to 1. `published: false` means the tag is declared but no artifact exists yet.",
|
|
3
|
+
"schema": 1,
|
|
4
|
+
"updated": "2026-10-21",
|
|
5
|
+
"channels": {
|
|
6
|
+
"stable": {
|
|
7
|
+
"windows-x64": {
|
|
8
|
+
"version": "155.0.8059.85",
|
|
9
|
+
"engine_version": "155.0.8059.84",
|
|
10
|
+
"revision": 1,
|
|
11
|
+
"sha256": "e10c944fc23637adb8d2f9206dbd69c595d51ba9de0cfd8140c9a2b5dc3510fc",
|
|
12
|
+
"published": true,
|
|
13
|
+
"license_status_protocol": 1
|
|
14
|
+
},
|
|
15
|
+
"macos-arm64": {
|
|
16
|
+
"version": "155.0.8059.84",
|
|
17
|
+
"engine_version": "155.0.8059.84",
|
|
18
|
+
"revision": 1,
|
|
19
|
+
"sha256": "273bdd754b06538f633d2830f6fb8e3f02df226f093cb42acd052c0fece74127",
|
|
20
|
+
"published": true,
|
|
21
|
+
"license_status_protocol": 1
|
|
22
|
+
},
|
|
23
|
+
"linux-x64": {
|
|
24
|
+
"version": "155.0.8059.84",
|
|
25
|
+
"engine_version": "155.0.8059.84",
|
|
26
|
+
"revision": 1,
|
|
27
|
+
"sha256": "e01b9b2179d82594e552f17aa0fad620785b4dfbf368c10c0ea146b5ce31c4e4",
|
|
28
|
+
"published": true,
|
|
29
|
+
"license_status_protocol": 1
|
|
30
|
+
},
|
|
31
|
+
"linux-arm64": {
|
|
32
|
+
"version": "155.0.8059.84",
|
|
33
|
+
"engine_version": "155.0.8059.84",
|
|
34
|
+
"revision": 1,
|
|
35
|
+
"sha256": null,
|
|
36
|
+
"published": false
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -24,16 +24,20 @@ import shutil
|
|
|
24
24
|
IGNORE_DEFAULT_ARGS = ["--enable-automation", "--enable-unsafe-swiftshader"]
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
# The 155 engine selects a seeded screen within these default bounds.
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
27
|
+
# The 155 engine selects a seeded screen within these default bounds. The headless
|
|
28
|
+
# window is sized PER SEED after launch (browser._fit_window_to_screen -> the seed's
|
|
29
|
+
# screen.availWidth/Height), giving a coherent maximized viewport < screen for every
|
|
30
|
+
# profile. HEADLESS_VIEWPORT is only the brief STARTUP fallback before that fit runs
|
|
31
|
+
# (and the value raw launch() callers get if they build their own contexts); it must
|
|
32
|
+
# fit the smallest default seeded screen (win/linux min is 1280x720), so it is NOT the
|
|
33
|
+
# 800x600 headless-Chrome default tell. Explicit screen/window flags take precedence.
|
|
31
34
|
HEADLESS_SCREEN = (1920, 1080)
|
|
32
|
-
HEADLESS_VIEWPORT = (
|
|
35
|
+
HEADLESS_VIEWPORT = (1280, 720)
|
|
33
36
|
|
|
34
37
|
|
|
35
38
|
def get_headless_default_args():
|
|
36
|
-
"""
|
|
39
|
+
"""Startup window bounds (a safe, common fallback); the per-seed fit resizes to the
|
|
40
|
+
seeded screen's available area after launch without replacing the engine's screen."""
|
|
37
41
|
vw, vh = HEADLESS_VIEWPORT
|
|
38
42
|
return [
|
|
39
43
|
"--window-size=%d,%d" % (vw, vh),
|
|
@@ -57,16 +57,19 @@ def test_third_party_cookies_allowed():
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
def test_headless_default_keeps_seeded_screen():
|
|
60
|
+
# Startup fallback is a safe common size (not the 800x600 headless-default tell) and
|
|
61
|
+
# does NOT pin the screen -- the per-seed window fit resizes to the seeded screen.
|
|
60
62
|
a = config.get_headless_default_args()
|
|
61
63
|
assert not _has(a, "--fingerprint-screen-width")
|
|
62
64
|
assert not _has(a, "--fingerprint-screen-height")
|
|
63
|
-
assert "--window-size=
|
|
65
|
+
assert "--window-size=1280,720" in a
|
|
66
|
+
assert "--window-size=800,600" not in a
|
|
64
67
|
|
|
65
68
|
|
|
66
69
|
def test_build_args_adds_headless_default_only_headless():
|
|
67
70
|
from capiumbrowser import browser
|
|
68
71
|
headless = browser._build_args(1, "windows", True, None, None, None, None, headless=True)
|
|
69
|
-
assert "--window-size=
|
|
72
|
+
assert "--window-size=1280,720" in headless
|
|
70
73
|
assert not _has(headless, "--fingerprint-screen-width")
|
|
71
74
|
assert not _has(headless, "--fingerprint-screen-height")
|
|
72
75
|
headed = browser._build_args(1, "windows", True, None, None, None, None, headless=False)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_comment": "SINGLE SOURCE OF TRUTH for the current stable Capium browser build per OS/arch. Each OS reaches stable independently -- edit one entry without touching the others. This file ships inside the wheel (the SDK reads it to pick each host's stable build) AND is published to the download server by the release pipeline. `version` is the Chromium version (what the browser reports to the customer -- unchanged by the revision); `revision` is our packaging counter -- the served R2 folder is chromium-v<version>.<revision>/, ALWAYS dotted-suffixed starting at 1 (chromium-v<version>.1/ is the first build, .2/ a same-engine re-spin), so publishing a re-spin never overwrites the artifact older SDKs still fetch. `published: false` means the tag is declared but no artifact exists yet -- the SDK raises a clear 'not published yet' error instead of a raw 404.",
|
|
3
|
-
"schema": 1,
|
|
4
|
-
"updated": "2026-10-10",
|
|
5
|
-
"channels": {
|
|
6
|
-
"stable": {
|
|
7
|
-
"windows-x64": {
|
|
8
|
-
"version": "155.0.8059.39",
|
|
9
|
-
"revision": 2,
|
|
10
|
-
"sha256": "25ef98b8713c2c9fb62615b4c9aa0d7a3bd20c76320ec3d99e848775b1d4fdd6",
|
|
11
|
-
"published": true,
|
|
12
|
-
"license_status_protocol": 1
|
|
13
|
-
},
|
|
14
|
-
"macos-arm64": {
|
|
15
|
-
"version": "155.0.8059.39",
|
|
16
|
-
"revision": 2,
|
|
17
|
-
"sha256": "2c39538576a8c5f63b39ac1f09cdb1cc5f7d2b6899ed7625752c6c4c2737a90f",
|
|
18
|
-
"published": true,
|
|
19
|
-
"license_status_protocol": 1
|
|
20
|
-
},
|
|
21
|
-
"linux-x64": {
|
|
22
|
-
"version": "155.0.8059.39",
|
|
23
|
-
"revision": 2,
|
|
24
|
-
"sha256": "87889050d6a1e46a8aabe4800f8fff5e474a07cd23e22a66f79b830f5544487c",
|
|
25
|
-
"published": true,
|
|
26
|
-
"license_status_protocol": 1
|
|
27
|
-
},
|
|
28
|
-
"linux-arm64": {
|
|
29
|
-
"version": "155.0.8059.39",
|
|
30
|
-
"revision": 2,
|
|
31
|
-
"sha256": null,
|
|
32
|
-
"published": false
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|