121 lines
4.0 KiB
Python
121 lines
4.0 KiB
Python
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()
|