dragg2 commited on
Commit
c00180e
·
verified ·
1 Parent(s): 5124452

Upload 33 files

Browse files
src/__pycache__/main.cpython-311.pyc CHANGED
Binary files a/src/__pycache__/main.cpython-311.pyc and b/src/__pycache__/main.cpython-311.pyc differ
 
src/api/__pycache__/routes.cpython-311.pyc CHANGED
Binary files a/src/api/__pycache__/routes.cpython-311.pyc and b/src/api/__pycache__/routes.cpython-311.pyc differ
 
src/core/__pycache__/config.cpython-311.pyc CHANGED
Binary files a/src/core/__pycache__/config.cpython-311.pyc and b/src/core/__pycache__/config.cpython-311.pyc differ
 
src/main.py CHANGED
@@ -62,34 +62,42 @@ _IMAGE_TEXT_TYPES = [
62
  ]
63
 
64
 
65
- @asynccontextmanager
66
- async def lifespan(app: FastAPI) -> AsyncIterator[None]:
67
- # ── startup ──
68
- v3_solver = RecaptchaV3Solver(config)
69
- await v3_solver.start()
70
- for task_type in _RECAPTCHA_V3_TYPES:
71
- task_manager.register_solver(task_type, v3_solver)
72
- log.info("Registered reCAPTCHA v3 solver for types: %s", _RECAPTCHA_V3_TYPES)
73
-
74
- v2_solver = RecaptchaV2Solver(config)
75
- await v2_solver.start()
76
- for task_type in _RECAPTCHA_V2_TYPES:
77
- task_manager.register_solver(task_type, v2_solver)
78
- log.info("Registered reCAPTCHA v2 solver for types: %s", _RECAPTCHA_V2_TYPES)
79
-
 
 
 
 
80
  classifier = ClassificationSolver(config)
81
 
82
  hcaptcha_solver = HCaptchaSolver(config, classifier=classifier)
83
- await hcaptcha_solver.start()
84
  for task_type in _HCAPTCHA_TYPES:
85
  task_manager.register_solver(task_type, hcaptcha_solver)
86
- log.info("Registered hCaptcha solver for types: %s", _HCAPTCHA_TYPES)
87
-
88
- turnstile_solver = TurnstileSolver(config)
89
- await turnstile_solver.start()
90
- for task_type in _TURNSTILE_TYPES:
91
- task_manager.register_solver(task_type, turnstile_solver)
92
- log.info("Registered Turnstile solver for types: %s", _TURNSTILE_TYPES)
 
 
 
 
 
93
 
94
  recognizer = CaptchaRecognizer(config)
95
  for task_type in _IMAGE_TEXT_TYPES:
 
62
  ]
63
 
64
 
65
+ @asynccontextmanager
66
+ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
67
+ # ── startup ──
68
+ v3_solver = RecaptchaV3Solver(config)
69
+ for task_type in _RECAPTCHA_V3_TYPES:
70
+ task_manager.register_solver(task_type, v3_solver)
71
+ log.info(
72
+ "Registered reCAPTCHA v3 solver for types: %s (browser startup deferred)",
73
+ _RECAPTCHA_V3_TYPES,
74
+ )
75
+
76
+ v2_solver = RecaptchaV2Solver(config)
77
+ for task_type in _RECAPTCHA_V2_TYPES:
78
+ task_manager.register_solver(task_type, v2_solver)
79
+ log.info(
80
+ "Registered reCAPTCHA v2 solver for types: %s (browser startup deferred)",
81
+ _RECAPTCHA_V2_TYPES,
82
+ )
83
+
84
  classifier = ClassificationSolver(config)
85
 
86
  hcaptcha_solver = HCaptchaSolver(config, classifier=classifier)
 
87
  for task_type in _HCAPTCHA_TYPES:
88
  task_manager.register_solver(task_type, hcaptcha_solver)
89
+ log.info(
90
+ "Registered hCaptcha solver for types: %s (browser startup deferred)",
91
+ _HCAPTCHA_TYPES,
92
+ )
93
+
94
+ turnstile_solver = TurnstileSolver(config)
95
+ for task_type in _TURNSTILE_TYPES:
96
+ task_manager.register_solver(task_type, turnstile_solver)
97
+ log.info(
98
+ "Registered Turnstile solver for types: %s (browser startup deferred)",
99
+ _TURNSTILE_TYPES,
100
+ )
101
 
102
  recognizer = CaptchaRecognizer(config)
103
  for task_type in _IMAGE_TEXT_TYPES:
src/models/__pycache__/task.cpython-311.pyc CHANGED
Binary files a/src/models/__pycache__/task.cpython-311.pyc and b/src/models/__pycache__/task.cpython-311.pyc differ
 
