nah gonna redo it again

This commit is contained in:
bootunloader
2026-01-03 09:55:02 +02:00
parent b36492dc52
commit c7ff53e8ac
4 changed files with 442 additions and 1484 deletions

View File

@@ -1,11 +1,16 @@
import logging import logging
import os
import time import time
from typing import Dict, List, Optional from typing import Dict, List, Optional
from urllib.parse import urlencode
import aiohttp
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Request from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse, Response from fastapi.responses import JSONResponse, Response
from pydantic import BaseModel from pydantic import BaseModel
from scrapling.fetchers import StealthySession
load_dotenv()
# Configure logging # Configure logging
logging.basicConfig( logging.basicConfig(
@@ -19,6 +24,10 @@ app = FastAPI()
logger.info("FastAPI Proxy Server initialized") logger.info("FastAPI Proxy Server initialized")
SCRAPERAPI_API_KEY = os.getenv("SCRAPERAPI_API_KEY")
if not SCRAPERAPI_API_KEY:
raise ValueError("SCRAPERAPI_API_KEY is not set")
CONSTANTS = { CONSTANTS = {
"SESSION_KEY_NAME": "SID", "SESSION_KEY_NAME": "SID",
@@ -27,6 +36,7 @@ CONSTANTS = {
"LAST_FETCHED_KEY": "LAST_FETCHED", "LAST_FETCHED_KEY": "LAST_FETCHED",
"SCRAP_API_URL": "https://gamebooking24.com/lottery-api", "SCRAP_API_URL": "https://gamebooking24.com/lottery-api",
"SCRAP_API_SESSION_KEY": "SRAJWT", "SCRAP_API_SESSION_KEY": "SRAJWT",
"SCRAPERAPI_BASE_URL": "http://api.scraperapi.com",
"SCRAP_API_BASE_HEADERS": { "SCRAP_API_BASE_HEADERS": {
"Host": "gamebooking24.com", "Host": "gamebooking24.com",
"Sec-Ch-Ua": '"Not/A)Brand";v="8", "Chromium";v="126"', "Sec-Ch-Ua": '"Not/A)Brand";v="8", "Chromium";v="126"',
@@ -44,33 +54,6 @@ CONSTANTS = {
}, },
} }
# Global StealthySession instance - will be initialized on startup
stealthy_session: Optional[StealthySession] = None
@app.on_event("startup")
async def startup_event():
"""Initialize the StealthySession when the app starts"""
global stealthy_session
logger.info("Initializing StealthySession...")
stealthy_session = StealthySession(
headless=True,
solve_cloudflare=True,
max_pages=10, # Allow up to 10 concurrent requests
google_search=False, # Skip Google search simulation for faster startup
)
logger.info("StealthySession initialized successfully")
@app.on_event("shutdown")
async def shutdown_event():
"""Close the StealthySession when the app shuts down"""
global stealthy_session
if stealthy_session:
logger.info("Closing StealthySession...")
await stealthy_session.close()
logger.info("StealthySession closed successfully")
# Middleware for logging all requests # Middleware for logging all requests
@app.middleware("http") @app.middleware("http")
@@ -109,6 +92,110 @@ def build_headers(
return headers return headers
async def make_get_request(
url: str, params: Optional[Dict] = None, headers: Optional[Dict] = None
):
"""Make a GET request using ScraperAPI"""
if SCRAPERAPI_API_KEY == "<TODO: get and put the key in here>":
raise HTTPException(status_code=500, detail="ScraperAPI API key not configured")
# Build the ScraperAPI request params
scraperapi_params = {
"api_key": SCRAPERAPI_API_KEY,
"url": url,
"render": "true",
}
# Add query params to the target URL if provided
if params:
url_with_params = f"{url}?{urlencode(params)}"
scraperapi_params["url"] = url_with_params
# Make the request to ScraperAPI using aiohttp
async with aiohttp.ClientSession() as session:
async with session.get(
CONSTANTS["SCRAPERAPI_BASE_URL"],
params=scraperapi_params,
headers=headers,
timeout=aiohttp.ClientTimeout(total=60),
) as response:
# Create a simple response-like object
class AsyncResponse:
def __init__(self, aiohttp_response):
self._response = aiohttp_response
self.status_code = aiohttp_response.status
self.headers = aiohttp_response.headers
self._text = None
self._json = None
self._content = None
async def text(self):
if self._text is None:
self._text = await self._response.text()
return self._text
async def json(self):
if self._json is None:
self._json = await self._response.json()
return self._json
async def content(self):
if self._content is None:
self._content = await self._response.read()
return self._content
return AsyncResponse(response)
async def make_post_request(url: str, data: dict, headers: Optional[Dict] = None):
"""Make a POST request using ScraperAPI"""
if SCRAPERAPI_API_KEY == "<TODO: get and put the key in here>":
raise HTTPException(status_code=500, detail="ScraperAPI API key not configured")
# Build the ScraperAPI request params
scraperapi_params = {
"api_key": SCRAPERAPI_API_KEY,
"url": url,
"render": "true",
}
# Make the POST request to ScraperAPI using aiohttp
async with aiohttp.ClientSession() as session:
async with session.post(
CONSTANTS["SCRAPERAPI_BASE_URL"],
params=scraperapi_params,
json=data, # Use json= for JSON payloads (sets Content-Type automatically)
headers=headers,
timeout=aiohttp.ClientTimeout(total=60),
) as response:
# Create a simple response-like object
class AsyncResponse:
def __init__(self, aiohttp_response):
self._response = aiohttp_response
self.status_code = aiohttp_response.status
self.headers = aiohttp_response.headers
self._text = None
self._json = None
self._content = None
async def text(self):
if self._text is None:
self._text = await self._response.text()
return self._text
async def json(self):
if self._json is None:
self._json = await self._response.json()
return self._json
async def content(self):
if self._content is None:
self._content = await self._response.read()
return self._content
return AsyncResponse(response)
# Pydantic models for request bodies # Pydantic models for request bodies
class LoginPayload(BaseModel): class LoginPayload(BaseModel):
userId: str userId: str
@@ -168,13 +255,15 @@ async def get_balance(userId: int, authorization: str):
logger.info(f"[GET /v1/user/get-balance] userId={userId}") logger.info(f"[GET /v1/user/get-balance] userId={userId}")
try: try:
headers = build_headers(authorization=authorization) headers = build_headers(authorization=authorization)
page = stealthy_session.fetch( response = await make_get_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/user/get-balance", f"{CONSTANTS['SCRAP_API_URL']}/v1/user/get-balance",
params={"userId": userId}, params={"userId": userId},
headers=headers, headers=headers,
) )
logger.info(f"[GET /v1/user/get-balance] Response: {page.status}") logger.info(f"[GET /v1/user/get-balance] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[GET /v1/user/get-balance] Error: {str(e)}") logger.error(f"[GET /v1/user/get-balance] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -185,14 +274,37 @@ async def login(payload: LoginPayload):
logger.info(f"[POST /v1/auth/login] - payload={payload.model_dump()}") logger.info(f"[POST /v1/auth/login] - payload={payload.model_dump()}")
try: try:
headers = build_headers(extra_headers={"Content-Type": "application/json"}) headers = build_headers(extra_headers={"Content-Type": "application/json"})
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/auth/login", f"{CONSTANTS['SCRAP_API_URL']}/v1/auth/login",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/auth/login] Response: {page.status}") logger.info(f"[POST /v1/auth/login] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status)
# Handle non-JSON responses (e.g., 403 HTML pages)
if response.status_code == 403:
response_text = await response.text()
logger.error(
f"[POST /v1/auth/login] 403 Forbidden - Response: {response_text[:500]}"
)
raise HTTPException(status_code=403, detail="Request blocked")
# Try to parse as JSON
try:
response_json = await response.json()
except Exception as json_error:
response_text = await response.text()
logger.error(
f"[POST /v1/auth/login] Failed to parse JSON response: {json_error}"
)
logger.error(f"[POST /v1/auth/login] Response text: {response_text[:500]}")
raise HTTPException(
status_code=500, detail=f"Invalid JSON response: {str(json_error)}"
)
return JSONResponse(content=response_json, status_code=response.status_code)
except HTTPException:
raise
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/auth/login] Error: {str(e)}") logger.error(f"[POST /v1/auth/login] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -207,28 +319,28 @@ async def get_captcha(uuid: str):
"Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8" "Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
} }
) )
page = stealthy_session.fetch( response = await make_get_request(
f"{CONSTANTS['SCRAP_API_URL']}/verify/image", f"{CONSTANTS['SCRAP_API_URL']}/verify/image",
params={"uuid": uuid}, params={"uuid": uuid},
headers=headers, headers=headers,
) )
if page.status == 403: if response.status_code == 403:
logger.error("[GET /verify/image] 403 Forbidden - Request blocked")
logger.error( logger.error(
"[GET /verify/image] 403 Forbidden - Cloudflare blocked the request" f"[GET /verify/image] Response headers: {dict(response.headers)}"
) )
logger.error( response_text = await response.text()
f"[GET /verify/image] Response headers: {dict(page.response.headers)}" logger.error(f"[GET /verify/image] Response text: {response_text[:500]}")
)
logger.error(f"[GET /verify/image] Response text: {page.response.text}")
content = await response.content()
logger.info( logger.info(
f"[GET /verify/image] Response: {page.status}, size={len(page.response.content)} bytes" f"[GET /verify/image] Response: {response.status_code}, size={len(content)} bytes"
) )
return Response( return Response(
content=page.response.content, content=content,
media_type="image/png", media_type="image/png",
status_code=page.status, status_code=response.status_code,
) )
except Exception as e: except Exception as e:
logger.error(f"[GET /verify/image] Error: {str(e)}") logger.error(f"[GET /verify/image] Error: {str(e)}")
@@ -245,14 +357,15 @@ async def dealer_list(payload: DealerListPayload, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json"}, extra_headers={"Content-Type": "application/json"},
) )
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/user/dealer-list", f"{CONSTANTS['SCRAP_API_URL']}/v1/user/dealer-list",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/user/dealer-list] Response: {page.status}") logger.info(f"[POST /v1/user/dealer-list] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/user/dealer-list] Error: {str(e)}") logger.error(f"[POST /v1/user/dealer-list] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -268,14 +381,17 @@ async def distributor_list(payload: DistributorListPayload, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json"}, extra_headers={"Content-Type": "application/json"},
) )
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/user/distributor-list", f"{CONSTANTS['SCRAP_API_URL']}/v1/user/distributor-list",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/user/distributor-list] Response: {page.status}") logger.info(
return JSONResponse(content=page.response.json(), status_code=page.status) f"[POST /v1/user/distributor-list] Response: {response.status_code}"
)
return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/user/distributor-list] Error: {str(e)}") logger.error(f"[POST /v1/user/distributor-list] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -289,13 +405,15 @@ async def list_draws(userId: int, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json"}, extra_headers={"Content-Type": "application/json"},
) )
page = stealthy_session.fetch( response = await make_get_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/draw/list-my", f"{CONSTANTS['SCRAP_API_URL']}/v1/draw/list-my",
params={"userId": userId}, params={"userId": userId},
headers=headers, headers=headers,
) )
logger.info(f"[GET /v1/draw/list-my] Response: {page.status}") logger.info(f"[GET /v1/draw/list-my] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[GET /v1/draw/list-my] Error: {str(e)}") logger.error(f"[GET /v1/draw/list-my] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -311,14 +429,15 @@ async def book_list(payload: BookListPayload, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json"}, extra_headers={"Content-Type": "application/json"},
) )
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/book/list2", f"{CONSTANTS['SCRAP_API_URL']}/v1/book/list2",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/book/list2] Response: {page.status}") logger.info(f"[POST /v1/book/list2] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/book/list2] Error: {str(e)}") logger.error(f"[POST /v1/book/list2] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -335,14 +454,15 @@ async def add_multiple(payload: AddMultiplePayload, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json;charset=UTF-8"}, extra_headers={"Content-Type": "application/json;charset=UTF-8"},
) )
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/book/add-multiple", f"{CONSTANTS['SCRAP_API_URL']}/v1/book/add-multiple",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/book/add-multiple] Response: {page.status}") logger.info(f"[POST /v1/book/add-multiple] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/book/add-multiple] Error: {str(e)}") logger.error(f"[POST /v1/book/add-multiple] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@@ -358,14 +478,15 @@ async def delete_multiple(payload: DeleteMultiplePayload, authorization: str):
authorization=authorization, authorization=authorization,
extra_headers={"Content-Type": "application/json;charset=UTF-8"}, extra_headers={"Content-Type": "application/json;charset=UTF-8"},
) )
page = stealthy_session.fetch( response = await make_post_request(
f"{CONSTANTS['SCRAP_API_URL']}/v1/book/delete-multiple", f"{CONSTANTS['SCRAP_API_URL']}/v1/book/delete-multiple",
method="POST",
data=payload.model_dump(), data=payload.model_dump(),
headers=headers, headers=headers,
) )
logger.info(f"[POST /v1/book/delete-multiple] Response: {page.status}") logger.info(f"[POST /v1/book/delete-multiple] Response: {response.status_code}")
return JSONResponse(content=page.response.json(), status_code=page.status) return JSONResponse(
content=await response.json(), status_code=response.status_code
)
except Exception as e: except Exception as e:
logger.error(f"[POST /v1/book/delete-multiple] Error: {str(e)}") logger.error(f"[POST /v1/book/delete-multiple] Error: {str(e)}")
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))

