Files
g0v0-server/app/router/v1/replay.py
2025-08-22 08:21:52 +00:00

95 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 Database
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
class ReplayModel(BaseModel):
content: str
encoding: Literal["base64"] = "base64"
@router.get(
"/get_replay",
response_model=ReplayModel,
name="获取回放文件",
description="获取指定谱面的回放文件。",
)
async def download_replay(
session: Database,
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"),
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}_{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")