unrealon 2.0.13__tar.gz → 2.0.14__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 (146) hide show
  1. {unrealon-2.0.13/unrealon.egg-info → unrealon-2.0.14}/PKG-INFO +1 -1
  2. {unrealon-2.0.13 → unrealon-2.0.14}/pyproject.toml +1 -1
  3. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/__init__.py +2 -10
  4. unrealon-2.0.14/unrealon-driver/src/unrealon_driver/utils/__init__.py +10 -0
  5. unrealon-2.0.14/unrealon-driver/src/unrealon_installer/__init__.py +11 -0
  6. unrealon-2.0.14/unrealon-driver/src/unrealon_installer/browser_fixes.py +227 -0
  7. unrealon-2.0.14/unrealon-driver/src/unrealon_installer/core.py +166 -0
  8. unrealon-2.0.14/unrealon-driver/src/unrealon_installer/platform.py +122 -0
  9. unrealon-2.0.14/unrealon-driver/src/unrealon_installer/templates.py +60 -0
  10. {unrealon-2.0.13 → unrealon-2.0.14/unrealon.egg-info}/PKG-INFO +1 -1
  11. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon.egg-info/SOURCES.txt +5 -1
  12. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon.egg-info/top_level.txt +1 -0
  13. unrealon-2.0.13/unrealon-driver/src/unrealon_driver/utils/__init__.py +0 -18
  14. unrealon-2.0.13/unrealon-driver/src/unrealon_driver/utils/platform_compatibility.py +0 -205
  15. {unrealon-2.0.13 → unrealon-2.0.14}/LICENSE +0 -0
  16. {unrealon-2.0.13 → unrealon-2.0.14}/MANIFEST.in +0 -0
  17. {unrealon-2.0.13 → unrealon-2.0.14}/README.md +0 -0
  18. {unrealon-2.0.13 → unrealon-2.0.14}/setup.cfg +0 -0
  19. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/README.md +0 -0
  20. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/__init__.py +0 -0
  21. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/cli/__init__.py +0 -0
  22. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/cli/browser_cli.py +0 -0
  23. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/cli/cookies_cli.py +0 -0
  24. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py +0 -0
  25. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/cli/main.py +0 -0
  26. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/core/__init__.py +0 -0
  27. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/core/browser_manager.py +0 -0
  28. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/__init__.py +0 -0
  29. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +0 -0
  30. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/config.py +0 -0
  31. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/core.py +0 -0
  32. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py +0 -0
  33. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/detection.py +0 -0
  34. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/enums.py +0 -0
  35. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py +0 -0
  36. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/__init__.py +0 -0
  37. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/captcha.py +0 -0
  38. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/cookies.py +0 -0
  39. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py +0 -0
  40. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py +0 -0
  41. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/profile.py +0 -0
  42. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/managers/script_manager.py +0 -0
  43. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/__init__.py +0 -0
  44. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.py +0 -0
  45. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/manager.py +0 -0
  46. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.py +0 -0
  47. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.py +0 -0
  48. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.py +0 -0
  49. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.py +0 -0
  50. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/__init__.py +0 -0
  51. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/config/__init__.py +0 -0
  52. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/config/environment.py +0 -0
  53. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/config/urls.py +0 -0
  54. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/enums/__init__.py +0 -0
  55. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/enums/events.py +0 -0
  56. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/enums/jobs.py +0 -0
  57. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/enums/status.py +0 -0
  58. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/enums/types.py +0 -0
  59. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/error_handling/__init__.py +0 -0
  60. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +0 -0
  61. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/error_handling/error_context.py +0 -0
  62. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/error_handling/recovery.py +0 -0
  63. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/error_handling/retry.py +0 -0
  64. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/__init__.py +0 -0
  65. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/base.py +0 -0
  66. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/communication.py +0 -0
  67. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/driver.py +0 -0
  68. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/proxy.py +0 -0
  69. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/task.py +0 -0
  70. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/exceptions/validation.py +0 -0
  71. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/__init__.py +0 -0
  72. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/arq_context.py +0 -0
  73. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/arq_responses.py +0 -0
  74. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/authentication.py +0 -0
  75. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/base.py +0 -0
  76. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/bridge_stats.py +0 -0
  77. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/communication.py +0 -0
  78. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/connection_stats.py +0 -0
  79. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/driver.py +0 -0
  80. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/driver_details.py +0 -0
  81. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/logging.py +0 -0
  82. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/task.py +0 -0
  83. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/typed_responses.py +0 -0
  84. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/__init__.py +0 -0
  85. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/base.py +0 -0
  86. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py +0 -0
  87. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/config.py +0 -0
  88. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/driver.py +0 -0
  89. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/errors.py +0 -0
  90. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +0 -0
  91. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/logging.py +0 -0
  92. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/proxy.py +0 -0
  93. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/tasks.py +0 -0
  94. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket/utils.py +0 -0
  95. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/models/websocket_session.py +0 -0
  96. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/monitoring/__init__.py +0 -0
  97. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/monitoring/alerts.py +0 -0
  98. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/monitoring/dashboard.py +0 -0
  99. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/monitoring/health_check.py +0 -0
  100. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/monitoring/metrics.py +0 -0
  101. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/utils/__init__.py +0 -0
  102. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/utils/time.py +0 -0
  103. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-core/src/unrealon_core/version.py +0 -0
  104. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/__init__.py +0 -0
  105. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/base.py +0 -0
  106. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/config.py +0 -0
  107. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +0 -0
  108. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/protocols.py +0 -0
  109. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/core_module/registry.py +0 -0
  110. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/decorators/__init__.py +0 -0
  111. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/decorators/retry.py +0 -0
  112. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/decorators/schedule.py +0 -0
  113. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/decorators/task.py +0 -0
  114. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/decorators/timing.py +0 -0
  115. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/__init__.py +0 -0
  116. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +0 -0
  117. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/communication/session.py +0 -0
  118. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +0 -0
  119. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +0 -0
  120. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/core/config.py +0 -0
  121. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/core/driver.py +0 -0
  122. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +0 -0
  123. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +0 -0
  124. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +0 -0
  125. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +0 -0
  126. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +0 -0
  127. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +0 -0
  128. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +0 -0
  129. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +0 -0
  130. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +0 -0
  131. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +0 -0
  132. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +0 -0
  133. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/__init__.py +0 -0
  134. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/base.py +0 -0
  135. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/browser.py +0 -0
  136. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/cache.py +0 -0
  137. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/http.py +0 -0
  138. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/logger.py +0 -0
  139. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/proxy.py +0 -0
  140. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/registry.py +0 -0
  141. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/threading.py +0 -0
  142. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/managers/update.py +0 -0
  143. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon-driver/src/unrealon_driver/utils/time.py +0 -0
  144. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon.egg-info/dependency_links.txt +0 -0
  145. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon.egg-info/entry_points.txt +0 -0
  146. {unrealon-2.0.13 → unrealon-2.0.14}/unrealon.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.13
