unrealon 2.0.11__tar.gz → 2.0.12__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.
Files changed (141) hide show
  1. {unrealon-2.0.11/unrealon.egg-info → unrealon-2.0.12}/PKG-INFO +1 -1
  2. {unrealon-2.0.11 → unrealon-2.0.12}/pyproject.toml +1 -1
  3. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/core/browser_manager.py +58 -0
  4. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/__init__.py +12 -2
  5. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +8 -1
  6. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/browser.py +16 -1
  7. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/proxy.py +11 -4
  8. unrealon-2.0.12/unrealon-driver/src/unrealon_driver/utils/__init__.py +18 -0
  9. unrealon-2.0.12/unrealon-driver/src/unrealon_driver/utils/platform_compatibility.py +205 -0
  10. {unrealon-2.0.11 → unrealon-2.0.12/unrealon.egg-info}/PKG-INFO +1 -1
  11. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon.egg-info/SOURCES.txt +1 -0
  12. unrealon-2.0.11/unrealon-driver/src/unrealon_driver/utils/__init__.py +0 -9
  13. {unrealon-2.0.11 → unrealon-2.0.12}/LICENSE +0 -0
  14. {unrealon-2.0.11 → unrealon-2.0.12}/MANIFEST.in +0 -0
  15. {unrealon-2.0.11 → unrealon-2.0.12}/README.md +0 -0
  16. {unrealon-2.0.11 → unrealon-2.0.12}/setup.cfg +0 -0
  17. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/README.md +0 -0
  18. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/__init__.py +0 -0
  19. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/cli/__init__.py +0 -0
  20. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/cli/browser_cli.py +0 -0
  21. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/cli/cookies_cli.py +0 -0
  22. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py +0 -0
  23. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/cli/main.py +0 -0
  24. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/core/__init__.py +0 -0
  25. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/__init__.py +0 -0
  26. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +0 -0
  27. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/config.py +0 -0
  28. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/core.py +0 -0
  29. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py +0 -0
  30. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/detection.py +0 -0
  31. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/enums.py +0 -0
  32. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py +0 -0
  33. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/__init__.py +0 -0
  34. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/captcha.py +0 -0
  35. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/cookies.py +0 -0
  36. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py +0 -0
  37. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py +0 -0
  38. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/profile.py +0 -0
  39. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/managers/script_manager.py +0 -0
  40. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/__init__.py +0 -0
  41. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.py +0 -0
  42. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/manager.py +0 -0
  43. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.py +0 -0
  44. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.py +0 -0
  45. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.py +0 -0
  46. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.py +0 -0
  47. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/__init__.py +0 -0
  48. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/config/__init__.py +0 -0
  49. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/config/environment.py +0 -0
  50. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/config/urls.py +0 -0
  51. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/enums/__init__.py +0 -0
  52. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/enums/events.py +0 -0
  53. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/enums/jobs.py +0 -0
  54. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/enums/status.py +0 -0
  55. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/enums/types.py +0 -0
  56. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/error_handling/__init__.py +0 -0
  57. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +0 -0
  58. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/error_handling/error_context.py +0 -0
  59. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/error_handling/recovery.py +0 -0
  60. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/error_handling/retry.py +0 -0
  61. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/__init__.py +0 -0
  62. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/base.py +0 -0
  63. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/communication.py +0 -0
  64. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/driver.py +0 -0
  65. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/proxy.py +0 -0
  66. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/task.py +0 -0
  67. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/exceptions/validation.py +0 -0
  68. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/__init__.py +0 -0
  69. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/arq_context.py +0 -0
  70. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/arq_responses.py +0 -0
  71. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/authentication.py +0 -0
  72. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/base.py +0 -0
  73. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/bridge_stats.py +0 -0
  74. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/communication.py +0 -0
  75. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/connection_stats.py +0 -0
  76. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/driver.py +0 -0
  77. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/driver_details.py +0 -0
  78. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/logging.py +0 -0
  79. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/task.py +0 -0
  80. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/typed_responses.py +0 -0
  81. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/__init__.py +0 -0
  82. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/base.py +0 -0
  83. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py +0 -0
  84. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/config.py +0 -0
  85. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/driver.py +0 -0
  86. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/errors.py +0 -0
  87. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +0 -0
  88. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/logging.py +0 -0
  89. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/proxy.py +0 -0
  90. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/tasks.py +0 -0
  91. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket/utils.py +0 -0
  92. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/models/websocket_session.py +0 -0
  93. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/monitoring/__init__.py +0 -0
  94. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/monitoring/alerts.py +0 -0
  95. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/monitoring/dashboard.py +0 -0
  96. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/monitoring/health_check.py +0 -0
  97. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/monitoring/metrics.py +0 -0
  98. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/utils/__init__.py +0 -0
  99. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/utils/time.py +0 -0
  100. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-core/src/unrealon_core/version.py +0 -0
  101. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/__init__.py +0 -0
  102. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/base.py +0 -0
  103. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/config.py +0 -0
  104. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +0 -0
  105. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/protocols.py +0 -0
  106. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/core_module/registry.py +0 -0
  107. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/decorators/__init__.py +0 -0
  108. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/decorators/retry.py +0 -0
  109. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/decorators/schedule.py +0 -0
  110. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/decorators/task.py +0 -0
  111. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/decorators/timing.py +0 -0
  112. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/__init__.py +0 -0
  113. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +0 -0
  114. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/communication/session.py +0 -0
  115. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +0 -0
  116. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +0 -0
  117. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/core/config.py +0 -0
  118. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/core/driver.py +0 -0
  119. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +0 -0
  120. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +0 -0
  121. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +0 -0
  122. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +0 -0
  123. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +0 -0
  124. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +0 -0
  125. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +0 -0
  126. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +0 -0
  127. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +0 -0
  128. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +0 -0
  129. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/__init__.py +0 -0
  130. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/base.py +0 -0
  131. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/cache.py +0 -0
  132. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/http.py +0 -0
  133. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/logger.py +0 -0
  134. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/registry.py +0 -0
  135. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/threading.py +0 -0
  136. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/managers/update.py +0 -0
  137. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon-driver/src/unrealon_driver/utils/time.py +0 -0
  138. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon.egg-info/dependency_links.txt +0 -0
  139. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon.egg-info/entry_points.txt +0 -0
  140. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon.egg-info/requires.txt +0 -0
  141. {unrealon-2.0.11 → unrealon-2.0.12}/unrealon.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.11