src/services/__pycache__/hcaptcha.cpython-311.pyc CHANGED
Binary files a/src/services/__pycache__/hcaptcha.cpython-311.pyc and b/src/services/__pycache__/hcaptcha.cpython-311.pyc differ
 
src/services/__pycache__/recaptcha_v2.cpython-311.pyc CHANGED
Binary files a/src/services/__pycache__/recaptcha_v2.cpython-311.pyc and b/src/services/__pycache__/recaptcha_v2.cpython-311.pyc differ
 
src/services/__pycache__/recaptcha_v3.cpython-311.pyc CHANGED
Binary files a/src/services/__pycache__/recaptcha_v3.cpython-311.pyc and b/src/services/__pycache__/recaptcha_v3.cpython-311.pyc differ
 
src/services/__pycache__/turnstile.cpython-311.pyc CHANGED
Binary files a/src/services/__pycache__/turnstile.cpython-311.pyc and b/src/services/__pycache__/turnstile.cpython-311.pyc differ
 
src/services/hcaptcha.py CHANGED
@@ -148,31 +148,46 @@ class HCaptchaSolver:
148
  self._browser: Browser | None = browser
149
  self._owns_browser = browser is None
150
  self._classifier = classifier
 
151
 
152
  async def start(self) -> None:
153
  if self._browser is not None:
154
  return
155
- self._playwright = await async_playwright().start()
156
- self._browser = await self._playwright.chromium.launch(
157
- headless=self._config.browser_headless,
158
- args=[
159
- "--disable-blink-features=AutomationControlled",
160
- "--no-sandbox",
161
- "--disable-dev-shm-usage",
162
- "--disable-gpu",
163
- ],
164
- )
165
- log.info("HCaptchaSolver browser started")
 
 
 
 
 
 
 
 
 
 
166
 
167
  async def stop(self) -> None:
168
- if self._owns_browser:
169
- if self._browser:
170
- await self._browser.close()
171
- if self._playwright:
172
- await self._playwright.stop()
 
 
 
173
  log.info("HCaptchaSolver stopped")
174
 
175
  async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
 
176
  website_url = params["websiteURL"]
177
  website_key = params["websiteKey"]
178
  enterprise_payload = params.get("enterprisePayload") or {}
 
148
  self._browser: Browser | None = browser
149
  self._owns_browser = browser is None
150
  self._classifier = classifier
151
+ self._start_lock = asyncio.Lock()
152
 
153
  async def start(self) -> None:
154
  if self._browser is not None:
155
  return
156
+
157
+ async with self._start_lock:
158
+ if self._browser is not None:
159
+ return
160
+ playwright = await async_playwright().start()
161
+ try:
162
+ browser = await playwright.chromium.launch(
163
+ headless=self._config.browser_headless,
164
+ args=[
165
+ "--disable-blink-features=AutomationControlled",
166
+ "--no-sandbox",
167
+ "--disable-dev-shm-usage",
168
+ "--disable-gpu",
169
+ ],
170
+ )
171
+ except Exception:
172
+ await playwright.stop()
173
+ raise
174
+ self._playwright = playwright
175
+ self._browser = browser
176
+ log.info("HCaptchaSolver browser started lazily")
177
 
178
  async def stop(self) -> None:
179
+ async with self._start_lock:
180
+ if self._owns_browser:
181
+ if self._browser:
182
+ await self._browser.close()
183
+ self._browser = None
184
+ if self._playwright:
185
+ await self._playwright.stop()
186
+ self._playwright = None
187
  log.info("HCaptchaSolver stopped")
188
 
189
  async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
190
+ await self.start()
191
  website_url = params["websiteURL"]
192
  website_key = params["websiteKey"]
193
  enterprise_payload = params.get("enterprisePayload") or {}
src/services/recaptcha_v2.py CHANGED
@@ -56,39 +56,54 @@ class RecaptchaV2Solver:
56
  challenge to the headless browser.
57
  """
58
 
59
- def __init__(self, config: Config, browser: Browser | None = None) -> None:
60
- self._config = config
61
- self._playwright: Playwright | None = None
62
- self._browser: Browser | None = browser
63
- self._owns_browser = browser is None
64
-
65
- async def start(self) -> None:
66
- if self._browser is not None:
67
- return
68
- self._playwright = await async_playwright().start()
69
- self._browser = await self._playwright.chromium.launch(
70
- headless=self._config.browser_headless,
71
- args=[
72
- "--disable-blink-features=AutomationControlled",
73
- "--no-sandbox",
74
- "--disable-dev-shm-usage",
75
- "--disable-gpu",
76
- ],
77
- )
78
- log.info("RecaptchaV2Solver browser started")
79
-
80
- async def stop(self) -> None:
81
- if self._owns_browser:
82
- if self._browser:
83
- await self._browser.close()
84
- if self._playwright:
85
- await self._playwright.stop()
86
- log.info("RecaptchaV2Solver stopped")
87
-
88
- async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
89
- website_url = params["websiteURL"]
90
- website_key = params["websiteKey"]
91
- is_invisible = params.get("isInvisible", False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  last_error: Exception | None = None
94
  for attempt in range(self._config.captcha_retries):
 
56
  challenge to the headless browser.
57
  """
