Files
g0v0-server/app/router/v2/beatmapset.py
2025-08-12 08:40:27 +00:00

121 lines
4.0 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
from typing import Literal
from app.database import Beatmap, Beatmapset, BeatmapsetResp, FavouriteBeatmapset, User
from app.dependencies.database import get_db
from app.dependencies.fetcher import get_fetcher
from app.dependencies.user import get_current_user
from app.fetcher import Fetcher
from .router import router
from fastapi import Depends, Form, HTTPException, Path, Query, Security
from fastapi.responses import RedirectResponse
from httpx import HTTPError
from sqlmodel import select
from sqlmodel.ext.asyncio.session import AsyncSession
@router.get(
"/beatmapsets/lookup",
tags=["谱面集"],
name="查询谱面集 (通过谱面 ID)",
response_model=BeatmapsetResp,
description=("通过谱面 ID 查询所属谱面集。"),
)
async def lookup_beatmapset(
beatmap_id: int = Query(description="谱面 ID"),
current_user: User = Security(get_current_user, scopes=["public"]),
db: AsyncSession = Depends(get_db),
fetcher: Fetcher = Depends(get_fetcher),
):
beatmap = await Beatmap.get_or_fetch(db, fetcher, bid=beatmap_id)
resp = await BeatmapsetResp.from_db(
beatmap.beatmapset, session=db, user=current_user
)
return resp
@router.get(
"/beatmapsets/{beatmapset_id}",
tags=["谱面集"],
name="获取谱面集详情",
response_model=BeatmapsetResp,
description="获取单个谱面集详情。",
)
async def get_beatmapset(
beatmapset_id: int = Path(..., description="谱面集 ID"),
current_user: User = Security(get_current_user, scopes=["public"]),
db: AsyncSession = Depends(get_db),
fetcher: Fetcher = Depends(get_fetcher),
):
try:
beatmapset = await Beatmapset.get_or_fetch(db, fetcher, beatmapset_id)
return await BeatmapsetResp.from_db(
beatmapset, session=db, include=["recent_favourites"], user=current_user
)
except HTTPError:
raise HTTPException(status_code=404, detail="Beatmapset not found")
@router.get(
"/beatmapsets/{beatmapset_id}/download",
tags=["谱面集"],
name="下载谱面集",
description="**客户端专属**\n下载谱面集文件。若用户国家为 CN 则跳转国内镜像。",
)
async def download_beatmapset(
beatmapset_id: int = Path(..., description="谱面集 ID"),
no_video: bool = Query(True, alias="noVideo", description="是否下载无视频版本"),
current_user: User = Security(get_current_user, scopes=["*"]),
):
if current_user.country_code == "CN":
return RedirectResponse(
f"https://txy1.sayobot.cn/beatmaps/download/"
f"{'novideo' if no_video else 'full'}/{beatmapset_id}?server=auto"
)
else:
return RedirectResponse(
f"https://api.nerinyan.moe/d/{beatmapset_id}?noVideo={no_video}"
)
@router.post(
"/beatmapsets/{beatmapset_id}/favourites",
tags=["谱面集"],
name="收藏或取消收藏谱面集",
description="**客户端专属**\n收藏或取消收藏指定谱面集。",
)
async def favourite_beatmapset(
beatmapset_id: int = Path(..., description="谱面集 ID"),
action: Literal["favourite", "unfavourite"] = Form(
description="操作类型favourite 收藏 / unfavourite 取消收藏"
),
current_user: User = Security(get_current_user, scopes=["*"]),
db: AsyncSession = Depends(get_db),
):
assert current_user.id is not None
existing_favourite = (
await db.exec(
select(FavouriteBeatmapset).where(
FavouriteBeatmapset.user_id == current_user.id,
FavouriteBeatmapset.beatmapset_id == beatmapset_id,
)
)
).first()
if (action == "favourite" and existing_favourite) or (
action == "unfavourite" and not existing_favourite
):
return
if action == "favourite":
favourite = FavouriteBeatmapset(
user_id=current_user.id, beatmapset_id=beatmapset_id
)
db.add(favourite)
else:
await db.delete(existing_favourite)
await db.commit()