capiumbrowser 1.2.4 → 1.3.1
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.
- package/lib/android-phones.json +64 -10
- package/lib/channels.json +13 -13
- package/lib/launch-common.js +34 -12
- package/lib/mobile.js +1 -1
- package/package.json +1 -1
- package/playwright.js +9 -10
- package/puppeteer.js +5 -7
package/lib/android-phones.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"schema_version": 2,
|
|
3
3
|
"minimum_release_year": 2022,
|
|
4
4
|
"browser": "chrome",
|
|
5
|
-
"status": "
|
|
6
|
-
"gpu_policy": "
|
|
7
|
-
"hardware_policy": "
|
|
5
|
+
"status": "catalog-emulation",
|
|
6
|
+
"gpu_policy": "catalog",
|
|
7
|
+
"hardware_policy": "catalog",
|
|
8
8
|
"physical_device_validation": "pending",
|
|
9
9
|
"default_profile_ids": [
|
|
10
10
|
"pixel-7",
|
|
@@ -13,6 +13,20 @@
|
|
|
13
13
|
"pixel-8a",
|
|
14
14
|
"pixel-9"
|
|
15
15
|
],
|
|
16
|
+
"font_core": [
|
|
17
|
+
"Roboto",
|
|
18
|
+
"Noto Sans",
|
|
19
|
+
"Noto Serif",
|
|
20
|
+
"Noto Sans Mono",
|
|
21
|
+
"Noto Color Emoji",
|
|
22
|
+
"Noto Sans JP",
|
|
23
|
+
"Noto Sans KR",
|
|
24
|
+
"Noto Sans SC",
|
|
25
|
+
"Noto Sans TC",
|
|
26
|
+
"Noto Naskh Arabic",
|
|
27
|
+
"Noto Sans Devanagari",
|
|
28
|
+
"Noto Sans Thai"
|
|
29
|
+
],
|
|
16
30
|
"sources": [
|
|
17
31
|
"https://support.google.com/pixelphone/answer/7158570?hl=en",
|
|
18
32
|
"https://news.samsung.com/global/samsung-galaxy-a55-5g-and-galaxy-a35-5g-awesome-innovations-and-security-engineered-for-everyone",
|
|
@@ -27,7 +41,12 @@
|
|
|
27
41
|
"platform_version": "13",
|
|
28
42
|
"width": 412,
|
|
29
43
|
"height": 915,
|
|
30
|
-
"dpr": 2.625
|
|
44
|
+
"dpr": 2.625,
|
|
45
|
+
"soc": "Tensor G2",
|
|
46
|
+
"cores": 8,
|
|
47
|
+
"memory_gb": 8,
|
|
48
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
49
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G710, OpenGL ES 3.2)"
|
|
31
50
|
},
|
|
32
51
|
{
|
|
33
52
|
"id": "pixel-8",
|
|
@@ -36,7 +55,12 @@
|
|
|
36
55
|
"platform_version": "14",
|
|
37
56
|
"width": 412,
|
|
38
57
|
"height": 915,
|
|
39
|
-
"dpr": 2.625
|
|
58
|
+
"dpr": 2.625,
|
|
59
|
+
"soc": "Tensor G3",
|
|
60
|
+
"cores": 9,
|
|
61
|
+
"memory_gb": 8,
|
|
62
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
63
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
40
64
|
},
|
|
41
65
|
{
|
|
42
66
|
"id": "pixel-8-pro",
|
|
@@ -45,7 +69,12 @@
|
|
|
45
69
|
"platform_version": "14",
|
|
46
70
|
"width": 448,
|
|
47
71
|
"height": 997,
|
|
48
|
-
"dpr": 3.0
|
|
72
|
+
"dpr": 3.0,
|
|
73
|
+
"soc": "Tensor G3",
|
|
74
|
+
"cores": 9,
|
|
75
|
+
"memory_gb": 12,
|
|
76
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
77
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
49
78
|
},
|
|
50
79
|
{
|
|
51
80
|
"id": "pixel-8a",
|
|
@@ -54,7 +83,12 @@
|
|
|
54
83
|
"platform_version": "14",
|
|
55
84
|
"width": 412,
|
|
56
85
|
"height": 915,
|
|
57
|
-
"dpr": 2.625
|
|
86
|
+
"dpr": 2.625,
|
|
87
|
+
"soc": "Tensor G3",
|
|
88
|
+
"cores": 9,
|
|
89
|
+
"memory_gb": 8,
|
|
90
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
91
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
58
92
|
},
|
|
59
93
|
{
|
|
60
94
|
"id": "pixel-9",
|
|
@@ -63,7 +97,12 @@
|
|
|
63
97
|
"platform_version": "14",
|
|
64
98
|
"width": 412,
|
|
65
99
|
"height": 924,
|
|
66
|
-
"dpr": 2.625
|
|
100
|
+
"dpr": 2.625,
|
|
101
|
+
"soc": "Tensor G4",
|
|
102
|
+
"cores": 8,
|
|
103
|
+
"memory_gb": 12,
|
|
104
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
105
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
67
106
|
},
|
|
68
107
|
{
|
|
69
108
|
"id": "samsung-galaxy-a55",
|
|
@@ -74,6 +113,11 @@
|
|
|
74
113
|
"width": 360,
|
|
75
114
|
"height": 800,
|
|
76
115
|
"dpr": 2.25,
|
|
116
|
+
"soc": "Exynos 1480",
|
|
117
|
+
"cores": 8,
|
|
118
|
+
"memory_gb": 8,
|
|
119
|
+
"gpu_vendor": "Google Inc. (Samsung Electronics Co., Ltd.)",
|
|
120
|
+
"gpu_renderer": "ANGLE (Samsung Electronics Co., Ltd., Xclipse 530, OpenGL ES 3.2)",
|
|
77
121
|
"geometry_status": "devtools-emulation-only",
|
|
78
122
|
"geometry_note": "These Chromium preset dimensions/DPR do not directly map to the published 1080x2340 panel; physical Chrome capture required."
|
|
79
123
|
},
|
|
@@ -84,7 +128,12 @@
|
|
|
84
128
|
"platform_version": "14",
|
|
85
129
|
"width": 427,
|
|
86
130
|
"height": 952,
|
|
87
|
-
"dpr": 3.0
|
|
131
|
+
"dpr": 3.0,
|
|
132
|
+
"soc": "Tensor G4",
|
|
133
|
+
"cores": 8,
|
|
134
|
+
"memory_gb": 16,
|
|
135
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
136
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
88
137
|
},
|
|
89
138
|
{
|
|
90
139
|
"id": "pixel-9-pro-xl",
|
|
@@ -93,7 +142,12 @@
|
|
|
93
142
|
"platform_version": "14",
|
|
94
143
|
"width": 448,
|
|
95
144
|
"height": 997,
|
|
96
|
-
"dpr": 3.0
|
|
145
|
+
"dpr": 3.0,
|
|
146
|
+
"soc": "Tensor G4",
|
|
147
|
+
"cores": 8,
|
|
148
|
+
"memory_gb": 16,
|
|
149
|
+
"gpu_vendor": "Google Inc. (ARM)",
|
|
150
|
+
"gpu_renderer": "ANGLE (ARM, Mali-G715, OpenGL ES 3.2)"
|
|
97
151
|
}
|
|
98
152
|
]
|
|
99
153
|
}
|
package/lib/channels.json
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
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
|
|
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/macOS report .48 on the .47 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
3
|
"schema": 1,
|
|
4
|
-
"updated": "2026-10-
|
|
4
|
+
"updated": "2026-10-24",
|
|
5
5
|
"channels": {
|
|
6
6
|
"stable": {
|
|
7
7
|
"windows-x64": {
|
|
8
|
-
"version": "
|
|
9
|
-
"engine_version": "
|
|
8
|
+
"version": "156.0.8078.48",
|
|
9
|
+
"engine_version": "156.0.8078.47",
|
|
10
10
|
"revision": 2,
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "76fa0d609f3d3fcac05436681884b3150405aaa470730d9a9ad1453ff6ad8276",
|
|
12
12
|
"published": true,
|
|
13
13
|
"license_status_protocol": 1
|
|
14
14
|
},
|
|
15
15
|
"macos-arm64": {
|
|
16
|
-
"version": "
|
|
17
|
-
"engine_version": "
|
|
16
|
+
"version": "156.0.8078.48",
|
|
17
|
+
"engine_version": "156.0.8078.47",
|
|
18
18
|
"revision": 2,
|
|
19
|
-
"sha256": "
|
|
19
|
+
"sha256": "3b883146c0f41fcb409113d3f43764b7e7061bb6c64d58cddb26b2619887275f",
|
|
20
20
|
"published": true,
|
|
21
21
|
"license_status_protocol": 1
|
|
22
22
|
},
|
|
23
23
|
"linux-x64": {
|
|
24
|
-
"version": "
|
|
25
|
-
"engine_version": "
|
|
24
|
+
"version": "156.0.8078.47",
|
|
25
|
+
"engine_version": "156.0.8078.47",
|
|
26
26
|
"revision": 2,
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "5fc9954366d8052e09d8f528d1cdbcedcf6d0cb1ae43c36441ce975a1e60c749",
|
|
28
28
|
"published": true,
|
|
29
29
|
"license_status_protocol": 1
|
|
30
30
|
},
|
|
31
31
|
"linux-arm64": {
|
|
32
|
-
"version": "
|
|
33
|
-
"engine_version": "
|
|
32
|
+
"version": "156.0.8078.47",
|
|
33
|
+
"engine_version": "156.0.8078.47",
|
|
34
34
|
"revision": 1,
|
|
35
35
|
"sha256": null,
|
|
36
36
|
"published": false
|
package/lib/launch-common.js
CHANGED
|
@@ -15,13 +15,14 @@ const proxy = require('./proxy');
|
|
|
15
15
|
/**
|
|
16
16
|
* Build [--proxy-server, --geoip] flags for geo coherence.
|
|
17
17
|
*
|
|
18
|
-
* The binary's CapiumGeoipResolver runs at PreBrowserStart ONLY when --geoip is present.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* The binary's CapiumGeoipResolver runs at PreBrowserStart ONLY when --geoip is present.
|
|
19
|
+
* When it runs it resolves the egress IP (proxy exit, else the host's real public IP) and
|
|
20
|
+
* pins WebRTC / timezone / geolocation / language -- so the SDK adds no probe of its own.
|
|
21
|
+
* geoipOn is tri-state:
|
|
22
|
+
* * null -> default: ON whenever a proxy is set, OFF otherwise. An uncorrected host
|
|
23
|
+
* timezone under a proxied identity (UTC on a server, or the operator's home
|
|
24
|
+
* zone against a foreign exit) is a far stronger detection signal than the
|
|
25
|
+
* lookup's one-off launch latency. Pass geoip: false to opt out.
|
|
25
26
|
* * true -> ON with --geoip (resolves the egress -- proxy exit, or the host IP if proxyless).
|
|
26
27
|
* * false -> OFF with --geoip=false, which the binary honors FIRST (explicit opt-out).
|
|
27
28
|
* Returns {launchOptions, args}.
|
|
@@ -29,11 +30,11 @@ const proxy = require('./proxy');
|
|
|
29
30
|
function proxyAndGeoArgs(spec, geoipOn) {
|
|
30
31
|
const { launchOptions, args } = proxy.resolveProxyConfig(spec);
|
|
31
32
|
const out = [...args];
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const explicitOff = geoipOn === false;
|
|
34
|
+
if (geoipOn === null || geoipOn === undefined) geoipOn = Boolean(spec);
|
|
35
|
+
if (geoipOn) {
|
|
35
36
|
out.push('--geoip');
|
|
36
|
-
} else {
|
|
37
|
+
} else if (explicitOff) {
|
|
37
38
|
out.push('--geoip=false');
|
|
38
39
|
}
|
|
39
40
|
return { launchOptions, args: out };
|
|
@@ -87,4 +88,25 @@ function clearStatusFile(p) {
|
|
|
87
88
|
} catch {}
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Deterministic per-seed window geometry inside the seed's available screen area.
|
|
93
|
+
*
|
|
94
|
+
* Every profile previously got the identical maximized-like window (exactly availWidth x
|
|
95
|
+
* availHeight at 0,0), so all profiles sharing a pool screen were geometry-identical -- a
|
|
96
|
+
* clusterable signature. Real users are a mix: most keep the browser maximized, a minority
|
|
97
|
+
* run a windowed browser at an arbitrary size/position. Mirror that mix deterministically
|
|
98
|
+
* per seed (the geometry is part of the profile's stable identity, like its screen).
|
|
99
|
+
* Matches python browser._window_bounds_for_seed.
|
|
100
|
+
*/
|
|
101
|
+
function windowBoundsForSeed(seed, aw, ah) {
|
|
102
|
+
const d = crypto.createHash('sha256')
|
|
103
|
+
.update(`capium-window:${Math.trunc(seed) || 0}`).digest();
|
|
104
|
+
if (d[0] % 10 < 6) return { left: 0, top: 0, width: aw, height: ah };
|
|
105
|
+
const w = Math.max(800, Math.trunc(aw * (0.78 + (d[1] / 255) * 0.16)));
|
|
106
|
+
const h = Math.max(600, Math.trunc(ah * (0.80 + (d[2] / 255) * 0.15)));
|
|
107
|
+
const left = Math.trunc(((aw - w) * d[3]) / 255);
|
|
108
|
+
const top = Math.trunc(((ah - h) * d[4]) / 255);
|
|
109
|
+
return { left, top, width: w, height: h };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = { proxyAndGeoArgs, buildArgs, newStatusFile, clearStatusFile, windowBoundsForSeed };
|
package/lib/mobile.js
CHANGED
|
@@ -84,7 +84,7 @@ async function engineProbe(expected) {
|
|
|
84
84
|
gl.getParameter(ext.UNMASKED_RENDERER_WEBGL) === 'Apple GPU';
|
|
85
85
|
}
|
|
86
86
|
const match = navigator.userAgent.match(/Chrome\/(\d+)\.0\.0\.0 Mobile Safari\//);
|
|
87
|
-
if (!expected || navigator.platform !== 'Linux
|
|
87
|
+
if (!expected || navigator.platform !== 'Linux armv8l' || !match ||
|
|
88
88
|
!navigator.userAgent.includes('(Linux; Android 10; K)') ||
|
|
89
89
|
navigator.userAgent.includes('Version/4.0') || !navigator.userAgentData) return false;
|
|
90
90
|
const ch = await navigator.userAgentData.getHighEntropyValues([
|
package/package.json
CHANGED
package/playwright.js
CHANGED
|
@@ -27,7 +27,7 @@ const human = require('./lib/human');
|
|
|
27
27
|
const license = require('./lib/license');
|
|
28
28
|
const readiness = require('./lib/license-readiness');
|
|
29
29
|
const { CapiumError, translateLaunchError, readLaunchStatus } = require('./lib/errors');
|
|
30
|
-
const { proxyAndGeoArgs, buildArgs, newStatusFile, clearStatusFile } =
|
|
30
|
+
const { proxyAndGeoArgs, buildArgs, newStatusFile, clearStatusFile, windowBoundsForSeed } =
|
|
31
31
|
require('./lib/launch-common');
|
|
32
32
|
|
|
33
33
|
function requireDriver() {
|
|
@@ -161,9 +161,9 @@ function applyViewportDefaults(browser, mobileSeed = null, mobileDevice = null,
|
|
|
161
161
|
*
|
|
162
162
|
* seed/platform : identity. stealthArgs: false drops the default fingerprint flags.
|
|
163
163
|
* proxy : "http://user:pass@host:port" | "socks5://host:port" | {server, username, ...}.
|
|
164
|
-
* geoip : geo coherence, resolved inside the binary. null (default) =
|
|
165
|
-
*
|
|
166
|
-
*
|
|
164
|
+
* geoip : geo coherence, resolved inside the binary. null (default) = ON whenever a
|
|
165
|
+
* proxy is set (pins timezone/geo/WebRTC/language to the exit), OFF otherwise.
|
|
166
|
+
* true = ON even proxyless (host IP). false = explicit opt-out.
|
|
167
167
|
* timezone/locale: explicit override (IANA tz + BCP-47 locale; in-binary spoof).
|
|
168
168
|
* licenseKey/licenseServer: pass the license programmatically (else read from
|
|
169
169
|
* CAPIUM_LICENSE_KEY / ~/.capium/license). The binary self-licenses; the key
|
|
@@ -298,12 +298,11 @@ async function fitWindow(browser, context, page) {
|
|
|
298
298
|
if (!scr || !scr.w || !scr.h) return;
|
|
299
299
|
const aw = Math.trunc(scr.w);
|
|
300
300
|
const ah = Math.trunc(scr.h);
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
const left =
|
|
306
|
-
const top = 0;
|
|
301
|
+
// Per-seed geometry within the seed's screen: maximized-like for most seeds,
|
|
302
|
+
// realistically windowed for the rest (match python _window_bounds_for_seed).
|
|
303
|
+
const seed = (context && context._capiumSeed) ||
|
|
304
|
+
(browser && browser._capiumSeed) || 0;
|
|
305
|
+
const { left, top, width: w, height: h } = windowBoundsForSeed(seed, aw, ah);
|
|
307
306
|
pcdp = await context.newCDPSession(page);
|
|
308
307
|
const { targetInfo } = await pcdp.send('Target.getTargetInfo');
|
|
309
308
|
// Persistent contexts may have no Browser handle; their page session still
|
package/puppeteer.js
CHANGED
|
@@ -31,7 +31,7 @@ const human = require('./lib/human');
|
|
|
31
31
|
const license = require('./lib/license');
|
|
32
32
|
const readiness = require('./lib/license-readiness');
|
|
33
33
|
const { CapiumError, translateLaunchError, readLaunchStatus } = require('./lib/errors');
|
|
34
|
-
const { proxyAndGeoArgs, buildArgs, newStatusFile, clearStatusFile } =
|
|
34
|
+
const { proxyAndGeoArgs, buildArgs, newStatusFile, clearStatusFile, windowBoundsForSeed } =
|
|
35
35
|
require('./lib/launch-common');
|
|
36
36
|
|
|
37
37
|
function requireDriver() {
|
|
@@ -267,12 +267,10 @@ async function fitWindow(browser, page) {
|
|
|
267
267
|
if (!scr || !scr.w || !scr.h) return;
|
|
268
268
|
const aw = Math.trunc(scr.w);
|
|
269
269
|
const ah = Math.trunc(scr.h);
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
const
|
|
273
|
-
const h = ah;
|
|
274
|
-
const left = 0;
|
|
275
|
-
const top = 0;
|
|
270
|
+
// Per-seed geometry within the seed's screen: maximized-like for most seeds,
|
|
271
|
+
// realistically windowed for the rest (match python _window_bounds_for_seed).
|
|
272
|
+
const seed = (browser && browser._capiumSeed) || 0;
|
|
273
|
+
const { left, top, width: w, height: h } = windowBoundsForSeed(seed, aw, ah);
|
|
276
274
|
cdp = await page.createCDPSession();
|
|
277
275
|
const { targetInfo } = await cdp.send('Target.getTargetInfo');
|
|
278
276
|
const { windowId } = await cdp.send('Browser.getWindowForTarget',
|