3
+ Version: 2.0.14
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.13"
7
+ version = "2.0.14"
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"}
@@ -60,12 +60,8 @@ 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
- )
63
+ # Utilities - Time utilities only (platform compatibility moved to installer)
64
+ from .utils import time
69
65
 
70
66
  __version__ = get_driver_version()
71
67
  __author__ = "UnrealOn Team"
@@ -108,8 +104,4 @@ __all__ = [
108
104
  "schedule",
109
105
  "timing",
110
106
 
111
- # Utilities
112
- "PlatformCompatibility",
113
- "ensure_platform_compatibility",
114
- "get_platform_info",
115
107
  ]
@@ -0,0 +1,10 @@
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
+
8
+ __all__ = [
9
+ 'utc_now',
10
+ ]
@@ -0,0 +1,11 @@
1
+ """
2
+ UnrealOn Universal Installer - Clean Edition
3
+
4
+ One function installs everything. Simple and reliable.
5
+ """
6
+
7
+ from .core import install_parser
8
+ from .browser_fixes import fix_browsers, diagnose_browsers, get_browser_status
9
+
10
+ __version__ = "2.0.0"
11
+ __all__ = ["install_parser", "fix_browsers", "diagnose_browsers", "get_browser_status"]
@@ -0,0 +1,227 @@
1
+ """
2
+ Browser troubleshooting and fixes for Windows.
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import subprocess
8
+ import platform
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional
11
+ import shutil
12
+
13
+
14
+ class BrowserFixer:
15
+ """Windows browser troubleshooting and fixes."""
16
+
17
+ def __init__(self):
18
+ self.is_windows = platform.system() == "Windows"
19
+ self.playwright_cache = self._get_playwright_cache_path()
20
+
21
+ def _get_playwright_cache_path(self) -> Optional[Path]:
22
+ """Get Playwright cache directory path."""
23
+ if self.is_windows:
24
+ return Path(os.environ.get("USERPROFILE", "")) / "AppData" / "Local" / "ms-playwright"
25
+ elif platform.system() == "Darwin": # macOS
26
+ return Path.home() / "Library" / "Caches" / "ms-playwright"
27
+ else: # Linux
28
+ return Path.home() / ".cache" / "ms-playwright"
29
+
30
+ def diagnose_browser_issues(self) -> Dict[str, bool]:
31
+ """Diagnose common browser issues."""
32
+ issues = {}
33
+
34
+ # Check if Playwright is installed
35
+ issues['playwright_installed'] = self._check_playwright_installed()
36
+
37
+ # Check if browsers are installed
38
+ issues['browsers_installed'] = self._check_browsers_installed()
39
+
40
+ # Check cache directory
41
+ issues['cache_exists'] = self._check_cache_directory()
42
+
43
+ # Check if browsers can launch
44
+ issues['browser_launch_test'] = self._test_browser_launch()
45
+
46
+ return issues
47
+
48
+ def _check_playwright_installed(self) -> bool:
49
+ """Check if Playwright is installed."""
50
+ try:
51
+ subprocess.run([sys.executable, "-c", "import playwright"],
52
+ check=True, capture_output=True)
53
+ return True
54
+ except (subprocess.CalledProcessError, FileNotFoundError):
55
+ return False
56
+
57
+ def _check_browsers_installed(self) -> bool:
58
+ """Check if Playwright browsers are installed."""
59
+ try:
60
+ result = subprocess.run([sys.executable, "-m", "playwright", "--version"],
61
+ check=True, capture_output=True, text=True)
62
+ return "version" in result.stdout.lower()
63
+ except (subprocess.CalledProcessError, FileNotFoundError):
64
+ return False
65
+
66
+ def _check_cache_directory(self) -> bool:
67
+ """Check if Playwright cache directory exists."""
68
+ if not self.playwright_cache:
69
+ return False
70
+ return self.playwright_cache.exists()
71
+
72
+ def _test_browser_launch(self) -> bool:
73
+ """Test if browser can launch (quick test)."""
74
+ try:
75
+ test_code = """
76
+ from playwright.sync_api import sync_playwright
77
+ try:
78
+ with sync_playwright() as p:
79
+ browser = p.chromium.launch(headless=True)
80
+ browser.close()
81
+ print("OK")
82
+ except Exception as e:
83
+ print(f"ERROR: {e}")
84
+ """
85
+ result = subprocess.run([sys.executable, "-c", test_code],
86
+ capture_output=True, text=True, timeout=30)
87
+ return "OK" in result.stdout
88
+ except (subprocess.CalledProcessError, subprocess.TimeoutExpired):
89
+ return False
90
+
91
+ def fix_browser_issues(self, force_reinstall: bool = False) -> bool:
92
+ """Fix common browser issues."""
93
+ print("🔧 Fixing browser issues...")
94
+
95
+ success = True
96
+
97
+ # Step 1: Clear cache if it exists
98
+ if self._clear_browser_cache():
99
+ print("✅ Browser cache cleared")
100
+ else:
101
+ print("⚠️ Could not clear browser cache")
102
+
103
+ # Step 2: Reinstall Playwright if needed or forced
104
+ if force_reinstall or not self._check_playwright_installed():
105
+ if self._reinstall_playwright():
106
+ print("✅ Playwright reinstalled")
107
+ else:
108
+ print("❌ Failed to reinstall Playwright")
109
+ success = False
110
+
111
+ # Step 3: Install browsers
112
+ if self._install_browsers():
113
+ print("✅ Browsers installed")
114
+ else:
115
+ print("❌ Failed to install browsers")
116
+ success = False
117
+
118
+ # Step 4: Test installation
119
+ if self._test_browser_launch():
120
+ print("✅ Browser test passed")
121
+ else:
122
+ print("❌ Browser test failed")
123
+ success = False
124
+
125
+ return success
126
+
127
+ def _clear_browser_cache(self) -> bool:
128
+ """Clear Playwright browser cache."""
129
+ try:
130
+ if self.playwright_cache and self.playwright_cache.exists():
131
+ shutil.rmtree(self.playwright_cache, ignore_errors=True)
132
+ print(f"Cleared cache: {self.playwright_cache}")
133
+ return True
134
+ except Exception as e:
135
+ print(f"Cache clear error: {e}")
136
+ return False
137
+
138
+ def _reinstall_playwright(self) -> bool:
139
+ """Reinstall Playwright completely."""
140
+ try:
141
+ # Uninstall
142
+ subprocess.run([sys.executable, "-m", "pip", "uninstall", "-y", "playwright"],
143
+ check=False, capture_output=True)
144
+
145
+ # Clear pip cache
146
+ subprocess.run([sys.executable, "-m", "pip", "cache", "purge"],
147
+ check=False, capture_output=True)
148
+
149
+ # Reinstall
150
+ subprocess.run([sys.executable, "-m", "pip", "install", "playwright"],
151
+ check=True, capture_output=True)
152
+
153
+ return True
154
+ except subprocess.CalledProcessError:
155
+ return False
156
+
157
+ def _install_browsers(self) -> bool:
158
+ """Install Playwright browsers."""
159
+ try:
160
+ # Install chromium (most stable)
161
+ subprocess.run([sys.executable, "-m", "playwright", "install", "chromium"],
162
+ check=True, capture_output=True)
163
+
164
+ # Try to install firefox too (optional)
165
+ subprocess.run([sys.executable, "-m", "playwright", "install", "firefox"],
166
+ check=False, capture_output=True)
167
+
168
+ return True
169
+ except subprocess.CalledProcessError:
170
+ return False
171
+
172
+ def get_browser_info(self) -> Dict[str, str]:
173
+ """Get browser installation information."""
174
+ info = {}
175
+
176
+ # Playwright version
177
+ try:
178
+ result = subprocess.run([sys.executable, "-m", "playwright", "--version"],
179
+ capture_output=True, text=True)
180
+ info['playwright_version'] = result.stdout.strip()
181
+ except:
182
+ info['playwright_version'] = "Not installed"
183
+
184
+ # Cache directory
185
+ info['cache_path'] = str(self.playwright_cache) if self.playwright_cache else "Unknown"
186
+ info['cache_exists'] = str(self._check_cache_directory())
187
+
188
+ # Browser test
189
+ info['browser_test'] = "PASS" if self._test_browser_launch() else "FAIL"
190
+
191
+ return info
192
+
193
+
194
+ def fix_browsers(force_reinstall: bool = False) -> bool:
195
+ """
196
+ Quick browser fix function.
197
+
198
+ Args:
199
+ force_reinstall: Force complete reinstall
200
+
201
+ Returns:
202
+ True if successful
203
+ """
204
+ fixer = BrowserFixer()
205
+ return fixer.fix_browser_issues(force_reinstall)
206
+
207
+
208
+ def diagnose_browsers() -> Dict[str, bool]:
209
+ """
210
+ Quick browser diagnosis.
211
+
212
+ Returns:
213
+ Dictionary with diagnosis results
214
+ """
215
+ fixer = BrowserFixer()
216
+ return fixer.diagnose_browser_issues()
217
+
218
+
219
+ def get_browser_status() -> Dict[str, str]:
220
+ """
221
+ Get browser status information.
222
+
223
+ Returns:
224
+ Dictionary with browser info
225
+ """
226
+ fixer = BrowserFixer()
227
+ return fixer.get_browser_info()
@@ -0,0 +1,166 @@
1
+ """
2
+ Core installer logic. Clean and simple.
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import subprocess
8
+ import platform
9
+ from pathlib import Path
10
+ from typing import Dict, Any
11
+
12
+ from .platform import apply_platform_fixes, check_system_requirements
13
+ from .templates import TemplateEngine
14
+ from .browser_fixes import fix_browsers, diagnose_browsers
15
+
16
+
17
+ def install_parser(parser_name: str, parser_path: str = ".") -> bool:
18
+ """
19
+ Install everything for a UnrealOn parser.
20
+
21
+ Args:
22
+ parser_name: Name like "upbit_concurrent"
23
+ parser_path: Path to parser directory
24
+
25
+ Returns:
26
+ True if success, False if failed
27
+ """
28
+ print(f"🚀 Installing {parser_name}")
29
+ print("=" * 40)
30
+
31
+ parser_dir = Path(parser_path).resolve()
32
+ os.chdir(parser_dir)
33
+
34
+ # 1. Apply platform fixes
35
+ print("🔧 Applying platform fixes...")
36
+ apply_platform_fixes()
37
+ print("✅ Platform fixes applied")
38
+
39
+ # 2. Check system
40
+ print("🔍 Checking system...")
41
+ requirements = check_system_requirements()
42
+ failed = [k for k, v in requirements.items() if not v]
43
+ if failed:
44
+ print(f"❌ Missing: {', '.join(failed)}")
45
+ return False
46
+
47
+ print(f"✅ Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
48
+
49
+ # 3. Install dependencies
50
+ if not _install_dependencies():
51
+ return False
52
+
53
+ # 4. Install browsers
54
+ if not _install_browsers():
55
+ return False
56
+
57
+ # 5. Create batch files (Windows only)
58
+ if platform.system() == "Windows":
59
+ _create_batch_files(parser_name)
60
+
61
+ print(f"\n✅ {parser_name} installed successfully!")
62
+ print("Run: python main.py 5 2")
63
+ if platform.system() == "Windows":
64
+ print("Or: START.bat")
65
+
66
+ return True
67
+
68
+
69
+ def _install_dependencies() -> bool:
70
+ """Install Python dependencies."""
71
+ print("📦 Installing dependencies...")
72
+
73
+ try:
74
+ # Check if requirements.txt exists
75
+ if Path("requirements.txt").exists():
76
+ subprocess.run([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"],
77
+ check=True, capture_output=True)
78
+ else:
79
+ # Fallback to basic packages
80
+ subprocess.run([sys.executable, "-m", "pip", "install", "unrealon", "playwright"],
81
+ check=True, capture_output=True)
82
+
83
+ print("✅ Dependencies installed")
84
+ return True
85
+ except subprocess.CalledProcessError as e:
86
+ print(f"❌ Failed to install dependencies: {e}")
87
+ return False
88
+
89
+
90
+ def _install_browsers() -> bool:
91
+ """Install Playwright browsers with smart fixing."""
92
+ print("🌐 Installing browsers...")
93
+
94
+ # First, diagnose any issues
95
+ issues = diagnose_browsers()
96
+
97
+ # If there are issues, try to fix them
98
+ if not all(issues.values()):
99
+ print("🔧 Detected browser issues, applying fixes...")
100
+ if fix_browsers(force_reinstall=False):
101
+ print("✅ Browser issues fixed")
102
+ return True
103
+ else:
104
+ print("❌ Could not fix browser issues")
105
+ return False
106
+
107
+ # If no issues, just install normally
108
+ try:
109
+ subprocess.run([sys.executable, "-m", "playwright", "install", "chromium"],
110
+ check=True, capture_output=True)
111
+ print("✅ Browsers installed")
112
+ return True
113
+ except subprocess.CalledProcessError as e:
114
+ print(f"⚠️ Normal install failed, trying fix: {e}")
115
+ # Try fixing as fallback
116
+ return fix_browsers(force_reinstall=True)
117
+
118
+
119
+ def _create_batch_files(parser_name: str):
120
+ """Create Windows batch files using Jinja2 templates."""
121
+ print("🪟 Creating Windows batch files...")
122
+
123
+ # Detect parser config
124
+ config = _detect_parser_config()
125
+
126
+ # Create template engine
127
+ engine = TemplateEngine()
128
+
129
+ # Generate batch files
130
+ start_content = engine.render_start_bat(parser_name, config)
131
+ Path("START.bat").write_text(start_content, encoding="utf-8")
132
+
133
+ quick_content = engine.render_quick_run_bat(parser_name, config)
134
+ Path("QUICK_RUN.bat").write_text(quick_content, encoding="utf-8")
135
+
136
+ test_content = engine.render_test_bat(parser_name, config)
137
+ Path("TEST.bat").write_text(test_content, encoding="utf-8")
138
+
139
+ print("✅ Created START.bat, QUICK_RUN.bat, TEST.bat")
140
+
141
+
142
+ def _detect_parser_config() -> Dict[str, Any]:
143
+ """Detect parser configuration from files."""
144
+ config = {
145
+ 'browsers_needed': ['chromium'],
146
+ 'proxy_support': False,
147
+ 'supports_persistent': False
148
+ }
149
+
150
+ # Check main.py for persistent mode support
151
+ if Path("main.py").exists():
152
+ main_content = Path("main.py").read_text()
153
+ if "--persistent" in main_content:
154
+ config['supports_persistent'] = True
155
+
156
+ # Check for proxy config
157
+ if Path("src/proxy_config.py").exists() or Path("proxy_config.py").exists():
158
+ config['proxy_support'] = True
159
+
160
+ # Check pyproject.toml for browser requirements
161
+ if Path("pyproject.toml").exists():
162
+ toml_content = Path("pyproject.toml").read_text()
163
+ if "firefox" in toml_content.lower():
164
+ config['browsers_needed'].append('firefox')
165
+
166
+ return config
@@ -0,0 +1,122 @@
1
+ """
2
+ Platform compatibility fixes. Clean and simple.
3
+ """
4
+
5
+ import asyncio
6
+ import sys
7
+ import platform
8
+ import warnings
9
+ import logging
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def apply_platform_fixes():
15
+ """Apply all necessary platform fixes automatically."""
16
+ system = platform.system()
17
+ fixes = []
18
+
19
+ if system == "Windows":
20
+ fixes.extend(_apply_windows_fixes())
21
+ elif system == "Darwin": # macOS
22
+ fixes.extend(_apply_macos_fixes())
23
+ elif system == "Linux":
24
+ fixes.extend(_apply_linux_fixes())
25
+
26
+ if fixes:
27
+ logger.info(f"✅ Applied platform fixes: {', '.join(fixes)}")
28
+
29
+ return fixes
30
+
31
+
32
+ def _apply_windows_fixes():
33
+ """Windows-specific fixes."""
34
+ fixes = []
35
+
36
+ # Asyncio event loop policy
37
+ if sys.version_info >= (3, 8):
38
+ try:
39
+ asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
40
+ fixes.append("ProactorEventLoop")
41
+ except Exception:
42
+ pass
43
+
44
+ # Console encoding
45
+ try:
46
+ if hasattr(sys.stdout, 'reconfigure'):
47
+ sys.stdout.reconfigure(encoding='utf-8')
48
+ sys.stderr.reconfigure(encoding='utf-8')
49
+ fixes.append("UTF-8 encoding")
50
+ except Exception:
51
+ pass
52
+
53
+ # Suppress warnings
54
+ warnings.filterwarnings("ignore", category=ResourceWarning)
55
+ fixes.append("ResourceWarning suppression")
56
+
57
+ return fixes
58
+
59
+
60
+ def _apply_macos_fixes():
61
+ """macOS-specific fixes."""
62
+ fixes = []
63
+
64
+ # SSL context fix
65
+ try:
66
+ import ssl
67
+ ssl._create_default_https_context = ssl._create_unverified_context
68
+ fixes.append("SSL context")
69
+ except Exception:
70
+ pass
71
+
72
+ # File descriptor limits
73
+ try:
74
+ import resource
75
+ soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
76
+ if soft < 1024:
77
+ resource.setrlimit(resource.RLIMIT_NOFILE, (min(1024, hard), hard))
78
+ fixes.append("File descriptor limit")
79
+ except Exception:
80
+ pass
81
+
82
+ return fixes
83
+
84
+
85
+ def _apply_linux_fixes():
86
+ """Linux-specific fixes."""
87
+ fixes = []
88
+
89
+ # File descriptor limits
90
+ try:
91
+ import resource
92
+ soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
93
+ if soft < 2048:
94
+ resource.setrlimit(resource.RLIMIT_NOFILE, (min(2048, hard), hard))
95
+ fixes.append("File descriptor limit")
96
+ except Exception:
97
+ pass
98
+
99
+ # Headless display
100
+ import os
101
+ if not os.environ.get('DISPLAY'):
102
+ os.environ['DISPLAY'] = ':99'
103
+ fixes.append("Headless display")
104
+
105
+ return fixes
106
+
107
+
108
+ def get_platform_info():
109
+ """Get platform information."""
110
+ return {
111
+ 'platform': platform.system(),
112
+ 'architecture': platform.architecture()[0],
113
+ 'python_version': f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
114
+ }
115
+
116
+
117
+ def check_system_requirements():
118
+ """Check if system meets requirements."""
119
+ return {
120
+ 'python_version': sys.version_info >= (3, 9),
121
+ 'platform_supported': platform.system() in ['Windows', 'Darwin', 'Linux']
122
+ }
@@ -0,0 +1,60 @@
1
+ """
2
+ Jinja2 template engine for batch files.
3
+ """
4
+
5
+ from pathlib import Path
6
+ from typing import Dict, Any
7
+ import json
8
+ from jinja2 import Environment, FileSystemLoader
9
+
10
+
11
+ class TemplateEngine:
12
+ """Jinja2-based template engine for Windows batch files."""
13
+
14
+ def __init__(self):
15
+ # Get batch templates directory
16
+ templates_dir = Path(__file__).parent / "batch_templates"
17
+
18
+ # Create Jinja2 environment
19
+ self.env = Environment(
20
+ loader=FileSystemLoader(str(templates_dir)),
21
+ trim_blocks=True,
22
+ lstrip_blocks=True
23
+ )
24
+
25
+ def render_start_bat(self, parser_name: str, config: Dict[str, Any]) -> str:
26
+ """Render START.bat file."""
27
+ template = self.env.get_template('start.bat.j2')
28
+
29
+ context = {
30
+ 'parser_name': parser_name,
31
+ 'config': config,
32
+ 'config_json': json.dumps(config, indent=None),
33
+ 'browsers_list': ', '.join(config.get('browsers_needed', ['chromium'])),
34
+ 'has_proxy': config.get('proxy_support', False),
35
+ 'has_persistent': config.get('supports_persistent', False)
36
+ }
37
+
38
+ return template.render(**context)
39
+
40
+ def render_quick_run_bat(self, parser_name: str, config: Dict[str, Any]) -> str:
41
+ """Render QUICK_RUN.bat file."""
42
+ template = self.env.get_template('quick_run.bat.j2')
43
+
44
+ context = {
45
+ 'parser_name': parser_name,
46
+ 'config': config
47
+ }
48
+
49
+ return template.render(**context)
50
+
51
+ def render_test_bat(self, parser_name: str, config: Dict[str, Any]) -> str:
52
+ """Render TEST.bat file."""
53
+ template = self.env.get_template('test.bat.j2')
54
+
55
+ context = {
56
+ 'parser_name': parser_name,
57
+ 'config': config
58
+ }
59
+
60
+ return template.render(**context)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unrealon
3
- Version: 2.0.13
3
+ Version: 2.0.14
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,8 +128,12 @@ 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
132
131
  unrealon-driver/src/unrealon_driver/utils/time.py
132
+ unrealon-driver/src/unrealon_installer/__init__.py
133
+ unrealon-driver/src/unrealon_installer/browser_fixes.py
134
+ unrealon-driver/src/unrealon_installer/core.py
135
+ unrealon-driver/src/unrealon_installer/platform.py
136
+ unrealon-driver/src/unrealon_installer/templates.py
133
137
  unrealon.egg-info/PKG-INFO
134
138
  unrealon.egg-info/SOURCES.txt
135
139
  unrealon.egg-info/dependency_links.txt
@@ -1,3 +1,4 @@
1
1
  unrealon_browser
2
2
  unrealon_core
3
3
  unrealon_driver
4
+ unrealon_installer
@@ -1,18 +0,0 @@
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
- ]