feat(tools): add tools to add daily-challenge
This commit is contained in:
@@ -79,15 +79,13 @@ class Mod(TypedDict):
|
|||||||
|
|
||||||
API_MODS: dict[Literal[0, 1, 2, 3], dict[str, Mod]] = {}
|
API_MODS: dict[Literal[0, 1, 2, 3], dict[str, Mod]] = {}
|
||||||
|
|
||||||
|
mods_file = STATIC_DIR / "mods.json"
|
||||||
def init_mods():
|
raw_mods = json.loads(mods_file.read_text())
|
||||||
mods_file = STATIC_DIR / "mods.json"
|
for ruleset in raw_mods:
|
||||||
raw_mods = json.loads(mods_file.read_text())
|
ruleset_mods = {}
|
||||||
for ruleset in raw_mods:
|
for mod in ruleset["Mods"]:
|
||||||
ruleset_mods = {}
|
ruleset_mods[mod["Acronym"]] = mod
|
||||||
for mod in ruleset["Mods"]:
|
API_MODS[ruleset["RulesetID"]] = ruleset_mods
|
||||||
ruleset_mods[mod["Acronym"]] = mod
|
|
||||||
API_MODS[ruleset["RulesetID"]] = ruleset_mods
|
|
||||||
|
|
||||||
|
|
||||||
def int_to_mods(mods: int) -> list[APIMod]:
|
def int_to_mods(mods: int) -> list[APIMod]:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from app.dependencies.database import with_db
|
|||||||
from app.dependencies.fetcher import get_fetcher
|
from app.dependencies.fetcher import get_fetcher
|
||||||
from app.exception import InvokeException
|
from app.exception import InvokeException
|
||||||
|
|
||||||
from .mods import APIMod
|
from .mods import API_MODS, APIMod
|
||||||
from .room import (
|
from .room import (
|
||||||
DownloadState,
|
DownloadState,
|
||||||
MatchType,
|
MatchType,
|
||||||
@@ -121,19 +121,9 @@ class PlaylistItem(BaseModel):
|
|||||||
star_rating: float
|
star_rating: float
|
||||||
freestyle: bool
|
freestyle: bool
|
||||||
|
|
||||||
def _get_api_mods(self):
|
|
||||||
from app.models.mods import API_MODS, init_mods
|
|
||||||
|
|
||||||
if not API_MODS:
|
|
||||||
init_mods()
|
|
||||||
return API_MODS
|
|
||||||
|
|
||||||
def _validate_mod_for_ruleset(
|
def _validate_mod_for_ruleset(
|
||||||
self, mod: APIMod, ruleset_key: int, context: str = "mod"
|
self, mod: APIMod, ruleset_key: int, context: str = "mod"
|
||||||
) -> None:
|
) -> None:
|
||||||
from typing import Literal, cast
|
|
||||||
|
|
||||||
API_MODS = self._get_api_mods()
|
|
||||||
typed_ruleset_key = cast(Literal[0, 1, 2, 3], ruleset_key)
|
typed_ruleset_key = cast(Literal[0, 1, 2, 3], ruleset_key)
|
||||||
|
|
||||||
# Check if mod is valid for ruleset
|
# Check if mod is valid for ruleset
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Literal, TypedDict, cast
|
|||||||
|
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
|
|
||||||
from .mods import API_MODS, APIMod, init_mods
|
from .mods import API_MODS, APIMod
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
from pydantic import BaseModel, Field, ValidationInfo, field_validator
|
||||||
|
|
||||||
@@ -193,8 +193,6 @@ class SoloScoreSubmissionInfo(BaseModel):
|
|||||||
@field_validator("mods", mode="after")
|
@field_validator("mods", mode="after")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_mods(cls, mods: list[APIMod], info: ValidationInfo):
|
def validate_mods(cls, mods: list[APIMod], info: ValidationInfo):
|
||||||
if not API_MODS:
|
|
||||||
init_mods()
|
|
||||||
incompatible_mods = set()
|
incompatible_mods = set()
|
||||||
# check incompatible mods
|
# check incompatible mods
|
||||||
for mod in mods:
|
for mod in mods:
|
||||||
|
|||||||
95
tools/add_daily_challenge.py
Normal file
95
tools/add_daily_challenge.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
|
||||||
|
|
||||||
|
from app.database import Beatmap
|
||||||
|
from app.dependencies.database import get_redis, with_db
|
||||||
|
from app.dependencies.fetcher import get_fetcher
|
||||||
|
from app.log import logger
|
||||||
|
from app.models.mods import APIMod, get_available_mods
|
||||||
|
from app.models.score import GameMode
|
||||||
|
|
||||||
|
logger.remove()
|
||||||
|
|
||||||
|
|
||||||
|
def mod_inp(name: str, default: list[APIMod]) -> list[APIMod]:
|
||||||
|
mods_inp = input(f"Enter {name} mods (JSON APIMod Array) >>> ")
|
||||||
|
while True:
|
||||||
|
if mods_inp.strip() == "":
|
||||||
|
mods = default
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
mods = json.loads(mods_inp)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
mods_inp = input(f"Invalid input. Enter {name} mods (JSON APIMod) >>> ")
|
||||||
|
continue
|
||||||
|
if not isinstance(mods, list):
|
||||||
|
mods_inp = input(f"Invalid input. Enter {name} mods (JSON APIMod) >>> ")
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
return mods
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with with_db() as session:
|
||||||
|
redis = get_redis()
|
||||||
|
fetcher = await get_fetcher()
|
||||||
|
|
||||||
|
today = datetime.date.today()
|
||||||
|
input_date = input(f"Enter a date ({today}) >>> ")
|
||||||
|
while True:
|
||||||
|
if not input_date:
|
||||||
|
input_date = str(today)
|
||||||
|
elif not re.match(r"^\d{4}-\d{2}-\d{2}$", input_date):
|
||||||
|
input_date = input(f"Invalid date format. Enter a date ({today}) >>> ")
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
beatmap_inp = input("Enter a beatmap ID >>> ")
|
||||||
|
while True:
|
||||||
|
if beatmap_inp.isdigit():
|
||||||
|
beatmap_id = int(beatmap_inp)
|
||||||
|
break
|
||||||
|
beatmap_inp = input("Invalid input. Enter a beatmap ID >>> ")
|
||||||
|
beatmap = await Beatmap.get_or_fetch(session, fetcher, beatmap_id)
|
||||||
|
ruleset_inp = input(f"Enter ruleset ID ({int(beatmap.mode)}) >>> ")
|
||||||
|
while True:
|
||||||
|
if not ruleset_inp:
|
||||||
|
ruleset_inp = str(int(beatmap.mode))
|
||||||
|
elif not ruleset_inp.isdigit():
|
||||||
|
ruleset_inp = input(
|
||||||
|
f"Invalid input. Enter ruleset ID ({int(beatmap.mode)}) >>> "
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
ruleset_id = int(ruleset_inp)
|
||||||
|
if beatmap.mode != GameMode.OSU and ruleset_id != int(beatmap.mode):
|
||||||
|
ruleset_inp = input(
|
||||||
|
f"Invalid input. Enter ruleset ID ({int(beatmap.mode)}) >>> "
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
|
||||||
|
required_mods = mod_inp("required", [])
|
||||||
|
allowed_mods = mod_inp("allowed", get_available_mods(ruleset_id, required_mods))
|
||||||
|
|
||||||
|
await redis.hset( # pyright: ignore[reportGeneralTypeIssues]
|
||||||
|
f"daily_challenge:{input_date}",
|
||||||
|
mapping={
|
||||||
|
"beatmap": beatmap.id,
|
||||||
|
"ruleset_id": ruleset_id,
|
||||||
|
"required_mods": json.dumps(required_mods),
|
||||||
|
"allowed_mods": json.dumps(allowed_mods),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
asyncio.run(main())
|
||||||
Reference in New Issue
Block a user