mirror of
https://github.com/ThePhaseless/Byparr.git
synced 2026-09-24 22:03:30 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03c98375f2 | ||
|
|
4bfb7845dd | ||
|
|
d7c22f042e | ||
|
|
33a1327f93 | ||
|
|
e52616934b | ||
|
|
892daccc60 | ||
|
|
3d91874ddb | ||
|
|
3026ed4a41 | ||
|
|
4b5d82b4f1 | ||
|
|
56d9a4659b | ||
|
|
273622c30c | ||
|
|
d0b51020a0 | ||
|
|
d17def34ba | ||
|
|
40a4bf3d8f | ||
|
|
e0bb4115fb | ||
|
|
9e2d40845c | ||
|
|
6c3da87c00 | ||
|
|
78d97dfd0d | ||
|
|
4461f5a59a | ||
|
|
7dac738ac5 | ||
|
|
ead7a09ce2 | ||
|
|
bf85a854fa | ||
|
|
9a20451ad9 | ||
|
|
150bf80583 | ||
|
|
bcce6779cc | ||
|
|
cd7e803411 | ||
|
|
5dc76167c2 | ||
|
|
8ae150fd87 | ||
|
|
0325877e19 | ||
|
|
c4159e5c38 | ||
|
|
83169ce019 | ||
|
|
1c0929fbc5 | ||
|
|
9170967455 | ||
|
|
d5d0bf7923 | ||
|
|
17854c70ed | ||
|
|
e30954c98c | ||
|
|
2556a1bc88 | ||
|
|
6c065d4dd3 | ||
|
|
096eda0fa3 | ||
|
|
2ebb1bd820 | ||
|
|
bf37539890 | ||
|
|
d7ef83b8c6 | ||
|
|
1a7cd9d657 | ||
|
|
f9387e6942 | ||
|
|
9d8c8db979 | ||
|
|
979e0b4803 | ||
|
|
3dbe3c424c | ||
|
|
bbb7c73065 | ||
|
|
9a353b3da2 | ||
|
|
140a97003e | ||
|
|
c9e29f578d | ||
|
|
c37ab51179 | ||
|
|
962db9409c | ||
|
|
96a9cc7ba9 | ||
|
|
bf9460b960 | ||
|
|
c0547192dd | ||
|
|
008077076c | ||
|
|
b33444dc48 | ||
|
|
b8c8576e5a | ||
|
|
905d802a26 | ||
|
|
f99429fdea | ||
|
|
1a4ec03587 | ||
|
|
ee2630dce2 | ||
|
|
82130b77c0 | ||
|
|
faf7e5e51a | ||
|
|
597faa48dc | ||
|
|
a28dbbe972 | ||
|
|
82124dee9b | ||
|
|
0551c7b82b | ||
|
|
b483dba080 | ||
|
|
7533d039ac | ||
|
|
38b2ea0798 | ||
|
|
58ae7964df | ||
|
|
5283fb2d0e | ||
|
|
b3e7662782 | ||
|
|
074a3dd712 | ||
|
|
cb48f16370 | ||
|
|
637de7572d | ||
|
|
7b55252a73 | ||
|
|
cbe4cf57a5 | ||
|
|
0775d107ad | ||
|
|
d36972b80e | ||
|
|
27ec17f7f2 | ||
|
|
0b2bf9e12a | ||
|
|
8c6906c916 | ||
|
|
3103051ccf |
@@ -1,5 +1,4 @@
|
||||
FROM python:3.12-bullseye
|
||||
FROM ghcr.io/astral-sh/uv:debian
|
||||
ENV UV_LINK_MODE=copy
|
||||
|
||||
RUN apt update && apt upgrade -y && apt install -y chromium chromium-driver xvfb
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||
RUN apt update && apt upgrade -y && apt install -y chromium chromium-driver xvfb git
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
about: Create a bug report
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
assignees: 'ThePhaseless'
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -23,50 +23,7 @@ env:
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.12"
|
||||
cache: "pip"
|
||||
|
||||
- name: Set up Poetry
|
||||
run: pip install poetry
|
||||
|
||||
- name: Setup a local virtual environment (if no poetry.toml file)
|
||||
run: |
|
||||
poetry config virtualenvs.create true --local
|
||||
poetry config virtualenvs.in-project true --local
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Define a cache for the virtual environment based on the dependencies lock file
|
||||
with:
|
||||
path: ./.venv
|
||||
key: venv-${{ hashFiles('poetry.lock') }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
poetry install
|
||||
sudo apt update
|
||||
sudo apt install -y xvfb scrot python3-tk
|
||||
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
sudo apt install -y ./google-chrome-stable_current_amd64.deb
|
||||
rm ./google-chrome-stable_current_amd64.deb
|
||||
|
||||
- name: Run tests
|
||||
run: poetry run pytest --retries 2 -n auto --xvfb
|
||||
|
||||
- name: Upload screenshots if tests fail
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: screenshots
|
||||
|
||||
build:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -83,21 +40,19 @@ jobs:
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da #v3.7.0
|
||||
with:
|
||||
cosign-release: "v2.2.4"
|
||||
uses: sigstore/cosign-installer@v3
|
||||
|
||||
# Set up BuildKit Docker container builder to be able to build
|
||||
# multi-platform images and export cache
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
@@ -107,7 +62,7 @@ jobs:
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
@@ -115,23 +70,35 @@ jobs:
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=raw,enable=${{ github.event_name != 'pull_request' && github.ref_name == 'main' }}, value=latest
|
||||
type=raw,enable=${{ github.ref_type == 'tag' }}, value=latest
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Test
|
||||
id: test
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
cache-from: type=gha
|
||||
pull: true
|
||||
cache-to: type=gha,mode=max
|
||||
target: test
|
||||
|
||||
# Build and push Docker image with Buildx (don't push on PR)
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
pull: true
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: GITHUB_BUILD=true
|
||||
build-args: GITHUB_BUILD=true,VERSION=${{ github.ref_name }}
|
||||
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
|
||||
+19
-12
@@ -1,4 +1,4 @@
|
||||
FROM python:3.12-slim-bullseye
|
||||
FROM debian:bullseye-slim AS base
|
||||
|
||||
# Inspired by https://github.com/Hudrolax/uc-docker-alpine/
|
||||
|
||||
@@ -11,22 +11,29 @@ ENV \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
# prevents python creating .pyc files
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
# do not ask any interactive question
|
||||
POETRY_NO_INTERACTION=1 \
|
||||
POETRY_VIRTUALENVS_IN_PROJECT=true \
|
||||
PATH="${HOME}/.local/bin:$PATH" \
|
||||
DISPLAY=:0
|
||||
|
||||
WORKDIR /app
|
||||
EXPOSE 8191
|
||||
RUN apt update &&\
|
||||
apt install -y xvfb scrot python3-tk curl chromium chromium-driver
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||
ENV PATH="${HOME}/.local/bin:$PATH"
|
||||
COPY pyproject.toml poetry.lock ./
|
||||
RUN poetry install
|
||||
apt upgrade -y &&\
|
||||
apt install -y --no-install-recommends --no-install-suggests xauth xvfb scrot curl chromium chromium-driver ca-certificates x11-common
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
COPY pyproject.toml uv.lock ./
|
||||
RUN uv sync
|
||||
|
||||
COPY . .
|
||||
RUN cd .venv/lib/*/site-packages/seleniumbase/drivers && ln -s /usr/bin/chromedriver uc_driver
|
||||
|
||||
ENV USE_HEADLESS=false
|
||||
|
||||
FROM base AS test
|
||||
|
||||
RUN uv sync --group test
|
||||
RUN ./test.sh
|
||||
|
||||
FROM base
|
||||
|
||||
EXPOSE 8191
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=5s --retries=3 CMD [ "curl", "http://localhost:8191/health" ]
|
||||
RUN ln /usr/bin/chromedriver ./.venv/lib/python3.12/site-packages/seleniumbase/drivers/uc_driver
|
||||
CMD ["./cmd.sh"]
|
||||
@@ -2,46 +2,62 @@
|
||||
|
||||
An alternative to [FlareSolverr](https://github.com/FlareSolverr/FlareSolverr) as a drop-in replacement, build with [seleniumbase](https://seleniumbase.io/) and [FastAPI](https://fastapi.tiangolo.com).
|
||||
|
||||
> [!WARNING]
|
||||
> [!IMPORTANT]
|
||||
> Due to recent challenge changes, this software does not guarantee that the Cloudflare challenge will be bypassed. Cloudflare likely requires valid network traffic originating from the user’s public IP address to mark a connection as legitimate. While this tool may bypass the initial browser check, it does not ensure that requests will consistently pass Cloudflare's validation. More testing and data are required to understand how Cloudflare identifies connections and requests as valid. Invalid requests will result in Byparr's looping and eventually time-outing.
|
||||
|
||||
> [!WARNING]
|
||||
> [!IMPORTANT]
|
||||
> Support for NAS devices (like Synology) is minimal. Please report issues, but do not expect it to be fixed quickly. The only ARM device I have is a free Ampere Oracle VM, so I can only test ARM support on that. See [#22](https://github.com/ThePhaseless/Byparr/issues/22) and [#3](https://github.com/ThePhaseless/Byparr/issues/3)
|
||||
|
||||
> [!NOTE]
|
||||
> Thanks to FastAPI implementation, now you can also see the API documentation at `/docs` or `/` (redirect to `/docs`) endpoints.
|
||||
|
||||
## Troubleshooting
|
||||
## Troubleshooting (Docker required)
|
||||
|
||||
1. Clone repo to the host that has the container has issues on.
|
||||
2. Using vscode and `SSH extention`, connect to the host and open repo in it.
|
||||
3. Download `devcontainers` extention and reopen repo in container (with `CTRL + SHIFT + P` -> `Reopen in devcontainer`)
|
||||
2. Using vscode and `SSH extension`, connect to the host and open repo in it.
|
||||
3. Download `Dev Containers` extension and reopen repo in container (with `CTRL + SHIFT + P` -> `Reopen in devcontainer`)
|
||||
4. Forward port 6080 from devcontainer (port of noVNC server) to the host.
|
||||
5. Open `http://localhost:6080` and connect to the virtual desktop.
|
||||
6. Check if `chromium` works by running in VNC's terminal command `chromium --no-sandbox`.
|
||||
7. If chromium works, run (or debug) tests from VS Code.
|
||||
1. If code works, congrats! (/s) You are on your own.
|
||||
2. If it does not, try another host or network, try again and create issue about the problem.
|
||||
1. If code works, congrats! (not really) You are on your own.
|
||||
2. If it does not, try on another host or network and create an issue if problem persists.
|
||||
|
||||
## Options
|
||||
|
||||
| Env | Default | Description |
|
||||
| -------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `USE_XVFB` | `false` | Use virtual desktop with Xvfb. (Linux only) (Can cause performance hog [#14](https://github.com/ThePhaseless/Byparr/issues/14)) |
|
||||
| `USE_HEADLESS` | `true/false on docker` | Use headless chromium. |
|
||||
|
||||
## Tags
|
||||
|
||||
- `v*.*.*`/`latest` - Releases considered stable
|
||||
- `main` - Latest release from main branch (untested)
|
||||
|
||||
## Usage
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
byparr:
|
||||
image: ghcr.io/thephaseless/byparr:latest
|
||||
environment:
|
||||
- LOG_LEVEL=INFO # optional
|
||||
ports:
|
||||
- "8191:8191" # Optional if needed to make make requests/check docs on host
|
||||
See `compose.yaml`
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker run -p 8191:8191 ghcr.io/thephaseless/byparr:latest
|
||||
```
|
||||
|
||||
### Local
|
||||
|
||||
```bash
|
||||
uv sync && ./cmd.sh
|
||||
```
|
||||
|
||||
## Need help with / TODO
|
||||
|
||||
- [x] Slimming container (only ~650 mB now!)
|
||||
- [x] Slimming container (only ~650 MB now!)
|
||||
- [x] Add more anti-bot challenges
|
||||
- [x] Add docstrings
|
||||
- [x] Add doc strings
|
||||
- [x] Implement versioning
|
||||
- [ ] Proxy support
|
||||
- [x] Add more architectures support
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
. .venv/bin/activate && python3 main.py
|
||||
uv run main.py
|
||||
@@ -15,26 +15,27 @@ import src.utils
|
||||
import src.utils.consts
|
||||
from src.models.requests import LinkRequest, LinkResponse, Solution
|
||||
from src.utils import logger
|
||||
from src.utils.consts import LOG_LEVEL
|
||||
from src.utils.consts import LOG_LEVEL, USE_HEADLESS, USE_XVFB
|
||||
|
||||
app = FastAPI(debug=LOG_LEVEL == logging.DEBUG, log_level=LOG_LEVEL)
|
||||
|
||||
cookies = []
|
||||
|
||||
|
||||
@app.get("/")
|
||||
def read_root():
|
||||
"""Redirect to /docs."""
|
||||
logger.info("Redirecting to /docs")
|
||||
logger.debug("Redirecting to /docs")
|
||||
return RedirectResponse(url="/docs", status_code=301)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
"""Health check endpoint."""
|
||||
logger.info("Health check")
|
||||
|
||||
health_check_request = read_item(
|
||||
LinkRequest.model_construct(url="https://prowlarr.servarr.com/v1/ping")
|
||||
)
|
||||
|
||||
if health_check_request.solution.status != HTTPStatus.OK:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
@@ -45,24 +46,40 @@ async def health_check():
|
||||
|
||||
|
||||
@app.post("/v1")
|
||||
def read_item(request: LinkRequest):
|
||||
def read_item(request: LinkRequest) -> LinkResponse:
|
||||
"""Handle POST requests."""
|
||||
start_time = int(time.time() * 1000)
|
||||
# request.url = "https://nowsecure.nl"
|
||||
logger.info(f"Request: {request}")
|
||||
|
||||
# Check is string is url
|
||||
if not (request.url.startswith("http://") or request.url.startswith("https://")):
|
||||
return LinkResponse.invalid(request.url)
|
||||
|
||||
response: LinkResponse
|
||||
|
||||
# start_time = int(time.time() * 1000)
|
||||
try:
|
||||
with SB(uc=True, locale_code="en", test=False, xvfb=True, ad_block=True) as sb:
|
||||
with SB(
|
||||
uc=True,
|
||||
locale_code="en",
|
||||
test=False,
|
||||
ad_block=True,
|
||||
xvfb=USE_XVFB,
|
||||
headless=USE_HEADLESS,
|
||||
) as sb:
|
||||
try:
|
||||
sb: BaseCase
|
||||
global cookies # noqa: PLW0603
|
||||
if cookies:
|
||||
sb.uc_open_with_reconnect(request.url)
|
||||
sb.add_cookies(cookies)
|
||||
sb.uc_open_with_reconnect(request.url)
|
||||
source = sb.get_page_source()
|
||||
source_bs = BeautifulSoup(source, "html.parser")
|
||||
title_tag = source_bs.title
|
||||
logger.info(f"Got webpage: {request.url}")
|
||||
logger.debug(f"Got webpage: {request.url}")
|
||||
if title_tag and title_tag.string in src.utils.consts.CHALLENGE_TITLES:
|
||||
logger.info("Challenge detected")
|
||||
logger.debug("Challenge detected")
|
||||
sb.uc_gui_click_captcha()
|
||||
logger.info("Clicked captcha")
|
||||
|
||||
@@ -86,9 +103,14 @@ def read_item(request: LinkRequest):
|
||||
),
|
||||
startTimestamp=start_time,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Error: {e}")
|
||||
raise HTTPException(status_code=500, detail="Unknown error, check logs") from e
|
||||
cookies = sb.get_cookies()
|
||||
except Exception as e:
|
||||
logger.error(f"Error: {e}")
|
||||
if sb.driver:
|
||||
sb.driver.quit()
|
||||
raise HTTPException(
|
||||
status_code=500, detail="Unknown error, check logs"
|
||||
) from e
|
||||
|
||||
return response
|
||||
|
||||
|
||||
Generated
-2239
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
[virtualenvs]
|
||||
in-project = true
|
||||
create = true
|
||||
+25
-30
@@ -1,38 +1,33 @@
|
||||
[tool.poetry]
|
||||
# cspell:disable
|
||||
[project]
|
||||
authors = [{ name = "ThePhaseless", email = "kukubaorch@gmail.com" }]
|
||||
license = { text = "LICENSE" }
|
||||
requires-python = "<4.0,>=3.12"
|
||||
name = "Byparr"
|
||||
version = "0.1.0"
|
||||
description = "API for getting cookies for Cloudflare challenges"
|
||||
package-mode = false
|
||||
authors = ["ThePhaseless <kukubaorch@gmail.com>"]
|
||||
readme = "README.md"
|
||||
license = "LICENSE"
|
||||
repository = "https://github.com/ThePhaseless/Byparr"
|
||||
dependencies = [
|
||||
"beautifulsoup4==4.12.3",
|
||||
"fastapi[standard]==0.115.8",
|
||||
"psutil==6.1.1",
|
||||
"pyautogui==0.9.54",
|
||||
"pydantic==2.10.6",
|
||||
"seleniumbase==4.34.6",
|
||||
"uvicorn==0.34.0",
|
||||
]
|
||||
urls = { repository = "https://github.com/ThePhaseless/Byparr" }
|
||||
|
||||
# cspell:disable
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
fastapi = { extras = ["standard"], version = "^0" }
|
||||
seleniumbase = "^4.33.1"
|
||||
beautifulsoup4 = "^4.12.3"
|
||||
uvicorn = "^0.32.1"
|
||||
pydantic = "^2.10.2"
|
||||
pyautogui = "^0.9.54"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
ruff = "^0.8.0"
|
||||
deptry = "^0.21.1"
|
||||
|
||||
[tool.poetry.group.test.dependencies]
|
||||
pytest = "^8.3.3"
|
||||
httpx = "^0.27.2"
|
||||
pytest-retry = "^1.6.3"
|
||||
pytest-progress = "^1.3.0"
|
||||
pytest-asyncio = "^0"
|
||||
pytest-xdist = "^3.6.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"httpx==0.28.1",
|
||||
"pytest==8.3.4",
|
||||
"pytest-asyncio==0.25.3",
|
||||
"pytest-progress==1.3.0",
|
||||
"pytest-retry==1.7.0",
|
||||
"pytest-xdist==3.6.1",
|
||||
]
|
||||
dev = ["deptry==0.23.0", "ruff==0.9.4"]
|
||||
|
||||
[tool.deptry.per_rule_ignores]
|
||||
DEP002 = ["pyautogui"]
|
||||
|
||||
+18
-7
@@ -6,6 +6,8 @@ from typing import Any
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from src.utils import consts
|
||||
|
||||
|
||||
class LinkRequest(BaseModel):
|
||||
cmd: str = "get"
|
||||
@@ -26,9 +28,14 @@ class Solution(BaseModel):
|
||||
response: str
|
||||
|
||||
@classmethod
|
||||
def empty(cls):
|
||||
def invalid(cls, url: str):
|
||||
"""
|
||||
Return an empty Solution with default values.
|
||||
|
||||
Useful for returning an error response.
|
||||
"""
|
||||
return cls(
|
||||
url="",
|
||||
url=url,
|
||||
status=HTTPStatus.INTERNAL_SERVER_ERROR,
|
||||
cookies=[],
|
||||
userAgent="",
|
||||
@@ -43,19 +50,23 @@ class LinkResponse(BaseModel):
|
||||
solution: Solution
|
||||
startTimestamp: int # noqa: N815 # Ignore to preserve compatibility
|
||||
endTimestamp: int = int(time.time() * 1000) # noqa: N815 # Ignore to preserve compatibility
|
||||
version: str = "3.3.21" # TODO: Implement versioning
|
||||
version: str = consts.VERSION
|
||||
|
||||
@classmethod
|
||||
def invalid(cls):
|
||||
def invalid(cls, url: str):
|
||||
"""
|
||||
Return an invalid LinkResponse with default error values.
|
||||
|
||||
This method is used to generate a response indicating an invalid request.
|
||||
"""
|
||||
return cls(
|
||||
status="error",
|
||||
message="Invalid request",
|
||||
solution=Solution.empty(),
|
||||
solution=Solution.invalid(url),
|
||||
startTimestamp=int(time.time() * 1000),
|
||||
endTimestamp=int(time.time() * 1000),
|
||||
version="3.3.21",
|
||||
)
|
||||
|
||||
|
||||
class NoChromeExtensionError(Exception):
|
||||
"""No chrome extention found."""
|
||||
"""No chrome extension found."""
|
||||
|
||||
@@ -1,9 +1,35 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
def get_version_from_env():
|
||||
"""
|
||||
Retrieve the version from the environment variable 'VERSION'.
|
||||
|
||||
This function checks the 'VERSION' environment variable for a value
|
||||
that starts with 'v' and returns the version without the prefix.
|
||||
|
||||
Returns:
|
||||
str | None: The version string without the 'v' prefix, or None if
|
||||
the 'VERSION' environment variable is not set or does not start
|
||||
with 'v'.
|
||||
|
||||
"""
|
||||
version_env = os.getenv("VERSION")
|
||||
if not version_env or not version_env.startswith("v"):
|
||||
return None
|
||||
|
||||
return version_env.removeprefix("v")
|
||||
|
||||
|
||||
LOG_LEVEL = os.getenv("LOG_LEVEL") or "INFO"
|
||||
LOG_LEVEL = logging.getLevelNamesMapping()[LOG_LEVEL.upper()]
|
||||
|
||||
VERSION = get_version_from_env() or "unknown"
|
||||
|
||||
USE_XVFB = os.getenv("USE_XVFB", "false") in ["true", "1"]
|
||||
USE_HEADLESS = os.getenv("USE_HEADLESS", "true").lower() in ["true", "1"]
|
||||
|
||||
CHALLENGE_TITLES = [
|
||||
# Cloudflare
|
||||
"Just a moment...",
|
||||
|
||||
@@ -10,21 +10,13 @@ from src.models.requests import LinkRequest
|
||||
client = TestClient(app)
|
||||
|
||||
test_websites = [
|
||||
"https://btmet.com/",
|
||||
"https://ext.to/",
|
||||
]
|
||||
|
||||
# Not testable on github actions
|
||||
github_restricted = [
|
||||
"https://www.ygg.re/",
|
||||
"https://extratorrent.st/",
|
||||
"https://idope.se/",
|
||||
"https://speed.cd/login",
|
||||
]
|
||||
|
||||
# if os.getenv("GITHUB_ACTIONS") != "true":
|
||||
test_websites.extend(github_restricted)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("website", test_websites)
|
||||
def test_bypass(website: str):
|
||||
|
||||
Reference in New Issue
Block a user