58
 
59
+ def __init__(self, config: Config, browser: Browser | None = None) -> None:
60
+ self._config = config
61
+ self._playwright: Playwright | None = None
62
+ self._browser: Browser | None = browser
63
+ self._owns_browser = browser is None
64
+ self._start_lock = asyncio.Lock()
65
+
66
+ async def start(self) -> None:
67
+ if self._browser is not None:
68
+ return
69
+
70
+ async with self._start_lock:
71
+ if self._browser is not None:
72
+ return
73
+ playwright = await async_playwright().start()
74
+ try:
75
+ browser = await playwright.chromium.launch(
76
+ headless=self._config.browser_headless,
77
+ args=[
78
+ "--disable-blink-features=AutomationControlled",
79
+ "--no-sandbox",
80
+ "--disable-dev-shm-usage",
81
+ "--disable-gpu",
82
+ ],
83
+ )
84
+ except Exception:
85
+ await playwright.stop()
86
+ raise
87
+ self._playwright = playwright
88
+ self._browser = browser
89
+ log.info("RecaptchaV2Solver browser started lazily")
90
+
91
+ async def stop(self) -> None:
92
+ async with self._start_lock:
93
+ if self._owns_browser:
94
+ if self._browser:
95
+ await self._browser.close()
96
+ self._browser = None
97
+ if self._playwright:
98
+ await self._playwright.stop()
99
+ self._playwright = None
100
+ log.info("RecaptchaV2Solver stopped")
101
+
102
+ async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
103
+ await self.start()
104
+ website_url = params["websiteURL"]
105
+ website_key = params["websiteKey"]
106
+ is_invisible = params.get("isInvisible", False)
107
 
108
  last_error: Exception | None = None
109
  for attempt in range(self._config.captcha_retries):
src/services/recaptcha_v3.py CHANGED
@@ -359,6 +359,7 @@ class RecaptchaV3Solver:
359
  self._config = config
360
  self._playwright: Playwright | None = None
361
  self._browser: Browser | None = None
 
362
 
363
  @staticmethod
364
  def _build_proxy_settings(raw_proxy_url: str) -> dict[str, str]:
@@ -414,36 +415,54 @@ class RecaptchaV3Solver:
414
  }
415
 
416
  async def start(self) -> None:
417
- self._playwright = await async_playwright().start()
418
- launch_options: dict[str, Any] = {
419
- "headless": self._config.browser_headless,
420
- "args": [
421
- "--disable-blink-features=AutomationControlled",
422
- "--no-sandbox",
423
- "--disable-dev-shm-usage",
424
- "--disable-gpu",
425
- ],
426
- }
427
- if self._config.browser_proxy_url:
428
- launch_options["proxy"] = self._build_proxy_settings(
429
- self._config.browser_proxy_url
430
- )
431
 
432
- self._browser = await self._playwright.chromium.launch(**launch_options)
433
- log.info(
434
- "Playwright browser started (headless=%s proxy=%s)",
435
- self._config.browser_headless,
436
- "configured" if self._config.browser_proxy_url else "none",
437
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
 
439
  async def stop(self) -> None:
440
- if self._browser:
441
- await self._browser.close()
442
- if self._playwright:
443
- await self._playwright.stop()
 
 
 
444
  log.info("Playwright browser stopped")
445
 
446
  async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
 
447
  profile = self._build_task_profile(params)
448
  last_error: Exception | None = None
449
  for attempt in range(self._config.captcha_retries):
 
359
  self._config = config
360
  self._playwright: Playwright | None = None
361
  self._browser: Browser | None = None
362
+ self._start_lock = asyncio.Lock()
363
 
364
  @staticmethod
365
  def _build_proxy_settings(raw_proxy_url: str) -> dict[str, str]:
 
415
  }
416
 
417
  async def start(self) -> None:
418
+ if self._browser is not None:
419
+ return
 
 
 
 
 
 
 
 
 
 
 
 
420
 
