From ac54603acba6fcf6d56d4496a626789b9f744ddb Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Tue, 12 Aug 2025 03:58:30 +0000 Subject: [PATCH] feat(score): store replay to storage service --- app/path.py | 3 --- app/router/v2/score.py | 27 ++++++++++++++++++--------- app/signalr/hub/spectator.py | 14 +++++++++----- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/app/path.py b/app/path.py index d086837..d723c53 100644 --- a/app/path.py +++ b/app/path.py @@ -3,6 +3,3 @@ from __future__ import annotations from pathlib import Path STATIC_DIR = Path(__file__).parent.parent / "static" - -REPLAY_DIR = Path(__file__).parent.parent / "replays" -REPLAY_DIR.mkdir(exist_ok=True) diff --git a/app/router/v2/score.py b/app/router/v2/score.py index 7ebd757..acd3bb0 100644 --- a/app/router/v2/score.py +++ b/app/router/v2/score.py @@ -32,6 +32,7 @@ from app.database.score import ( ) from app.dependencies.database import get_db, get_redis from app.dependencies.fetcher import get_fetcher +from app.dependencies.storage import get_storage_service from app.dependencies.user import get_current_user from app.fetcher import Fetcher from app.models.room import RoomCategory @@ -42,12 +43,13 @@ from app.models.score import ( Rank, SoloScoreSubmissionInfo, ) -from app.path import REPLAY_DIR +from app.storage.base import StorageService +from app.storage.local import LocalStorageService from .router import router from fastapi import Body, Depends, Form, HTTPException, Query, Security -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, RedirectResponse from httpx import HTTPError from pydantic import BaseModel from redis.asyncio import Redis @@ -715,15 +717,15 @@ async def download_score_replay( score_id: int, current_user: User = Security(get_current_user, scopes=["public"]), db: AsyncSession = Depends(get_db), + storage_service: StorageService = Depends(get_storage_service), ): score = (await db.exec(select(Score).where(Score.id == score_id))).first() if not score: raise HTTPException(status_code=404, detail="Score not found") - filename = f"{score.id}_{score.beatmap_id}_{score.user_id}_lazer_replay.osr" - path = REPLAY_DIR / filename + filepath = f"replays/{score.id}_{score.beatmap_id}_{score.user_id}_lazer_replay.osr" - if not path.exists(): + if not await storage_service.is_exists(filepath): raise HTTPException(status_code=404, detail="Replay file not found") is_friend = ( @@ -755,7 +757,14 @@ async def download_score_replay( db.add(replay_watched_count) replay_watched_count.count += 1 await db.commit() - - return FileResponse( - path=path, filename=filename, media_type="application/x-osu-replay" - ) + if isinstance(storage_service, LocalStorageService): + return FileResponse( + path=await storage_service.get_file_url(filepath), + filename=filepath, + media_type="application/x-osu-replay", + ) + else: + return RedirectResponse( + await storage_service.get_file_url(filepath), + 301, + ) diff --git a/app/signalr/hub/spectator.py b/app/signalr/hub/spectator.py index dcc47f3..418228c 100644 --- a/app/signalr/hub/spectator.py +++ b/app/signalr/hub/spectator.py @@ -13,6 +13,7 @@ from app.database.score import Score from app.database.score_token import ScoreToken from app.dependencies.database import engine from app.dependencies.fetcher import get_fetcher +from app.dependencies.storage import get_storage_service from app.models.mods import mods_to_int from app.models.score import LegacyReplaySoloScoreInfo, ScoreStatistics from app.models.spectator_hub import ( @@ -25,7 +26,6 @@ from app.models.spectator_hub import ( StoreClientState, StoreScore, ) -from app.path import REPLAY_DIR from app.utils import unix_timestamp_to_windows from .hub import Client, Hub @@ -64,7 +64,7 @@ def encode_string(s: str) -> bytes: return ret -def save_replay( +async def save_replay( ruleset_id: int, md5: str, username: str, @@ -136,10 +136,14 @@ def save_replay( data.extend(struct.pack("