3
+ Version: 2.0.12
4
4
  Summary: Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities
5
5
  Author-email: UnrealOn Team <team@unrealon.com>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "unrealon"
7
- version = "2.0.11"
7
+ version = "2.0.12"
8
8
  description = "Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities"
9
9
  authors = [
10
10
  {name = "UnrealOn Team", email = "team@unrealon.com"}
@@ -55,6 +55,9 @@ class BrowserManager:
55
55
  self._page = None
56
56
  self._initialized = False
57
57
  self._statistics = BrowserManagerStatistics()
58
+
59
+ # Proxy settings (can be set externally)
60
+ self._proxy_url: Optional[str] = None
58
61
 
59
62
  # Initialize logger bridge first
60
63
  self.logger_bridge = create_browser_logger_bridge(session_id=self._generate_session_id(), parser_id=self.parser_id, enable_console=True) # Use resolved parser_id
@@ -197,6 +200,12 @@ class BrowserManager:
197
200
  "ignore_default_args": ["--enable-automation"],
198
201
  **context_options, # viewport, user_agent, etc.
199
202
  }
203
+
204
+ # Add proxy configuration for persistent context
205
+ if self._proxy_url:
206
+ proxy_config = self._get_playwright_proxy_config()
207
+ if proxy_config:
208
+ persistent_args["proxy"] = proxy_config
200
209
 
201
210
  # Use persistent context with user_data_dir for profiles
202
211
  if self.config.browser_type == BrowserType.CHROMIUM:
@@ -223,6 +232,12 @@ class BrowserManager:
223
232
  raise ValueError(f"Unsupported browser type: {self.config.browser_type}")
224
233
 
225
234
  # Create context without profile
235
+ # Add proxy configuration for context
236
+ if self._proxy_url:
237
+ proxy_config = self._get_playwright_proxy_config()
238
+ if proxy_config:
239
+ context_options["proxy"] = proxy_config
240
+
226
241
  self._context = await self._browser.new_context(**context_options)
227
242
 
228
243
  # 🔥 STEALTH ALWAYS ON - NO CONFIG NEEDED!
@@ -276,6 +291,9 @@ class BrowserManager:
276
291
  # 🔥 STEALTH ALWAYS ON - ALWAYS ADD STEALTH ARGS!
277
292
  browser_args.extend(self.stealth_manager.get_stealth_args())
