from __future__ import annotations import base64 from datetime import date from typing import Literal from app.database.counts import ReplayWatchedCount from app.database.score import Score from app.dependencies.database import get_db from app.dependencies.storage import get_storage_service from app.models.mods import int_to_mods from app.models.score import GameMode from app.storage import StorageService from .router import router from fastapi import Depends, HTTPException, Query from pydantic import BaseModel from sqlmodel import col, select from sqlmodel.ext.asyncio.session import AsyncSession class ReplayModel(BaseModel): content: str encoding: Literal["base64"] = "base64" @router.get( "/get_replay", response_model=ReplayModel, name="获取回放文件", description="获取指定谱面的回放文件。", ) async def download_replay( beatmap: int = Query(..., alias="b", description="谱面 ID"), user: str = Query(..., alias="u", description="用户"), ruleset_id: int | None = Query( None, alias="m", description="Ruleset ID", ge=0, ), score_id: int | None = Query(None, alias="s", description="成绩 ID"), type: Literal["string", "id"] | None = Query( None, description="用户类型:string 用户名称 / id 用户 ID" ), mods: int = Query(0, description="成绩的 MOD"), session: AsyncSession = Depends(get_db), storage_service: StorageService = Depends(get_storage_service), ): mods_ = int_to_mods(mods) if score_id is not None: score_record = await session.get(Score, score_id) if score_record is None: raise HTTPException(status_code=404, detail="Score not found") else: try: score_record = ( await session.exec( select(Score).where( Score.beatmap_id == beatmap, Score.user_id == user if type == "id" or user.isdigit() else col(Score.user).has(username=user), Score.mods == mods_, Score.gamemode == GameMode.from_int_extra(ruleset_id) if ruleset_id is not None else True, ) ) ).first() if score_record is None: raise HTTPException(status_code=404, detail="Score not found") except KeyError: raise HTTPException(status_code=400, detail="Invalid request") filepath = ( f"replays/{score_record.id}_{score_record.beatmap_id}" f"_{score_record.user_id}_lazer_replay.osr" ) if not await storage_service.is_exists(filepath): raise HTTPException(status_code=404, detail="Replay file not found") replay_watched_count = ( await session.exec( select(ReplayWatchedCount).where( ReplayWatchedCount.user_id == score_record.user_id, ReplayWatchedCount.year == date.today().year, ReplayWatchedCount.month == date.today().month, ) ) ).first() if replay_watched_count is None: replay_watched_count = ReplayWatchedCount( user_id=score_record.user_id, year=date.today().year, month=date.today().month, ) session.add(replay_watched_count) replay_watched_count.count += 1 await session.commit() data = await storage_service.read_file(filepath) return ReplayModel( content=base64.b64encode(data).decode("utf-8"), encoding="base64" )