From e1f0d32a5b941e5fddbea164853b450962b9ab4e Mon Sep 17 00:00:00 2001 From: cmyui Date: Sun, 30 Jun 2024 06:16:23 -0400 Subject: [PATCH] Add internal API for .osu files --- app/adapters/osu_api_v1.py | 23 +++++++++++++++++++++-- app/api/internal/v1/__init__.py | 2 ++ app/api/internal/v1/osu_api_v1.py | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 app/api/internal/v1/osu_api_v1.py diff --git a/app/adapters/osu_api_v1.py b/app/adapters/osu_api_v1.py index d6f3483..80779a3 100644 --- a/app/adapters/osu_api_v1.py +++ b/app/adapters/osu_api_v1.py @@ -10,7 +10,7 @@ from app.common_models import GameMode osu_api_v1_http_client = httpx.AsyncClient( - base_url="https://old.ppy.sh/api/", + base_url="https://old.ppy.sh/", timeout=httpx.Timeout(15), ) @@ -68,7 +68,7 @@ async def fetch_one_beatmap( try: osu_api_v1_key = random.choice(settings.OSU_API_V1_API_KEYS_POOL) response = await osu_api_v1_http_client.get( - "get_beatmaps", + "api/get_beatmaps", params={ "k": osu_api_v1_key, **({"b": beatmap_id} if beatmap_id else {"h": beatmap_md5}), @@ -100,3 +100,22 @@ async def fetch_one_beatmap( }, ) raise + + +async def fetch_beatmap_osu_file_data(beatmap_id: int) -> bytes | None: + try: + response = await osu_api_v1_http_client.get(f"osu/{beatmap_id}") + if response.status_code == 404: + return None + if response.status_code == 403: + raise ValueError("osu api is down") from None + response.raise_for_status() + return response.read() + except Exception: + logging.exception( + "Failed to fetch beatmap osu file from osu! API v1", + extra={ + "beatmap_id": beatmap_id, + }, + ) + raise diff --git a/app/api/internal/v1/__init__.py b/app/api/internal/v1/__init__.py index 6877a21..927c27b 100644 --- a/app/api/internal/v1/__init__.py +++ b/app/api/internal/v1/__init__.py @@ -1,9 +1,11 @@ from fastapi import APIRouter from . import akatsuki +from . import osu_api_v1 from . import osu_api_v2 v1_router = APIRouter() v1_router.include_router(akatsuki.router) v1_router.include_router(osu_api_v2.router) +v1_router.include_router(osu_api_v1.router) diff --git a/app/api/internal/v1/osu_api_v1.py b/app/api/internal/v1/osu_api_v1.py new file mode 100644 index 0000000..2dea894 --- /dev/null +++ b/app/api/internal/v1/osu_api_v1.py @@ -0,0 +1,23 @@ +from fastapi import APIRouter +from fastapi import Response + +from app.adapters import osu_api_v1 + +router = APIRouter(tags=["osu Files"]) + + +@router.get("/api/osu-api/v1/osu-files/{beatmap_id}") +async def download_beatmap_osu_file(beatmap_id: int) -> Response: + beatmap_osu_file_data = await osu_api_v1.fetch_beatmap_osu_file_data(beatmap_id) + # TODO: consider at which points in beatmaps-service we should update + # the .osu file that is currently saved in wasabi s3 storage. + if beatmap_osu_file_data is not None: + return Response( + beatmap_osu_file_data, + media_type="application/octet-stream", + headers={ + "Content-Disposition": f"attachment; filename={beatmap_id}.osu", + }, + ) + + return Response(status_code=404)