unrealon 2.0.13__tar.gz → 2.0.15__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.15}/PKG-INFO +2 -1
  2. {unrealon-2.0.13 → unrealon-2.0.15}/pyproject.toml +3 -1
  3. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/__init__.py +2 -10
  4. unrealon-2.0.15/unrealon-driver/src/unrealon_driver/utils/__init__.py +10 -0
  5. unrealon-2.0.15/unrealon-driver/src/unrealon_installer/__init__.py +11 -0
  6. unrealon-2.0.15/unrealon-driver/src/unrealon_installer/browser_fixes.py +227 -0
  7. unrealon-2.0.15/unrealon-driver/src/unrealon_installer/core.py +143 -0
  8. unrealon-2.0.15/unrealon-driver/src/unrealon_installer/platform.py +122 -0
  9. unrealon-2.0.15/unrealon-driver/src/unrealon_installer/templates.py +60 -0
  10. {unrealon-2.0.13 → unrealon-2.0.15/unrealon.egg-info}/PKG-INFO +2 -1
  11. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon.egg-info/SOURCES.txt +5 -1
  12. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon.egg-info/entry_points.txt +1 -0
  13. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon.egg-info/requires.txt +1 -0
  14. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon.egg-info/top_level.txt +1 -0
  15. unrealon-2.0.13/unrealon-driver/src/unrealon_driver/utils/__init__.py +0 -18
  16. unrealon-2.0.13/unrealon-driver/src/unrealon_driver/utils/platform_compatibility.py +0 -205
  17. {unrealon-2.0.13 → unrealon-2.0.15}/LICENSE +0 -0
  18. {unrealon-2.0.13 → unrealon-2.0.15}/MANIFEST.in +0 -0
  19. {unrealon-2.0.13 → unrealon-2.0.15}/README.md +0 -0
  20. {unrealon-2.0.13 → unrealon-2.0.15}/setup.cfg +0 -0
  21. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/README.md +0 -0
  22. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/__init__.py +0 -0
  23. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/cli/__init__.py +0 -0
  24. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/cli/browser_cli.py +0 -0
  25. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/cli/cookies_cli.py +0 -0
  26. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/cli/interactive_mode.py +0 -0
  27. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/cli/main.py +0 -0
  28. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/core/__init__.py +0 -0
  29. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/core/browser_manager.py +0 -0
  30. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/__init__.py +0 -0
  31. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/bot_detection.py +0 -0
  32. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/config.py +0 -0
  33. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/core.py +0 -0
  34. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/dataclasses.py +0 -0
  35. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/detection.py +0 -0
  36. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/enums.py +0 -0
  37. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/dto/models/statistics.py +0 -0
  38. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/__init__.py +0 -0
  39. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/captcha.py +0 -0
  40. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/cookies.py +0 -0
  41. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/logger_bridge.py +0 -0
  42. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/page_wait_manager.py +0 -0
  43. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/profile.py +0 -0
  44. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/managers/script_manager.py +0 -0
  45. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/__init__.py +0 -0
  46. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/bypass_techniques.py +0 -0
  47. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/manager.py +0 -0
  48. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/nodriver_stealth.py +0 -0
  49. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/playwright_stealth.py +0 -0
  50. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/scanner_tester.py +0 -0
  51. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-browser/src/unrealon_browser/stealth/undetected_chrome.py +0 -0
  52. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/__init__.py +0 -0
  53. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/config/__init__.py +0 -0
  54. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/config/environment.py +0 -0
  55. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/config/urls.py +0 -0
  56. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/enums/__init__.py +0 -0
  57. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/enums/events.py +0 -0
  58. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/enums/jobs.py +0 -0
  59. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/enums/status.py +0 -0
  60. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/enums/types.py +0 -0
  61. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/error_handling/__init__.py +0 -0
  62. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/error_handling/circuit_breaker.py +0 -0
  63. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/error_handling/error_context.py +0 -0
  64. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/error_handling/recovery.py +0 -0
  65. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/error_handling/retry.py +0 -0
  66. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/__init__.py +0 -0
  67. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/base.py +0 -0
  68. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/communication.py +0 -0
  69. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/driver.py +0 -0
  70. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/proxy.py +0 -0
  71. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/task.py +0 -0
  72. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/exceptions/validation.py +0 -0
  73. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/__init__.py +0 -0
  74. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/arq_context.py +0 -0
  75. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/arq_responses.py +0 -0
  76. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/authentication.py +0 -0
  77. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/base.py +0 -0
  78. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/bridge_stats.py +0 -0
  79. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/communication.py +0 -0
  80. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/connection_stats.py +0 -0
  81. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/driver.py +0 -0
  82. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/driver_details.py +0 -0
  83. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/logging.py +0 -0
  84. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/task.py +0 -0
  85. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/typed_responses.py +0 -0
  86. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/__init__.py +0 -0
  87. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/base.py +0 -0
  88. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/broadcast.py +0 -0
  89. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/config.py +0 -0
  90. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/driver.py +0 -0
  91. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/errors.py +0 -0
  92. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/heartbeat.py +0 -0
  93. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/logging.py +0 -0
  94. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/proxy.py +0 -0
  95. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/tasks.py +0 -0
  96. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket/utils.py +0 -0
  97. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/models/websocket_session.py +0 -0
  98. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/monitoring/__init__.py +0 -0
  99. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/monitoring/alerts.py +0 -0
  100. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/monitoring/dashboard.py +0 -0
  101. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/monitoring/health_check.py +0 -0
  102. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/monitoring/metrics.py +0 -0
  103. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/utils/__init__.py +0 -0
  104. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/utils/time.py +0 -0
  105. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-core/src/unrealon_core/version.py +0 -0
  106. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/__init__.py +0 -0
  107. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/base.py +0 -0
  108. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/config.py +0 -0
  109. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/event_manager.py +0 -0
  110. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/protocols.py +0 -0
  111. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/core_module/registry.py +0 -0
  112. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/decorators/__init__.py +0 -0
  113. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/decorators/retry.py +0 -0
  114. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/decorators/schedule.py +0 -0
  115. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/decorators/task.py +0 -0
  116. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/decorators/timing.py +0 -0
  117. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/__init__.py +0 -0
  118. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/communication/__init__.py +0 -0
  119. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/communication/session.py +0 -0
  120. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/communication/websocket_client.py +0 -0
  121. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/core/__init__.py +0 -0
  122. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/core/config.py +0 -0
  123. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/core/driver.py +0 -0
  124. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/factory/__init__.py +0 -0
  125. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/factory/manager_factory.py +0 -0
  126. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/lifecycle/__init__.py +0 -0
  127. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/lifecycle/daemon.py +0 -0
  128. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/lifecycle/initialization.py +0 -0
  129. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/lifecycle/shutdown.py +0 -0
  130. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/monitoring/__init__.py +0 -0
  131. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/monitoring/health.py +0 -0
  132. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/utilities/__init__.py +0 -0
  133. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/utilities/logging.py +0 -0
  134. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/driver/utilities/serialization.py +0 -0
  135. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/__init__.py +0 -0
  136. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/base.py +0 -0
  137. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/browser.py +0 -0
  138. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/cache.py +0 -0
  139. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/http.py +0 -0
  140. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/logger.py +0 -0
  141. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/proxy.py +0 -0
  142. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/registry.py +0 -0
  143. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/threading.py +0 -0
  144. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/managers/update.py +0 -0
  145. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon-driver/src/unrealon_driver/utils/time.py +0 -0
  146. {unrealon-2.0.13 → unrealon-2.0.15}/unrealon.egg-info/dependency_links.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.15
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
@@ -33,6 +33,7 @@ Requires-Dist: aiohttp>=3.8.0
33
33
  Requires-Dist: httpx>=0.23.0
