mirror of
https://github.com/ThePhaseless/Byparr.git
synced 2026-09-24 14:20:08 +01:00
Nothing waited for the destination once the interstitial let go: page_html stayed unset and the networkidle wait only ran on the branch that never saw a challenge, so a challenge clearing on its own returned whatever had loaded by then. Wait for it on both branches. An exhausted budget produced timeout=0, which Playwright reads as no timeout at all, turning every remaining wait unbounded exactly when it should fail fast. Floor it instead. Scroll the widget into view before measuring it, since bounding_box reports viewport coordinates and an off-screen widget was clicked at a point that hit nothing, and reject containers taller than a checkbox row so a full-page wrapper cannot pass for one - both reported success while clicking blank space. Drop max_attempts, which nothing reads now that the solver is gone, and refresh AGENTS.md, which still described camoufox and a solver in the dependency. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1.9 KiB
1.9 KiB
Copilot Instructions
Project overview
- FastAPI service that mimics FlareSolverr-style API for bypassing anti-bot pages using invisible_playwright.
- Entry point: main app in main.py; routes and request flow defined in src/endpoints.py and src/models.py.
- Browser lifecycle is owned by get_browser() in src/utils.py, which yields a page and context for each request.
Architecture and data flow
- Request flow: POST /v1 -> read_item() -> page.goto() -> wait for load states -> detect the interstitial -> click its checkbox until it clears -> return LinkResponse.
- Challenge detection uses detect_cloudflare_challenge() from playwright_captcha; the challenge is over when its markup goes, not when a solver says so.
- Health check hits /v1 internally with https://google.com and fails if status is not OK.
- Logging: LogRequest middleware logs only POST /v1 timing and outcome; other paths pass through.
Key modules and patterns
- Models use Pydantic v2 with camelCase aliasing for responses (see src/models.py).
- LinkResponse.invalid() is the standard error response shape; keep fields consistent with FlareSolverr style.
- get_camoufox() constructs AsyncCamoufox with addons and optional proxy config from env vars.
Config and environment
- Core env vars in src/consts.py: HOST, PORT, PROXY_SERVER, PROXY_USERNAME, PROXY_PASSWORD, LOG_LEVEL, VERSION.
- VERSION strips leading "v" for tag-style values.
Developer workflows
- Local run: uv sync && uv run main.py
- Init mode: uv run main.py --init (pre-warms health check via browser setup)
- Tests: uv sync --group test && uv run pytest --retries 5
- Docker troubleshooting: docker build --target test .
Tests and external dependencies
- tests/main_test.py calls real websites; tests are network-dependent and may be skipped based on upstream status.
- HTTP client tests use starlette.testclient + httpx; avoid mocking unless needed for local-only changes.