View File

@@ -5,9 +5,8 @@ description = "Add your description here"
readme = "README.md" readme = "README.md"
requires-python = ">=3.13" requires-python = ">=3.13"
dependencies = [ dependencies = [
"cloudscraper>=1.2.71", "aiohttp>=3.13.2",
"fastapi[standard]>=0.128.0", "fastapi[standard]>=0.128.0",
"pydantic>=2.12.5", "pydantic>=2.12.5",
"python-dotenv>=1.2.1", "python-dotenv>=1.2.1",
"scrapling[all]>=0.3.12",
] ]

1167
pyapi/uv.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -340,6 +340,7 @@ export const zPostDataFilters = z.object({
export type PostDataFilters = z.infer<typeof zPostDataFilters>; export type PostDataFilters = z.infer<typeof zPostDataFilters>;
// TODO: THIS IS OUTDATED, HAVE TO UPDATE THIS TO A NEW DISTRIBUTOR
export const DEFAULT_RANDOM_DISTRIBUTOR = { export const DEFAULT_RANDOM_DISTRIBUTOR = {
id: "apiuser:6339", id: "apiuser:6339",
userType: 2, userType: 2,
@@ -350,8 +351,8 @@ export const DEFAULT_RANDOM_DISTRIBUTOR = {
parentDistributor: 0, parentDistributor: 0,
userName: "Baba Sagar", userName: "Baba Sagar",
userCity: "Shikar pur", userCity: "Shikar pur",
userId: "317XY3", userId: "298HAM",
password: "405613", password: "HA16Z7",
accessDenied: 0, accessDenied: 0,
phoneNumber: "", phoneNumber: "",
emailAddress: "", emailAddress: "",