34
34
  Requires-Dist: beautifulsoup4>=4.13.5
35
35
  Requires-Dist: pydantic-yaml>=1.6.0
36
+ Requires-Dist: jinja2>=3.1.0
36
37
  Requires-Dist: rich>=13.0.0
37
38
  Requires-Dist: pyyaml>=6.0
38
39
  Requires-Dist: python-socketio>=5.0
@@ -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.15"
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"}
@@ -45,6 +45,7 @@ dependencies = [
45
45
  "httpx>=0.23.0",
46
46
  "beautifulsoup4>=4.13.5",
47
47
  "pydantic-yaml>=1.6.0",
48
+ "jinja2>=3.1.0",
48
49
 
49
50
  # Additional dependencies for full functionality
50
51
  "rich>=13.0.0",
@@ -104,6 +105,7 @@ full = ["selenium>=4.15.0", "playwright>=1.40.0", "undetected-chromedriver>=3.5.
104
105
  [project.scripts]
105
106
  unrealon = "unrealon_driver.cli:main"
106
107
  unrealon-browser = "unrealon_browser.cli.main:main"
108
+ unrealon-installer = "unrealon_installer.cli:main"
107
109
 
108
110
  [project.urls]
109
111
  Homepage = "https://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,143 @@
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. Check if basic tools are available (optional)
50
+ _check_tools_availability()
51
+
52
+ # 4. Create batch files (Windows only)
53
+ if platform.system() == "Windows":
54
+ _create_batch_files(parser_name)
55
+
56
+ print(f"\n✅ {parser_name} setup completed!")
57
+ print("\n📋 Next steps:")
58
+ print("1. Install dependencies: pip install -r requirements.txt")
59
+ print("2. Install browsers: playwright install chromium")
60
+ print("3. Run parser: python main.py 5 2")
61
+ if platform.system() == "Windows":
62
+ print(" Or use: START.bat (includes setup menu)")
63
+
64
+ return True
65
+
66
+
67
+ def _check_tools_availability():
68
+ """Check if basic tools are available (non-blocking)."""
69
+ print("🔍 Checking available tools...")
70
+
71
+ # Check pip
72
+ try:
73
+ subprocess.run([sys.executable, "-m", "pip", "--version"],
74
+ check=True, capture_output=True)
75
+ print("✅ pip available")
76
+ except:
77
+ print("⚠️ pip not available")
78
+
79
+ # Check if requirements.txt exists
80
+ if Path("requirements.txt").exists():
81
+ print("✅ requirements.txt found")
82
+ print("💡 To install dependencies: pip install -r requirements.txt")
83
+ else:
84
+ print("⚠️ requirements.txt not found")
85
+
86
+ # Check playwright
87
+ try:
88
+ subprocess.run([sys.executable, "-c", "import playwright"],
89
+ check=True, capture_output=True)
90
+ print("✅ playwright available")
91
+ except:
92
+ print("⚠️ playwright not available")
93
+ print("💡 To install: pip install playwright && playwright install chromium")
94
+
95
+
96
+ def _create_batch_files(parser_name: str):
97
+ """Create Windows batch files using Jinja2 templates."""
98
+ print("🪟 Creating Windows batch files...")
99
+
100
+ # Detect parser config
101
+ config = _detect_parser_config()
102
+
103
+ # Create template engine
104
+ engine = TemplateEngine()
105
+
106
+ # Generate batch files
107
+ start_content = engine.render_start_bat(parser_name, config)
108
+ Path("START.bat").write_text(start_content, encoding="utf-8")
109
+
110
+ quick_content = engine.render_quick_run_bat(parser_name, config)
111
+ Path("QUICK_RUN.bat").write_text(quick_content, encoding="utf-8")
112
+
113
+ test_content = engine.render_test_bat(parser_name, config)
114
+ Path("TEST.bat").write_text(test_content, encoding="utf-8")
115
+
116
+ print("✅ Created START.bat, QUICK_RUN.bat, TEST.bat")
117
+
118
+
119
+ def _detect_parser_config() -> Dict[str, Any]:
120
+ """Detect parser configuration from files."""
121
+ config = {
122
+ 'browsers_needed': ['chromium'],
123
+ 'proxy_support': False,
124
+ 'supports_persistent': False
125
+ }
126
+
127
+ # Check main.py for persistent mode support
128
+ if Path("main.py").exists():
129
+ main_content = Path("main.py").read_text()
130
+ if "--persistent" in main_content:
131
+ config['supports_persistent'] = True
132
+
133
+ # Check for proxy config
134
+ if Path("src/proxy_config.py").exists() or Path("proxy_config.py").exists():
135
+ config['proxy_support'] = True
136
+
137
+ # Check pyproject.toml for browser requirements
138
+ if Path("pyproject.toml").exists():
139
+ toml_content = Path("pyproject.toml").read_text()
140
+ if "firefox" in toml_content.lower():
141
+ config['browsers_needed'].append('firefox')
142
+
143
+ 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.15
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
@@ -33,6 +33,7 @@ Requires-Dist: aiohttp>=3.8.0
33
33
  Requires-Dist: httpx>=0.23.0
34
34
  Requires-Dist: beautifulsoup4>=4.13.5
35
35
  Requires-Dist: pydantic-yaml>=1.6.0
36
+ Requires-Dist: jinja2>=3.1.0
36
37
  Requires-Dist: rich>=13.0.0
37
38
  Requires-Dist: pyyaml>=6.0
38
39
  Requires-Dist: python-socketio>=5.0
@@ -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
  [console_scripts]
2
2
  unrealon = unrealon_driver.cli:main
3
3
  unrealon-browser = unrealon_browser.cli.main:main
4
+ unrealon-installer = unrealon_installer.cli:main
@@ -10,6 +10,7 @@ aiohttp>=3.8.0
10
10
  httpx>=0.23.0
11
11
  beautifulsoup4>=4.13.5
12
12
  pydantic-yaml>=1.6.0
13
+ jinja2>=3.1.0
13
14
  rich>=13.0.0
14
15
  pyyaml>=6.0
15
16
  python-socketio>=5.0