278
293
 
294
+ # Note: Proxy configuration is now handled via Playwright API in context options
295
+ # instead of command line arguments for better compatibility
296
+
279
297
  if self.config.disable_images:
280
298
  browser_args.extend(
281
299
  [
@@ -286,6 +304,46 @@ class BrowserManager:
286
304
 
287
305
  args["args"] = browser_args
288
306
  return args
307
+
308
+ def _get_playwright_proxy_config(self) -> Optional[Dict[str, Any]]:
309
+ """
310
+ Get Playwright-compatible proxy configuration.
311
+
312
+ Returns:
313
+ Proxy configuration dict for Playwright or None if not supported
314
+ """
315
+ if not self._proxy_url:
316
+ return None
317
+
318
+ try:
319
+ from urllib.parse import urlparse
320
+
321
+ parsed = urlparse(self._proxy_url)
322
+
323
+ # Playwright proxy configuration
324
+ proxy_config = {
325
+ "server": f"{parsed.scheme}://{parsed.hostname}:{parsed.port}"
326
+ }
327
+
328
+ # Add authentication if present
329
+ if parsed.username and parsed.password:
330
+ # WARNING: Playwright does NOT support SOCKS5 authentication!
331
+ if parsed.scheme == 'socks5':
332
+ self.logger_bridge.log_warning("⚠️ Playwright does not support SOCKS5 authentication!")
333
+ self.logger_bridge.log_warning("⚠️ Falling back to SOCKS5 without auth - may fail!")
334
+ # Return configuration without authentication for SOCKS5
335
+ return proxy_config
336
+ else:
337
+ # HTTP/HTTPS proxies support authentication
338
+ proxy_config["username"] = parsed.username
339
+ proxy_config["password"] = parsed.password
340
+
341
+ self.logger_bridge.log_info(f"🔒 Playwright proxy config: {proxy_config['server']}")
342
+ return proxy_config
343
+
344
+ except Exception as e:
345
+ self.logger_bridge.log_error(f"❌ Failed to parse proxy URL: {e}")
346
+ return None
289
347
 
290
348
  def _get_context_options(self) -> Dict[str, Any]:
291
349
  """Get browser context options"""
@@ -60,15 +60,20 @@ from .decorators import (
60
60
  timing
61
61
  )
62
62
 
63
+ # Utilities - Cross-platform compatibility
64
+ from .utils import (
65
+ PlatformCompatibility,
66
+ ensure_platform_compatibility,
67
+ get_platform_info
68
+ )
69
+
63
70
  __version__ = get_driver_version()
64
71
  __author__ = "UnrealOn Team"
65
- __phase__ = "Phase 3.8: Clean Refactor"
66
72
 
67
73
  __all__ = [
68
74
  # Version
69
75
  "__version__",
70
76
  "__author__",
71
- "__phase__",
72
77
 
73
78
  # Core API
74
79
  "UniversalDriver",
@@ -102,4 +107,9 @@ __all__ = [
102
107
  "retry",
103
108
  "schedule",
104
109
  "timing",
110
+
111
+ # Utilities
112
+ "PlatformCompatibility",
113
+ "ensure_platform_compatibility",
114
+ "get_platform_info",
105
115
  ]
@@ -81,11 +81,18 @@ class ManagerFactory:
81
81
  @staticmethod
82
82
  def _setup_browser_manager(driver: 'UniversalDriver', registry: ManagerRegistry):
83
83
  """Setup browser manager."""
84
+ # Get proxy URL from proxy manager if enabled
85
+ proxy_url = None
86
+ if driver.config.proxy_enabled and hasattr(driver, 'proxy') and driver.proxy:
87
+ proxy_url = driver.proxy.get_proxy()
88
+
84
89
  browser_config = BrowserManagerConfig(
85
90
  enabled=True,
86
91
  headless=driver.config.browser_headless,
87
92
  timeout=driver.config.browser_timeout,
88
- parser_name=driver.driver_id
93
+ parser_name=driver.driver_id,
94
+ proxy_enabled=driver.config.proxy_enabled,
95
+ proxy_url=proxy_url
89
96
  )
90
97
  driver.browser = BrowserManager(browser_config)
91
98
  registry.register(driver.browser)
@@ -17,6 +17,11 @@ class BrowserManagerConfig(ManagerConfig):
17
17
  headless: bool = Field(default=True, description="Run headless")
18
18
  parser_name: str = Field(..., description="Parser name for browser")
19
19
  stealth_warmup_enabled: bool = Field(default=False, description="Enable stealth warmup")
20
+
21
+ # Proxy settings
22
+ proxy_enabled: bool = Field(default=False, description="Enable proxy usage")
23
+ proxy_url: Optional[str] = Field(default=None, description="Proxy URL (http://user:pass@host:port)")
24
+ proxy_timeout: int = Field(default=30, description="Proxy timeout in seconds")
20
25
 
21
26
 
22
27
  class BrowserManager(BaseManager):
@@ -53,6 +58,12 @@ class BrowserManager(BaseManager):
53
58
  try:
54
59
  self.logger.info("🚀 Starting browser (lazy initialization)...")
55
60
 
61
+ # Log proxy status
62
+ if self.config.proxy_enabled and self.config.proxy_url:
63
+ self.logger.info(f"🔒 Proxy enabled: {self.config.proxy_url}")
64
+ else:
65
+ self.logger.info("🌐 No proxy configured")
66
+
56
67
  # Create browser config with proper headless mode
57
68
  browser_mode = BrowserMode.HEADLESS if self.config.headless else BrowserMode.HEADED
58
69
 
@@ -62,8 +73,12 @@ class BrowserManager(BaseManager):
62
73
  stealth_warmup_enabled=self.config.stealth_warmup_enabled
63
74
  )
64
75
 
65
- # Create browser manager
76
+ # Create browser manager with proxy support
66
77
  self.browser = CoreBrowserManager(browser_config)
78
+
79
+ # Set proxy if enabled (we'll need to modify CoreBrowserManager to support this)
80
+ if self.config.proxy_enabled and self.config.proxy_url:
81
+ self.browser._proxy_url = self.config.proxy_url
67
82
 
68
83
  # Initialize browser
69
84
  await self.browser.initialize_async()
@@ -13,6 +13,7 @@ from .base import BaseManager, ManagerConfig
13
13
  class ProxyManagerConfig(ManagerConfig):
14
14
  """Proxy manager configuration."""
15
15
  proxies: List[str] = Field(default_factory=list, description="List of proxy URLs")
16
+ single_proxy: Optional[str] = Field(default=None, description="Single proxy URL to use")
16
17
  rotation_interval: int = Field(default=300, description="Rotation interval seconds")
17
18
  health_check_interval: int = Field(default=60, description="Health check interval")
18
19
 
@@ -29,11 +30,17 @@ class ProxyManager(BaseManager):
29
30
 
30
31
  async def _initialize(self) -> bool:
31
32
  """Initialize proxy manager."""
32
- self.active_proxies = self.config.proxies.copy()
33
+ # Use single proxy if specified, otherwise use proxy list
34
+ if self.config.single_proxy:
35
+ self.active_proxies = [self.config.single_proxy]
36
+ self.current_proxy = self.config.single_proxy
37
+ else:
38
+ self.active_proxies = self.config.proxies.copy()
39
+ if self.active_proxies:
40
+ self.current_proxy = random.choice(self.active_proxies)
33
41
 
34
- if self.active_proxies:
35
- self.current_proxy = random.choice(self.active_proxies)
36
- # Start rotation task
42
+ # Only start rotation if we have multiple proxies
43
+ if len(self.active_proxies) > 1:
37
44
  self._rotation_task = asyncio.create_task(self._rotation_loop())
38
45
 
39
46
  return True
@@ -0,0 +1,18 @@
1
+ """
2
+ Utility modules for UnrealOn Driver.
3
+
4
+ Contains cross-platform compatibility and other utility functions.
5
+ """
6
+ from .time import utc_now
7
+ from .platform_compatibility import (
8
+ PlatformCompatibility,
9
+ ensure_platform_compatibility,
10
+ get_platform_info
11
+ )
12
+
13
+ __all__ = [
14
+ 'utc_now',
15
+ 'PlatformCompatibility',
16
+ 'ensure_platform_compatibility',
17
+ 'get_platform_info'
18
+ ]
@@ -0,0 +1,205 @@
1
+ """
2
+ Cross-platform compatibility utilities for UnrealOn Driver.
3
+
4
+ Handles platform-specific configurations and fixes for Windows, macOS, and Linux.
5
+ """
6
+
7
+ import asyncio
8
+ import sys
9
+ import platform
10
+ import warnings
11
+ from typing import Optional
12
+ import logging
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class PlatformCompatibility:
18
+ """
19
+ Handles cross-platform compatibility for UnrealOn Driver.
20
+
21
+ Automatically applies platform-specific fixes and configurations
22
+ to ensure consistent behavior across Windows, macOS, and Linux.
23
+ """
24
+
25
+ def __init__(self):
26
+ """Initialize platform compatibility."""
27
+ self.platform = platform.system()
28
+ self.python_version = sys.version_info
29
+ self._applied_fixes = []
30
+
31
+ def apply_all_fixes(self) -> None:
32
+ """
33
+ Apply all platform-specific fixes automatically.
34
+
35
+ This method should be called once at the start of the application
36
+ to ensure optimal cross-platform compatibility.
37
+ """
38
+ logger.info(f"🔧 Applying platform fixes for {self.platform}")
39
+
40
+ if self.platform == "Windows":
41
+ self._apply_windows_fixes()
42
+ elif self.platform == "Darwin": # macOS
43
+ self._apply_macos_fixes()
44
+ elif self.platform == "Linux":
45
+ self._apply_linux_fixes()
46
+
47
+ logger.info(f"✅ Applied {len(self._applied_fixes)} platform fixes: {', '.join(self._applied_fixes)}")
48
+
49
+ def _apply_windows_fixes(self) -> None:
50
+ """Apply Windows-specific fixes."""
51
+
52
+ # Fix 1: Set ProactorEventLoopPolicy for better asyncio performance
53
+ if self.python_version >= (3, 8):
54
+ try:
55
+ asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
56
+ self._applied_fixes.append("WindowsProactorEventLoopPolicy")
57
+ logger.debug("✅ Set WindowsProactorEventLoopPolicy for better asyncio performance")
58
+ except Exception as e:
59
+ logger.warning(f"⚠️ Failed to set WindowsProactorEventLoopPolicy: {e}")
60
+
61
+ # Fix 2: Suppress ResourceWarning on Windows
62
+ try:
63
+ warnings.filterwarnings("ignore", category=ResourceWarning)
64
+ self._applied_fixes.append("ResourceWarning suppression")
65
+ logger.debug("✅ Suppressed ResourceWarning for cleaner output")
66
+ except Exception as e:
67
+ logger.warning(f"⚠️ Failed to suppress ResourceWarning: {e}")
68
+
69
+ # Fix 3: Set console encoding to UTF-8 if possible
70
+ try:
71
+ if hasattr(sys.stdout, 'reconfigure'):
72
+ sys.stdout.reconfigure(encoding='utf-8')
73
+ sys.stderr.reconfigure(encoding='utf-8')
74
+ self._applied_fixes.append("UTF-8 console encoding")
75
+ logger.debug("✅ Set console encoding to UTF-8")
76
+ except Exception as e:
77
+ logger.debug(f"Console encoding fix not needed or failed: {e}")
78
+
79
+ # Fix 4: Increase default socket timeout for Windows
80
+ try:
81
+ import socket
82
+ socket.setdefaulttimeout(30.0)
83
+ self._applied_fixes.append("Socket timeout increase")
84
+ logger.debug("✅ Increased default socket timeout to 30s")
85
+ except Exception as e:
86
+ logger.warning(f"⚠️ Failed to set socket timeout: {e}")
87
+
88
+ def _apply_macos_fixes(self) -> None:
89
+ """Apply macOS-specific fixes."""
90
+
91
+ # Fix 1: Handle macOS SSL context issues
92
+ try:
93
+ import ssl
94
+ # Create unverified SSL context for development
95
+ ssl._create_default_https_context = ssl._create_unverified_context
96
+ self._applied_fixes.append("SSL context fix")
97
+ logger.debug("✅ Applied macOS SSL context fix")
98
+ except Exception as e:
99
+ logger.debug(f"SSL context fix not needed: {e}")
100
+
101
+ # Fix 2: Set optimal file descriptor limits
102
+ try:
103
+ import resource
104
+ soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
105
+ if soft < 1024:
106
+ resource.setrlimit(resource.RLIMIT_NOFILE, (min(1024, hard), hard))
107
+ self._applied_fixes.append("File descriptor limit increase")
108
+ logger.debug("✅ Increased file descriptor limit")
109
+ except Exception as e:
110
+ logger.debug(f"File descriptor limit fix not needed: {e}")
111
+
112
+ def _apply_linux_fixes(self) -> None:
113
+ """Apply Linux-specific fixes."""
114
+
115
+ # Fix 1: Set optimal file descriptor limits
116
+ try:
117
+ import resource
118
+ soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
119
+ if soft < 2048:
120
+ resource.setrlimit(resource.RLIMIT_NOFILE, (min(2048, hard), hard))
121
+ self._applied_fixes.append("File descriptor limit increase")
122
+ logger.debug("✅ Increased file descriptor limit")
123
+ except Exception as e:
124
+ logger.debug(f"File descriptor limit fix not needed: {e}")
125
+
126
+ # Fix 2: Handle display issues for headless environments
127
+ try:
128
+ import os
129
+ if not os.environ.get('DISPLAY'):
130
+ os.environ['DISPLAY'] = ':99'
131
+ self._applied_fixes.append("Headless display fix")
132
+ logger.debug("✅ Set display for headless environment")
133
+ except Exception as e:
134
+ logger.debug(f"Display fix not needed: {e}")
135
+
136
+ def get_platform_info(self) -> dict:
137
+ """
138
+ Get detailed platform information.
139
+
140
+ Returns:
141
+ Dictionary with platform details
142
+ """
143
+ return {
144
+ 'platform': self.platform,
145
+ 'platform_release': platform.release(),
146
+ 'platform_version': platform.version(),
147
+ 'architecture': platform.architecture(),
148
+ 'machine': platform.machine(),
149
+ 'processor': platform.processor(),
150
+ 'python_version': f"{self.python_version.major}.{self.python_version.minor}.{self.python_version.micro}",
151
+ 'python_implementation': platform.python_implementation(),
152
+ 'applied_fixes': self._applied_fixes
153
+ }
154
+
155
+ @classmethod
156
+ def auto_configure(cls) -> 'PlatformCompatibility':
157
+ """
158
+ Automatically configure platform compatibility.
159
+
160
+ This is the recommended way to use this class - it will
161
+ automatically detect the platform and apply all necessary fixes.
162
+
163
+ Returns:
164
+ Configured PlatformCompatibility instance
165
+ """
166
+ compatibility = cls()
167
+ compatibility.apply_all_fixes()
168
+ return compatibility
169
+
170
+
171
+ # Global instance for easy access
172
+ _platform_compatibility: Optional[PlatformCompatibility] = None
173
+
174
+
175
+ def ensure_platform_compatibility() -> PlatformCompatibility:
176
+ """
177
+ Ensure platform compatibility is configured.
178
+
179
+ This function can be called multiple times safely - it will only
180
+ configure compatibility once per application run.
181
+
182
+ Returns:
183
+ PlatformCompatibility instance
184
+ """
185
+ global _platform_compatibility
186
+
187
+ if _platform_compatibility is None:
188
+ _platform_compatibility = PlatformCompatibility.auto_configure()
189
+
190
+ return _platform_compatibility
191
+
192
+
193
+ def get_platform_info() -> dict:
194
+ """
195
+ Get platform information.
196
+
197
+ Returns:
198
+ Dictionary with platform details
199
+ """
200
+ compatibility = ensure_platform_compatibility()
201
+ return compatibility.get_platform_info()
202
+
203
+
204
+ # Auto-configure on import for convenience
205
+ ensure_platform_compatibility()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.11
3
+ Version: 2.0.12
4
4
  Summary: Enterprise-grade web scraping platform with AI-powered automation and real-time orchestration capabilities
5
5
  Author-email: UnrealOn Team <team@unrealon.com>
6
6
  License: MIT
@@ -128,6 +128,7 @@ unrealon-driver/src/unrealon_driver/managers/registry.py
128
128
  unrealon-driver/src/unrealon_driver/managers/threading.py
129
129
  unrealon-driver/src/unrealon_driver/managers/update.py
130
130
  unrealon-driver/src/unrealon_driver/utils/__init__.py
131
+ unrealon-driver/src/unrealon_driver/utils/platform_compatibility.py
131
132
  unrealon-driver/src/unrealon_driver/utils/time.py
132
133
  unrealon.egg-info/PKG-INFO
133
134
  unrealon.egg-info/SOURCES.txt
@@ -1,9 +0,0 @@
1
- """
2
- Utility functions for UnrealOn Driver.
3
- """
4
-
5
- from .time import utc_now
6
-
7
- __all__ = [
8
- "utc_now",
9
- ]
File without changes
File without changes
File without changes
File without changes