shardx 0.1.0__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.
- shardx-0.1.0/.gitignore +48 -0
- shardx-0.1.0/PKG-INFO +255 -0
- shardx-0.1.0/README.md +231 -0
- shardx-0.1.0/pyproject.toml +38 -0
- shardx-0.1.0/shardx/__init__.py +204 -0
- shardx-0.1.0/shardx/auto_resolve.py +191 -0
- shardx-0.1.0/shardx/browser.py +203 -0
- shardx-0.1.0/shardx/geo.py +128 -0
- shardx-0.1.0/shardx/host.py +143 -0
- shardx-0.1.0/shardx/profile.py +95 -0
- shardx-0.1.0/shardx/proxy.py +168 -0
- shardx-0.1.0/shardx/randomize.py +127 -0
- shardx-0.1.0/shardx/runtime.py +291 -0
- shardx-0.1.0/shardx/screen.py +115 -0
shardx-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ===== Logs =====
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
# ===== Node / Vite =====
|
|
11
|
+
node_modules
|
|
12
|
+
dist
|
|
13
|
+
dist-ssr
|
|
14
|
+
*.local
|
|
15
|
+
*.tsbuildinfo
|
|
16
|
+
.cache/
|
|
17
|
+
.parcel-cache/
|
|
18
|
+
coverage/
|
|
19
|
+
|
|
20
|
+
# ===== Rust / Tauri build artifacts =====
|
|
21
|
+
src-tauri/target/
|
|
22
|
+
src-tauri/Cargo.lock.bak
|
|
23
|
+
src-tauri/.cargo-lock
|
|
24
|
+
src-tauri/gen/
|
|
25
|
+
# Per-platform release bundles — built by the release workflow,
|
|
26
|
+
# uploaded to GitHub Releases, never committed.
|
|
27
|
+
src-tauri/target/release/bundle/
|
|
28
|
+
|
|
29
|
+
# ===== Editor / OS junk =====
|
|
30
|
+
.vscode/*
|
|
31
|
+
!.vscode/extensions.json
|
|
32
|
+
!.vscode/settings.json
|
|
33
|
+
.idea/
|
|
34
|
+
*.suo
|
|
35
|
+
*.ntvs*
|
|
36
|
+
*.njsproj
|
|
37
|
+
*.sln
|
|
38
|
+
*.sw?
|
|
39
|
+
.DS_Store
|
|
40
|
+
Thumbs.db
|
|
41
|
+
|
|
42
|
+
# ===== Local secrets / env =====
|
|
43
|
+
.env
|
|
44
|
+
.env.*
|
|
45
|
+
!.env.example
|
|
46
|
+
|
|
47
|
+
# ===== MCP server local install (downloaded by the user post-install) =====
|
|
48
|
+
mcp/node_modules/
|
shardx-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: shardx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Self-contained Python SDK for the ShardX anti-detect browser — downloads the engine + Widevine + fingerprint library on first use, launches isolated profiles.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ProxyShard/ShardBrowser
|
|
6
|
+
Project-URL: Documentation, https://docs.proxyshard.com
|
|
7
|
+
Project-URL: Issues, https://github.com/ProxyShard/ShardBrowser/issues
|
|
8
|
+
Author-email: ProxyShard <support@proxyshard.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: anti-detect,automation,browser,chromium,fingerprint,multi-accounting,scraping
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.9
|
|
21
|
+
Requires-Dist: httpx[socks]>=0.27
|
|
22
|
+
Requires-Dist: patchright>=1.49
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# shardx (Python)
|
|
26
|
+
|
|
27
|
+
Self-contained Python SDK for the **ShardX anti-detect browser** by the
|
|
28
|
+
[ProxyShard](https://proxyshard.com) team.
|
|
29
|
+
|
|
30
|
+
This package does **not** depend on the desktop launcher. On first use
|
|
31
|
+
it downloads the patched Chromium 148 engine, Widevine CDM, and the
|
|
32
|
+
170-profile fingerprint library from our CDN into a local cache, then
|
|
33
|
+
launches isolated browser sessions on demand.
|
|
34
|
+
|
|
35
|
+
Driven by [patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python)
|
|
36
|
+
(stealth-patched Playwright) — `sdk.session()` returns a ready-to-use
|
|
37
|
+
`Browser` instance, no manual `connect_over_cdp` plumbing.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install shardx
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Supported hosts: **macOS arm64**, **Windows x64**, **Linux x64**.
|
|
46
|
+
|
|
47
|
+
## Quick start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import asyncio
|
|
51
|
+
from shardx import ShardX
|
|
52
|
+
|
|
53
|
+
async def main():
|
|
54
|
+
sdk = ShardX()
|
|
55
|
+
# Engine + Widevine + fingerprint library auto-download from CDN on
|
|
56
|
+
# the first `session`/`launch`/`list_profiles` call (~170 MB once,
|
|
57
|
+
# etag-cached afterward). No separate install step.
|
|
58
|
+
|
|
59
|
+
# Launch + drive in one call. Yields a patchright `Browser`.
|
|
60
|
+
async with sdk.session("win-rtx4060", proxy="socks5://user:pass@host:port") as browser:
|
|
61
|
+
ctx = browser.contexts[0]
|
|
62
|
+
page = await ctx.new_page()
|
|
63
|
+
await page.goto("https://browserleaks.com/quic")
|
|
64
|
+
print(await page.title())
|
|
65
|
+
|
|
66
|
+
# Inspect what the SDK resolved before launch:
|
|
67
|
+
sess = browser._shardx
|
|
68
|
+
print(sess.geo) # GeoInfo(...) from ip-api / ipapi.co
|
|
69
|
+
print(sess.proxy_udp_ms, # UDP RTT in ms or None
|
|
70
|
+
sess.quic_enabled, # bool
|
|
71
|
+
sess.webrtc_mode) # "auto" | "tcp_only" | "block"
|
|
72
|
+
# browser + udd shut down cleanly on exit
|
|
73
|
+
|
|
74
|
+
asyncio.run(main())
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Random profile when none specified
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
async with sdk.session(platform="Windows", randomize=True) as browser:
|
|
81
|
+
# picks a random win-* profile, re-randomises hardware_concurrency /
|
|
82
|
+
# device_memory / platform_version using the host as a basis
|
|
83
|
+
page = await browser.contexts[0].new_page()
|
|
84
|
+
...
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Discover bundled profiles
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
print(sdk.list_profiles()[:5])
|
|
91
|
+
# ['linux-gt1030', 'linux-gtx1050', 'mac-m1-air13', 'mac-m1-imac24', 'mac-m1-max-mbp14']
|
|
92
|
+
|
|
93
|
+
print(sdk.list_profiles(platform="Windows")[:5])
|
|
94
|
+
|
|
95
|
+
profile = sdk.random_profile(platform="macOS")
|
|
96
|
+
print(profile.id, profile.config["webgl"]["renderer"])
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Validate a proxy before binding
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
print(sdk.check_proxy("socks5://user:pass@host:port"))
|
|
103
|
+
# {
|
|
104
|
+
# 'udp_ms': 142.3,
|
|
105
|
+
# 'geo': GeoInfo(country_code='DE', timezone='Europe/Berlin', ...),
|
|
106
|
+
# 'would_enable_quic': True,
|
|
107
|
+
# 'would_set_webrtc': 'auto',
|
|
108
|
+
# }
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Pre-launch checks
|
|
112
|
+
|
|
113
|
+
Every call to `sdk.session()` / `sdk.launch()` runs the same pre-spawn
|
|
114
|
+
pipeline the desktop launcher uses:
|
|
115
|
+
|
|
116
|
+
1. **`resolve_auto_fields`** — if the profile has `"auto"` sentinels for
|
|
117
|
+
`timezone`, `navigator.language`, or `geolocation.mode`, the SDK
|
|
118
|
+
makes a live geo lookup through the bound proxy (`ip-api.com` by
|
|
119
|
+
default). It then writes concrete values: timezone (from the API,
|
|
120
|
+
never a static table), `accept_language` chain, `languages`,
|
|
121
|
+
`icu_locale` (always overwritten so `Intl.*` matches
|
|
122
|
+
`navigator.language`), and lat/lng. Proxy-via failure → direct geo
|
|
123
|
+
→ host `$LANG` / `$TZ` as last-resort fallback. The chosen geo is
|
|
124
|
+
surfaced on `session.geo`.
|
|
125
|
+
2. **`apply_screen_strategy`** — see below.
|
|
126
|
+
3. **`probe_udp`** — SOCKS5 UDP_ASSOCIATE round-trip. If it fails, QUIC
|
|
127
|
+
is force-disabled and WebRTC switches to `tcp_only` automatically.
|
|
128
|
+
|
|
129
|
+
### Screen strategy
|
|
130
|
+
|
|
131
|
+
`screen_mode` kw to `session()` / `launch()`:
|
|
132
|
+
|
|
133
|
+
* **`"profile"`** — keep whatever the fingerprint claims.
|
|
134
|
+
* **`"cap_to_host"`** — *macOS default.* If the host monitor is smaller
|
|
135
|
+
than the FP screen, scale `screen.*` + `window.*` down proportionally;
|
|
136
|
+
otherwise no-op.
|
|
137
|
+
* **`"use_host"`** — *Windows/Linux default.* Overwrite `screen.*` with
|
|
138
|
+
the real monitor (minus a 40 px Windows taskbar) and recompute
|
|
139
|
+
`window.outer_*` / `window.inner_*` accordingly.
|
|
140
|
+
|
|
141
|
+
Default mode is picked from `navigator.platform`. Override per launch:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
async with sdk.session("win-rtx4060", screen_mode="profile") as browser:
|
|
145
|
+
...
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Host-aware hardware randomisation
|
|
149
|
+
|
|
150
|
+
`randomize=True` re-picks `hardware_concurrency`, `device_memory`, and
|
|
151
|
+
`platform_version` before the launch — using the same logic as the
|
|
152
|
+
desktop launcher (`randomize_hardware` in `lib.rs`):
|
|
153
|
+
|
|
154
|
+
* **macOS** profiles use the curated `MAC_HW_CONFIGS` table by id.
|
|
155
|
+
* **Windows / Linux** profiles bracket the host's logical CPU count
|
|
156
|
+
within `[host − 4, host + 2]` from the real x86 set
|
|
157
|
+
`[4, 6, 8, 12, 16, 20, 24, 28, 32]`; `device_memory` is floored by
|
|
158
|
+
core count (≥ 12 → 16, else 8) and capped by `host_ram_bucket_gb()`
|
|
159
|
+
(8 / 16 / 32 GiB bucketed from `sysctl hw.memsize` / `/proc/meminfo`
|
|
160
|
+
/ `Get-CimInstance Win32_ComputerSystem`).
|
|
161
|
+
|
|
162
|
+
So a profile launched on an 8-core / 16 GB laptop will never claim
|
|
163
|
+
32 cores / 128 GB of RAM — keeps fingerprints internally consistent
|
|
164
|
+
with real-world hardware.
|
|
165
|
+
|
|
166
|
+
### Override fingerprint fields
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
profile = sdk.library.load("win-rtx4060").with_override(
|
|
170
|
+
name="my-account",
|
|
171
|
+
timezone="Europe/Berlin",
|
|
172
|
+
navigator={"language": "de-DE"},
|
|
173
|
+
)
|
|
174
|
+
async with sdk.session(profile, proxy="socks5://...") as browser:
|
|
175
|
+
...
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Use your own fingerprint JSON
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from shardx import Profile
|
|
182
|
+
|
|
183
|
+
profile = Profile.from_file("/path/to/my-custom.json")
|
|
184
|
+
async with sdk.session(profile) as browser:
|
|
185
|
+
...
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### WebRTC policy
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
async with sdk.session(
|
|
192
|
+
"win-rtx4060",
|
|
193
|
+
proxy="socks5://...",
|
|
194
|
+
webrtc="tcp_only", # or "block" | "auto" (default)
|
|
195
|
+
webrtc_public_ip="203.0.113.42", # advertised in ICE candidates
|
|
196
|
+
) as browser:
|
|
197
|
+
...
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Advanced: raw launch without patchright
|
|
201
|
+
|
|
202
|
+
If you'd rather drive the browser with a different CDP client (raw
|
|
203
|
+
`pychrome`, `pyppeteer`, your own WebSocket), skip `session()` and use
|
|
204
|
+
`launch()` directly:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
sess = sdk.launch("win-rtx4060", proxy="socks5://...", cdp=True)
|
|
208
|
+
print(sess.cdp_url) # ws://127.0.0.1:54113/devtools/browser/c0a3…
|
|
209
|
+
# … drive it yourself …
|
|
210
|
+
sess.stop()
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
`launch()` does the same pre-launch pipeline (auto-resolve, screen
|
|
214
|
+
strategy, UDP probe, hw randomisation) and returns a `BrowserSession`
|
|
215
|
+
with `cdp_url`, `geo`, `proxy_udp_ms`, `quic_enabled`, `webrtc_mode`,
|
|
216
|
+
`user_data_dir`, and `stop()`.
|
|
217
|
+
|
|
218
|
+
## Cache layout
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
~/Library/Application Support/shardx-sdk/ (mac)
|
|
222
|
+
%LOCALAPPDATA%\shardx-sdk\ (win)
|
|
223
|
+
~/.cache/shardx-sdk/ (linux)
|
|
224
|
+
├── manifest.json ← etag cache for browser/widevine/fingerprints
|
|
225
|
+
├── ShardX-Mac-arm64/ ← extracted engine
|
|
226
|
+
│ └── ShardX.app/…
|
|
227
|
+
├── fingerprints/ ← 170 bundled .json profiles
|
|
228
|
+
│ ├── win-rtx4060.json
|
|
229
|
+
│ └── …
|
|
230
|
+
└── profiles/ ← per-launch user-data-dir (cookies, IndexedDB, cache)
|
|
231
|
+
└── <profile-id>/
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Override the cache root:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
sdk = ShardX(cache_dir="/data/shardx")
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Update the runtime
|
|
241
|
+
|
|
242
|
+
The SDK auto-checks remote etags on the first `session`/`launch`/`list_profiles`
|
|
243
|
+
call of each process and re-downloads anything that changed. To force a
|
|
244
|
+
re-download mid-process (e.g. CI scenarios):
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
sdk.runtime.install(force=True)
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## License
|
|
251
|
+
|
|
252
|
+
MIT (this SDK). The Chromium-fork engine binary downloaded at runtime
|
|
253
|
+
is a closed-source product — see the
|
|
254
|
+
[main repo](https://github.com/ProxyShard/ShardBrowser) for engine
|
|
255
|
+
licensing.
|
shardx-0.1.0/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# shardx (Python)
|
|
2
|
+
|
|
3
|
+
Self-contained Python SDK for the **ShardX anti-detect browser** by the
|
|
4
|
+
[ProxyShard](https://proxyshard.com) team.
|
|
5
|
+
|
|
6
|
+
This package does **not** depend on the desktop launcher. On first use
|
|
7
|
+
it downloads the patched Chromium 148 engine, Widevine CDM, and the
|
|
8
|
+
170-profile fingerprint library from our CDN into a local cache, then
|
|
9
|
+
launches isolated browser sessions on demand.
|
|
10
|
+
|
|
11
|
+
Driven by [patchright](https://github.com/Kaliiiiiiiiii-Vinyzu/patchright-python)
|
|
12
|
+
(stealth-patched Playwright) — `sdk.session()` returns a ready-to-use
|
|
13
|
+
`Browser` instance, no manual `connect_over_cdp` plumbing.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install shardx
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Supported hosts: **macOS arm64**, **Windows x64**, **Linux x64**.
|
|
22
|
+
|
|
23
|
+
## Quick start
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import asyncio
|
|
27
|
+
from shardx import ShardX
|
|
28
|
+
|
|
29
|
+
async def main():
|
|
30
|
+
sdk = ShardX()
|
|
31
|
+
# Engine + Widevine + fingerprint library auto-download from CDN on
|
|
32
|
+
# the first `session`/`launch`/`list_profiles` call (~170 MB once,
|
|
33
|
+
# etag-cached afterward). No separate install step.
|
|
34
|
+
|
|
35
|
+
# Launch + drive in one call. Yields a patchright `Browser`.
|
|
36
|
+
async with sdk.session("win-rtx4060", proxy="socks5://user:pass@host:port") as browser:
|
|
37
|
+
ctx = browser.contexts[0]
|
|
38
|
+
page = await ctx.new_page()
|
|
39
|
+
await page.goto("https://browserleaks.com/quic")
|
|
40
|
+
print(await page.title())
|
|
41
|
+
|
|
42
|
+
# Inspect what the SDK resolved before launch:
|
|
43
|
+
sess = browser._shardx
|
|
44
|
+
print(sess.geo) # GeoInfo(...) from ip-api / ipapi.co
|
|
45
|
+
print(sess.proxy_udp_ms, # UDP RTT in ms or None
|
|
46
|
+
sess.quic_enabled, # bool
|
|
47
|
+
sess.webrtc_mode) # "auto" | "tcp_only" | "block"
|
|
48
|
+
# browser + udd shut down cleanly on exit
|
|
49
|
+
|
|
50
|
+
asyncio.run(main())
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Random profile when none specified
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
async with sdk.session(platform="Windows", randomize=True) as browser:
|
|
57
|
+
# picks a random win-* profile, re-randomises hardware_concurrency /
|
|
58
|
+
# device_memory / platform_version using the host as a basis
|
|
59
|
+
page = await browser.contexts[0].new_page()
|
|
60
|
+
...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Discover bundled profiles
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
print(sdk.list_profiles()[:5])
|
|
67
|
+
# ['linux-gt1030', 'linux-gtx1050', 'mac-m1-air13', 'mac-m1-imac24', 'mac-m1-max-mbp14']
|
|
68
|
+
|
|
69
|
+
print(sdk.list_profiles(platform="Windows")[:5])
|
|
70
|
+
|
|
71
|
+
profile = sdk.random_profile(platform="macOS")
|
|
72
|
+
print(profile.id, profile.config["webgl"]["renderer"])
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Validate a proxy before binding
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
print(sdk.check_proxy("socks5://user:pass@host:port"))
|
|
79
|
+
# {
|
|
80
|
+
# 'udp_ms': 142.3,
|
|
81
|
+
# 'geo': GeoInfo(country_code='DE', timezone='Europe/Berlin', ...),
|
|
82
|
+
# 'would_enable_quic': True,
|
|
83
|
+
# 'would_set_webrtc': 'auto',
|
|
84
|
+
# }
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Pre-launch checks
|
|
88
|
+
|
|
89
|
+
Every call to `sdk.session()` / `sdk.launch()` runs the same pre-spawn
|
|
90
|
+
pipeline the desktop launcher uses:
|
|
91
|
+
|
|
92
|
+
1. **`resolve_auto_fields`** — if the profile has `"auto"` sentinels for
|
|
93
|
+
`timezone`, `navigator.language`, or `geolocation.mode`, the SDK
|
|
94
|
+
makes a live geo lookup through the bound proxy (`ip-api.com` by
|
|
95
|
+
default). It then writes concrete values: timezone (from the API,
|
|
96
|
+
never a static table), `accept_language` chain, `languages`,
|
|
97
|
+
`icu_locale` (always overwritten so `Intl.*` matches
|
|
98
|
+
`navigator.language`), and lat/lng. Proxy-via failure → direct geo
|
|
99
|
+
→ host `$LANG` / `$TZ` as last-resort fallback. The chosen geo is
|
|
100
|
+
surfaced on `session.geo`.
|
|
101
|
+
2. **`apply_screen_strategy`** — see below.
|
|
102
|
+
3. **`probe_udp`** — SOCKS5 UDP_ASSOCIATE round-trip. If it fails, QUIC
|
|
103
|
+
is force-disabled and WebRTC switches to `tcp_only` automatically.
|
|
104
|
+
|
|
105
|
+
### Screen strategy
|
|
106
|
+
|
|
107
|
+
`screen_mode` kw to `session()` / `launch()`:
|
|
108
|
+
|
|
109
|
+
* **`"profile"`** — keep whatever the fingerprint claims.
|
|
110
|
+
* **`"cap_to_host"`** — *macOS default.* If the host monitor is smaller
|
|
111
|
+
than the FP screen, scale `screen.*` + `window.*` down proportionally;
|
|
112
|
+
otherwise no-op.
|
|
113
|
+
* **`"use_host"`** — *Windows/Linux default.* Overwrite `screen.*` with
|
|
114
|
+
the real monitor (minus a 40 px Windows taskbar) and recompute
|
|
115
|
+
`window.outer_*` / `window.inner_*` accordingly.
|
|
116
|
+
|
|
117
|
+
Default mode is picked from `navigator.platform`. Override per launch:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
async with sdk.session("win-rtx4060", screen_mode="profile") as browser:
|
|
121
|
+
...
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Host-aware hardware randomisation
|
|
125
|
+
|
|
126
|
+
`randomize=True` re-picks `hardware_concurrency`, `device_memory`, and
|
|
127
|
+
`platform_version` before the launch — using the same logic as the
|
|
128
|
+
desktop launcher (`randomize_hardware` in `lib.rs`):
|
|
129
|
+
|
|
130
|
+
* **macOS** profiles use the curated `MAC_HW_CONFIGS` table by id.
|
|
131
|
+
* **Windows / Linux** profiles bracket the host's logical CPU count
|
|
132
|
+
within `[host − 4, host + 2]` from the real x86 set
|
|
133
|
+
`[4, 6, 8, 12, 16, 20, 24, 28, 32]`; `device_memory` is floored by
|
|
134
|
+
core count (≥ 12 → 16, else 8) and capped by `host_ram_bucket_gb()`
|
|
135
|
+
(8 / 16 / 32 GiB bucketed from `sysctl hw.memsize` / `/proc/meminfo`
|
|
136
|
+
/ `Get-CimInstance Win32_ComputerSystem`).
|
|
137
|
+
|
|
138
|
+
So a profile launched on an 8-core / 16 GB laptop will never claim
|
|
139
|
+
32 cores / 128 GB of RAM — keeps fingerprints internally consistent
|
|
140
|
+
with real-world hardware.
|
|
141
|
+
|
|
142
|
+
### Override fingerprint fields
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
profile = sdk.library.load("win-rtx4060").with_override(
|
|
146
|
+
name="my-account",
|
|
147
|
+
timezone="Europe/Berlin",
|
|
148
|
+
navigator={"language": "de-DE"},
|
|
149
|
+
)
|
|
150
|
+
async with sdk.session(profile, proxy="socks5://...") as browser:
|
|
151
|
+
...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Use your own fingerprint JSON
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from shardx import Profile
|
|
158
|
+
|
|
159
|
+
profile = Profile.from_file("/path/to/my-custom.json")
|
|
160
|
+
async with sdk.session(profile) as browser:
|
|
161
|
+
...
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### WebRTC policy
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
async with sdk.session(
|
|
168
|
+
"win-rtx4060",
|
|
169
|
+
proxy="socks5://...",
|
|
170
|
+
webrtc="tcp_only", # or "block" | "auto" (default)
|
|
171
|
+
webrtc_public_ip="203.0.113.42", # advertised in ICE candidates
|
|
172
|
+
) as browser:
|
|
173
|
+
...
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Advanced: raw launch without patchright
|
|
177
|
+
|
|
178
|
+
If you'd rather drive the browser with a different CDP client (raw
|
|
179
|
+
`pychrome`, `pyppeteer`, your own WebSocket), skip `session()` and use
|
|
180
|
+
`launch()` directly:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
sess = sdk.launch("win-rtx4060", proxy="socks5://...", cdp=True)
|
|
184
|
+
print(sess.cdp_url) # ws://127.0.0.1:54113/devtools/browser/c0a3…
|
|
185
|
+
# … drive it yourself …
|
|
186
|
+
sess.stop()
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
`launch()` does the same pre-launch pipeline (auto-resolve, screen
|
|
190
|
+
strategy, UDP probe, hw randomisation) and returns a `BrowserSession`
|
|
191
|
+
with `cdp_url`, `geo`, `proxy_udp_ms`, `quic_enabled`, `webrtc_mode`,
|
|
192
|
+
`user_data_dir`, and `stop()`.
|
|
193
|
+
|
|
194
|
+
## Cache layout
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
~/Library/Application Support/shardx-sdk/ (mac)
|
|
198
|
+
%LOCALAPPDATA%\shardx-sdk\ (win)
|
|
199
|
+
~/.cache/shardx-sdk/ (linux)
|
|
200
|
+
├── manifest.json ← etag cache for browser/widevine/fingerprints
|
|
201
|
+
├── ShardX-Mac-arm64/ ← extracted engine
|
|
202
|
+
│ └── ShardX.app/…
|
|
203
|
+
├── fingerprints/ ← 170 bundled .json profiles
|
|
204
|
+
│ ├── win-rtx4060.json
|
|
205
|
+
│ └── …
|
|
206
|
+
└── profiles/ ← per-launch user-data-dir (cookies, IndexedDB, cache)
|
|
207
|
+
└── <profile-id>/
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Override the cache root:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
sdk = ShardX(cache_dir="/data/shardx")
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Update the runtime
|
|
217
|
+
|
|
218
|
+
The SDK auto-checks remote etags on the first `session`/`launch`/`list_profiles`
|
|
219
|
+
call of each process and re-downloads anything that changed. To force a
|
|
220
|
+
re-download mid-process (e.g. CI scenarios):
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
sdk.runtime.install(force=True)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## License
|
|
227
|
+
|
|
228
|
+
MIT (this SDK). The Chromium-fork engine binary downloaded at runtime
|
|
229
|
+
is a closed-source product — see the
|
|
230
|
+
[main repo](https://github.com/ProxyShard/ShardBrowser) for engine
|
|
231
|
+
licensing.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "shardx"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Self-contained Python SDK for the ShardX anti-detect browser — downloads the engine + Widevine + fingerprint library on first use, launches isolated profiles."
|
|
5
|
+
authors = [{ name = "ProxyShard", email = "support@proxyshard.com" }]
|
|
6
|
+
license = { text = "MIT" }
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
requires-python = ">=3.9"
|
|
9
|
+
keywords = ["anti-detect", "browser", "fingerprint", "chromium", "scraping", "multi-accounting", "automation"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Operating System :: MacOS",
|
|
15
|
+
"Operating System :: Microsoft :: Windows",
|
|
16
|
+
"Operating System :: POSIX :: Linux",
|
|
17
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
18
|
+
"Topic :: Internet :: WWW/HTTP :: Browsers",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"httpx[socks]>=0.27",
|
|
23
|
+
# patchright is a stealth-patched Playwright fork; `sdk.session()`
|
|
24
|
+
# returns a patchright Browser ready to drive (no manual CDP wiring).
|
|
25
|
+
"patchright>=1.49",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/ProxyShard/ShardBrowser"
|
|
30
|
+
Documentation = "https://docs.proxyshard.com"
|
|
31
|
+
Issues = "https://github.com/ProxyShard/ShardBrowser/issues"
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["hatchling"]
|
|
35
|
+
build-backend = "hatchling.build"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.wheel]
|
|
38
|
+
packages = ["shardx"]
|