Spaces:
Sleeping
feat: add audio support for browser portal and audio captchas
Browse filesAudio Support:
- Added browser args for audio autoplay and media stream
- Enabled microphone and camera permissions in browser context
- Added AudioContext wrapper for proper audio initialization
- Audio elements can now autoplay without user gesture
- Support for audio captchas (reCAPTCHA audio challenges)
- Media stream permissions for WebRTC applications
Browser Args Added:
- --autoplay-policy=no-user-gesture-required
- --use-fake-ui-for-media-stream
- --use-fake-device-for-media-stream
- --enable-features=AudioServiceOutOfProcess
- --disable-features=AudioServiceSandbox
Stealth Scripts Added:
- AudioContext constructor wrapper
- HTMLMediaElement.play() override for autoplay
- Proper destination channel count mocking
This enables:
- Audio captcha solving
- Video/audio playback in browser
- WebRTC applications
- Full multimedia browser experience
- browser_portal.py +35 -3
|
@@ -126,7 +126,7 @@ class BrowserPortal:
|
|
| 126 |
|
| 127 |
self.playwright = await async_playwright().start()
|
| 128 |
|
| 129 |
-
# Maximum stealth args
|
| 130 |
args = [
|
| 131 |
"--disable-blink-features=AutomationControlled",
|
| 132 |
"--disable-features=IsolateOrigins,site-per-process",
|
|
@@ -147,6 +147,12 @@ class BrowserPortal:
|
|
| 147 |
"--no-default-browser-check",
|
| 148 |
"--password-store=basic",
|
| 149 |
"--use-mock-keychain",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
]
|
| 151 |
|
| 152 |
# Build browser launch options
|
|
@@ -161,7 +167,7 @@ class BrowserPortal:
|
|
| 161 |
|
| 162 |
self.browser = await self.playwright.chromium.launch(**launch_options)
|
| 163 |
|
| 164 |
-
# Use a real Chrome user agent
|
| 165 |
self.context = await self.browser.new_context(
|
| 166 |
viewport=self.config.viewport,
|
| 167 |
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
@@ -169,7 +175,7 @@ class BrowserPortal:
|
|
| 169 |
timezone_id="America/New_York",
|
| 170 |
color_scheme="light",
|
| 171 |
geolocation={"latitude": 40.7128, "longitude": -74.0060},
|
| 172 |
-
permissions=["geolocation"],
|
| 173 |
java_script_enabled=True,
|
| 174 |
has_touch=False,
|
| 175 |
is_mobile=False,
|
|
@@ -254,6 +260,32 @@ class BrowserPortal:
|
|
| 254 |
}
|
| 255 |
return getParameter.call(this, parameter);
|
| 256 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
""")
|
| 258 |
|
| 259 |
self.page = await self.context.new_page()
|
|
|
|
| 126 |
|
| 127 |
self.playwright = await async_playwright().start()
|
| 128 |
|
| 129 |
+
# Maximum stealth args with audio support
|
| 130 |
args = [
|
| 131 |
"--disable-blink-features=AutomationControlled",
|
| 132 |
"--disable-features=IsolateOrigins,site-per-process",
|
|
|
|
| 147 |
"--no-default-browser-check",
|
| 148 |
"--password-store=basic",
|
| 149 |
"--use-mock-keychain",
|
| 150 |
+
# Audio support
|
| 151 |
+
"--autoplay-policy=no-user-gesture-required",
|
| 152 |
+
"--use-fake-ui-for-media-stream",
|
| 153 |
+
"--use-fake-device-for-media-stream",
|
| 154 |
+
"--enable-features=AudioServiceOutOfProcess",
|
| 155 |
+
"--disable-features=AudioServiceSandbox",
|
| 156 |
]
|
| 157 |
|
| 158 |
# Build browser launch options
|
|
|
|
| 167 |
|
| 168 |
self.browser = await self.playwright.chromium.launch(**launch_options)
|
| 169 |
|
| 170 |
+
# Use a real Chrome user agent with audio permissions
|
| 171 |
self.context = await self.browser.new_context(
|
| 172 |
viewport=self.config.viewport,
|
| 173 |
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
|
|
| 175 |
timezone_id="America/New_York",
|
| 176 |
color_scheme="light",
|
| 177 |
geolocation={"latitude": 40.7128, "longitude": -74.0060},
|
| 178 |
+
permissions=["geolocation", "microphone", "camera"],
|
| 179 |
java_script_enabled=True,
|
| 180 |
has_touch=False,
|
| 181 |
is_mobile=False,
|
|
|
|
| 260 |
}
|
| 261 |
return getParameter.call(this, parameter);
|
| 262 |
};
|
| 263 |
+
|
| 264 |
+
// Audio Context support for audio captchas
|
| 265 |
+
if (window.AudioContext || window.webkitAudioContext) {
|
| 266 |
+
const OriginalAudioContext = window.AudioContext || window.webkitAudioContext;
|
| 267 |
+
window.AudioContext = function() {
|
| 268 |
+
const instance = new OriginalAudioContext();
|
| 269 |
+
// Ensure destination is properly connected
|
| 270 |
+
if (instance.destination) {
|
| 271 |
+
Object.defineProperty(instance.destination, 'maxChannelCount', {
|
| 272 |
+
get: () => 2
|
| 273 |
+
});
|
| 274 |
+
}
|
| 275 |
+
return instance;
|
| 276 |
+
};
|
| 277 |
+
window.AudioContext.prototype = OriginalAudioContext.prototype;
|
| 278 |
+
if (window.webkitAudioContext) {
|
| 279 |
+
window.webkitAudioContext = window.AudioContext;
|
| 280 |
+
}
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
// Allow audio autoplay
|
| 284 |
+
const originalAudioPlay = HTMLMediaElement.prototype.play;
|
| 285 |
+
HTMLMediaElement.prototype.play = function() {
|
| 286 |
+
this.muted = false;
|
| 287 |
+
return originalAudioPlay.apply(this, arguments);
|
| 288 |
+
};
|
| 289 |
""")
|
| 290 |
|
| 291 |
self.page = await self.context.new_page()
|