95 lines
3.4 KiB
Python
95 lines
3.4 KiB
Python
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")
|