421
+ async with self._start_lock:
422
+ if self._browser is not None:
423
+ return
424
+
425
+ playwright = await async_playwright().start()
426
+ launch_options: dict[str, Any] = {
427
+ "headless": self._config.browser_headless,
428
+ "args": [
429
+ "--disable-blink-features=AutomationControlled",
430
+ "--no-sandbox",
431
+ "--disable-dev-shm-usage",
432
+ "--disable-gpu",
433
+ ],
434
+ }
435
+ if self._config.browser_proxy_url:
436
+ launch_options["proxy"] = self._build_proxy_settings(
437
+ self._config.browser_proxy_url
438
+ )
439
+
440
+ try:
441
+ browser = await playwright.chromium.launch(**launch_options)
442
+ except Exception:
443
+ await playwright.stop()
444
+ raise
445
+
446
+ self._playwright = playwright
447
+ self._browser = browser
448
+ log.info(
449
+ "Playwright browser started lazily (headless=%s proxy=%s)",
450
+ self._config.browser_headless,
451
+ "configured" if self._config.browser_proxy_url else "none",
452
+ )
453
 
454
  async def stop(self) -> None:
455
+ async with self._start_lock:
456
+ if self._browser:
457
+ await self._browser.close()
458
+ self._browser = None
459
+ if self._playwright:
460
+ await self._playwright.stop()
461
+ self._playwright = None
462
  log.info("Playwright browser stopped")
463
 
464
  async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
465
+ await self.start()
466
  profile = self._build_task_profile(params)
467
  last_error: Exception | None = None
468
  for attempt in range(self._config.captcha_retries):
src/services/turnstile.py CHANGED
@@ -44,38 +44,53 @@ _EXTRACT_TURNSTILE_TOKEN_JS = """
44
  class TurnstileSolver:
45
  """Solves Cloudflare Turnstile tasks via headless Chromium."""
46
 
47
- def __init__(self, config: Config, browser: Browser | None = None) -> None:
48
- self._config = config
49
- self._playwright: Playwright | None = None
50
- self._browser: Browser | None = browser
51
- self._owns_browser = browser is None
52
-
53
- async def start(self) -> None:
54
- if self._browser is not None:
55
- return
56
- self._playwright = await async_playwright().start()
57
- self._browser = await self._playwright.chromium.launch(
58
- headless=self._config.browser_headless,
59
- args=[
60
- "--disable-blink-features=AutomationControlled",
61
- "--no-sandbox",
62
- "--disable-dev-shm-usage",
63
- "--disable-gpu",
64
- ],
65
- )
66
- log.info("TurnstileSolver browser started")
67
-
68
- async def stop(self) -> None:
69
- if self._owns_browser:
70
- if self._browser:
71
- await self._browser.close()
72
- if self._playwright:
73
- await self._playwright.stop()
74
- log.info("TurnstileSolver stopped")
75
-
76
- async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
77
- website_url = params["websiteURL"]
78
- website_key = params["websiteKey"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  last_error: Exception | None = None
81
  for attempt in range(self._config.captcha_retries):
 
44
  class TurnstileSolver:
45
  """Solves Cloudflare Turnstile tasks via headless Chromium."""
46
 
47
+ def __init__(self, config: Config, browser: Browser | None = None) -> None:
48
+ self._config = config
49
+ self._playwright: Playwright | None = None
50
+ self._browser: Browser | None = browser
51
+ self._owns_browser = browser is None
52
+ self._start_lock = asyncio.Lock()
53
+
54
+ async def start(self) -> None:
55
+ if self._browser is not None:
56
+ return
57
+
58
+ async with self._start_lock:
59
+ if self._browser is not None:
60
+ return
61
+ playwright = await async_playwright().start()
62
+ try:
63
+ browser = await playwright.chromium.launch(
64
+ headless=self._config.browser_headless,
65
+ args=[
66
+ "--disable-blink-features=AutomationControlled",
67
+ "--no-sandbox",
68
+ "--disable-dev-shm-usage",
69
+ "--disable-gpu",
70
+ ],
71
+ )
72
+ except Exception:
73
+ await playwright.stop()
74
+ raise
75
+ self._playwright = playwright
76
+ self._browser = browser
77
+ log.info("TurnstileSolver browser started lazily")
78
+
79
+ async def stop(self) -> None:
80
+ async with self._start_lock:
81
+ if self._owns_browser:
82
+ if self._browser:
83
+ await self._browser.close()
84
+ self._browser = None
85
+ if self._playwright:
86
+ await self._playwright.stop()
87
+ self._playwright = None
88
+ log.info("TurnstileSolver stopped")
89
+
90
+ async def solve(self, params: dict[str, Any]) -> dict[str, Any]:
91
+ await self.start()
92
+ website_url = params["websiteURL"]
93
+ website_key = params["websiteKey"]
94
 
95
  last_error: Exception | None = None
96
  for attempt in range(self._config.captcha_retries):