207 lines
5.4 KiB
Python
207 lines
5.4 KiB
Python
from __future__ import annotations
|
||
|
||
from enum import IntEnum
|
||
from typing import Annotated, Any, Literal
|
||
|
||
from .score import Rank
|
||
|
||
from pydantic import BaseModel, BeforeValidator, Field, PlainSerializer
|
||
|
||
|
||
class BeatmapRankStatus(IntEnum):
|
||
GRAVEYARD = -2
|
||
WIP = -1
|
||
PENDING = 0
|
||
RANKED = 1
|
||
APPROVED = 2
|
||
QUALIFIED = 3
|
||
LOVED = 4
|
||
|
||
def has_leaderboard(self) -> bool:
|
||
return self in {
|
||
BeatmapRankStatus.RANKED,
|
||
BeatmapRankStatus.APPROVED,
|
||
BeatmapRankStatus.QUALIFIED,
|
||
BeatmapRankStatus.LOVED,
|
||
}
|
||
|
||
def has_pp(self) -> bool:
|
||
return self in {
|
||
BeatmapRankStatus.RANKED,
|
||
BeatmapRankStatus.APPROVED,
|
||
}
|
||
|
||
def ranked(self) -> bool:
|
||
# https://osu.ppy.sh/wiki/Gameplay/Score/Ranked_score
|
||
return self in {BeatmapRankStatus.RANKED, BeatmapRankStatus.APPROVED, BeatmapRankStatus.LOVED}
|
||
|
||
|
||
class Genre(IntEnum):
|
||
ANY = 0
|
||
UNSPECIFIED = 1
|
||
VIDEO_GAME = 2
|
||
ANIME = 3
|
||
ROCK = 4
|
||
POP = 5
|
||
OTHER = 6
|
||
NOVELTY = 7
|
||
HIP_HOP = 9
|
||
ELECTRONIC = 10
|
||
METAL = 11
|
||
CLASSICAL = 12
|
||
FOLK = 13
|
||
JAZZ = 14
|
||
|
||
|
||
class Language(IntEnum):
|
||
ANY = 0
|
||
UNSPECIFIED = 1
|
||
ENGLISH = 2
|
||
JAPANESE = 3
|
||
CHINESE = 4
|
||
INSTRUMENTAL = 5
|
||
KOREAN = 6
|
||
FRENCH = 7
|
||
GERMAN = 8
|
||
SWEDISH = 9
|
||
ITALIAN = 10
|
||
SPANISH = 11
|
||
RUSSIAN = 12
|
||
POLISH = 13
|
||
OTHER = 14
|
||
|
||
|
||
class BeatmapAttributes(BaseModel):
|
||
star_rating: float
|
||
max_combo: int
|
||
|
||
# osu
|
||
aim_difficulty: float | None = None
|
||
aim_difficult_slider_count: float | None = None
|
||
speed_difficulty: float | None = None
|
||
speed_note_count: float | None = None
|
||
slider_factor: float | None = None
|
||
aim_difficult_strain_count: float | None = None
|
||
speed_difficult_strain_count: float | None = None
|
||
|
||
# taiko
|
||
mono_stamina_factor: float | None = None
|
||
|
||
|
||
def _parse_list(v: Any):
|
||
if isinstance(v, str):
|
||
return v.split(".")
|
||
return v
|
||
|
||
|
||
class SearchQueryModel(BaseModel):
|
||
# model_config = ConfigDict(serialize_by_alias=True)
|
||
|
||
q: str = Field("", description="搜索关键词")
|
||
c: Annotated[
|
||
list[Literal["recommended", "converts", "follows", "spotlights", "featured_artists"]],
|
||
BeforeValidator(_parse_list),
|
||
PlainSerializer(lambda x: ".".join(x)),
|
||
] = Field(
|
||
default_factory=list,
|
||
description=(
|
||
"常规:recommended 推荐难度 / converts 包括转谱 / follows 已关注谱师 / "
|
||
"spotlights 聚光灯谱面 / featured_artists 精选艺术家"
|
||
),
|
||
)
|
||
m: int | None = Field(None, description="模式", alias="m")
|
||
s: Literal[
|
||
"any",
|
||
"leaderboard",
|
||
"ranked",
|
||
"qualified",
|
||
"loved",
|
||
"favourites",
|
||
"pending",
|
||
"wip",
|
||
"graveyard",
|
||
"mine",
|
||
] = Field(
|
||
default="leaderboard",
|
||
description=(
|
||
"分类:any 全部 / leaderboard 拥有排行榜 / ranked 上架 / "
|
||
"qualified 过审 / loved 社区喜爱 / favourites 收藏 / "
|
||
"pending 待定 / wip 制作中 / graveyard 坟场 / mine 我做的谱面"
|
||
),
|
||
)
|
||
l: Literal[ # noqa: E741
|
||
"any",
|
||
"unspecified",
|
||
"english",
|
||
"japanese",
|
||
"chinese",
|
||
"instrumental",
|
||
"korean",
|
||
"french",
|
||
"german",
|
||
"swedish",
|
||
"spanish",
|
||
"italian",
|
||
"russian",
|
||
"polish",
|
||
"other",
|
||
] = Field(
|
||
default="any",
|
||
description=(
|
||
"语言:any 全部 / unspecified 未指定 / english 英语 / japanese 日语 / "
|
||
"chinese 中文 / instrumental 器乐 / korean 韩语 / "
|
||
"french 法语 / german 德语 / swedish 瑞典语 / "
|
||
"spanish 西班牙语 / italian 意大利语 / russian 俄语 / "
|
||
"polish 波兰语 / other 其他"
|
||
),
|
||
)
|
||
sort: Literal[
|
||
"title_asc",
|
||
"artist_asc",
|
||
"difficulty_asc",
|
||
"updated_asc",
|
||
"ranked_asc",
|
||
"rating_asc",
|
||
"plays_asc",
|
||
"favourites_asc",
|
||
"relevance_asc",
|
||
"nominations_asc",
|
||
"title_desc",
|
||
"artist_desc",
|
||
"difficulty_desc",
|
||
"updated_desc",
|
||
"ranked_desc",
|
||
"rating_desc",
|
||
"plays_desc",
|
||
"favourites_desc",
|
||
"relevance_desc",
|
||
"nominations_desc",
|
||
] = Field(
|
||
...,
|
||
description=(
|
||
"排序方式: title 标题 / artist 艺术家 / difficulty 难度 / updated 更新时间"
|
||
" / ranked 上架时间 / rating 评分 / plays 游玩次数 / favourites 收藏量"
|
||
" / relevance 相关性 / nominations 提名"
|
||
),
|
||
)
|
||
e: Annotated[
|
||
list[Literal["video", "storyboard"]],
|
||
BeforeValidator(_parse_list),
|
||
PlainSerializer(lambda x: ".".join(x)),
|
||
] = Field(default_factory=list, description=("其他:video 有视频 / storyboard 有故事板"))
|
||
r: Annotated[list[Rank], BeforeValidator(_parse_list), PlainSerializer(lambda x: ".".join(x))] = Field(
|
||
default_factory=list, description="成绩"
|
||
)
|
||
played: bool = Field(
|
||
default=False,
|
||
description="玩过",
|
||
)
|
||
nsfw: bool = Field(
|
||
default=False,
|
||
description="不良内容",
|
||
)
|
||
cursor_string: str | None = Field(
|
||
default=None,
|
||
description="游标字符串,用于分页",
|
||
)
|