diff --git a/src/arcaea_offline/external/__init__.py b/src/arcaea_offline/external/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/arcaea_offline/external/scores/__init__.py b/src/arcaea_offline/external/scores/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/arcaea_offline/external/scores/common.py b/src/arcaea_offline/external/scores/common.py new file mode 100644 index 0000000..bea5ff0 --- /dev/null +++ b/src/arcaea_offline/external/scores/common.py @@ -0,0 +1,20 @@ +import dataclasses +from typing import List + + +@dataclasses.dataclass +class ExternalScoreItem: + song_id: str + rating_class: int + score: int + pure: int = -1 + far: int = -1 + lost: int = -1 + max_recall: int = -1 + clear_type: int = -1 + time: int = -1 + + +class ExternalScoreSource: + def get_score_items(self) -> List[ExternalScoreItem]: + ... diff --git a/src/arcaea_offline/external.py b/src/arcaea_offline/external/scores/st3.py similarity index 80% rename from src/arcaea_offline/external.py rename to src/arcaea_offline/external/scores/st3.py index 9cc1c90..a17d889 100644 --- a/src/arcaea_offline/external.py +++ b/src/arcaea_offline/external/scores/st3.py @@ -1,24 +1,7 @@ -import dataclasses import sqlite3 -from typing import List, Union +from typing import Union - -@dataclasses.dataclass -class ExternalScoreItem: - song_id: str - rating_class: int - score: int - pure: int = -1 - far: int = -1 - lost: int = -1 - max_recall: int = -1 - clear_type: int = -1 - time: int = -1 - - -class ExternalScoreSource: - def get_score_items(self) -> List[ExternalScoreItem]: - ... +from .common import ExternalScoreItem, ExternalScoreSource class St3ScoreSource(ExternalScoreSource): diff --git a/src/arcaea_offline/init_sqls.py b/src/arcaea_offline/init_sqls.py deleted file mode 100644 index d69540b..0000000 --- a/src/arcaea_offline/init_sqls.py +++ /dev/null @@ -1,148 +0,0 @@ -from typing import Dict, List, TypedDict - - -class VersionSqls(TypedDict): - init: List[str] - update: List[str] - - -INIT_SQLS: Dict[int, VersionSqls] = { - 1: { - "init": [ - # region CREATE - """ - CREATE TABLE IF NOT EXISTS charts ( - song_id TEXT NOT NULL, - rating_class INTEGER NOT NULL, - name_en TEXT NOT NULL, - name_jp TEXT, - artist TEXT NOT NULL, - bpm TEXT NOT NULL, - bpm_base REAL NOT NULL, - package_id TEXT NOT NULL, - time INTEGER, - side INTEGER NOT NULL, - world_unlock BOOLEAN NOT NULL, - remote_download BOOLEAN, - bg TEXT NOT NULL, - date INTEGER NOT NULL, - version TEXT NOT NULL, - difficulty INTEGER NOT NULL, - rating INTEGER NOT NULL, - note INTEGER NOT NULL, - chart_designer TEXT, - jacket_designer TEXT, - jacket_override BOOLEAN NOT NULL, - audio_override BOOLEAN NOT NULL, - - PRIMARY KEY (song_id, rating_class) - ) - """, - """ - CREATE TABLE IF NOT EXISTS aliases ( - song_id TEXT NOT NULL, - alias TEXT NOT NULL - ) - """, - """ - CREATE TABLE IF NOT EXISTS packages ( - package_id TEXT NOT NULL, - name TEXT NOT NULL - ) - """, - """ - CREATE TABLE IF NOT EXISTS scores ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - song_id TEXT NOT NULL, - rating_class INTEGER NOT NULL, - score INTEGER NOT NULL, - pure INTEGER, - far INTEGER, - lost INTEGER, - time INTEGER NOT NULL, - max_recall INTEGER, - clear_type INTEGER, - - FOREIGN KEY (song_id, rating_class) REFERENCES charts(song_id, rating_class) ON UPDATE CASCADE ON DELETE NO ACTION - ) - """, - """ - CREATE TABLE IF NOT EXISTS properties ( - key TEXT NOT NULL UNIQUE, - value TEXT NOT NULL - ) - """, - """ - CREATE VIEW IF NOT EXISTS calculated AS - SELECT - scores.id, - scores.song_id, - scores.rating_class, - scores.score, - scores.pure, - scores.far, - scores.lost, - scores.time, - charts.rating, - charts.note, - score - FLOOR(( pure * 10000000.0 / note ) + ( far * 0.5 * 10000000.0 / note )) AS pure_small, - CASE - WHEN score >= 10000000 THEN - rating / 10.0 + 2 - WHEN score >= 9800000 THEN - rating / 10.0 + 1 + ( score - 9800000 ) / 200000.0 - ELSE MAX(( rating / 10.0 ) + ( score - 9500000 ) / 300000.0, 0) - END AS potential - FROM - scores - LEFT JOIN charts ON scores.rating_class = charts.rating_class - AND scores.song_id = charts.song_id - GROUP BY - scores.id - """, - """ - CREATE VIEW IF NOT EXISTS bests AS - SELECT - c.song_id, - c.rating_class, - MAX(c.potential) AS potential - FROM - calculated c - GROUP BY - c.song_id, - c.rating_class - ORDER BY - potential DESC - """, - """ - CREATE VIEW IF NOT EXISTS calculated_potential AS - SELECT - AVG(b30_ptt) AS b30 - FROM - ( SELECT potential AS b30_ptt FROM bests ORDER BY potential DESC LIMIT 30 ) - """, - """ - CREATE VIEW IF NOT EXISTS song_id_names AS - SELECT song_id, name - FROM ( - SELECT song_id, alias AS name FROM aliases - UNION ALL - SELECT song_id, song_id AS name FROM charts - UNION ALL - SELECT song_id, name_en AS name FROM charts - UNION ALL - SELECT song_id, name_jp AS name FROM charts - ) AS subquery - WHERE name IS NOT NULL AND name <> '' - GROUP BY song_id, name - """, - # endregion - # region INSERT - """ - INSERT INTO properties VALUES ('db_version', '1') - """ - # endregion - ], - "update": [], - } -} diff --git a/src/arcaea_offline/utils/__init__.py b/src/arcaea_offline/utils/__init__.py deleted file mode 100644 index a63aa70..0000000 --- a/src/arcaea_offline/utils/__init__.py +++ /dev/null @@ -1,52 +0,0 @@ -from typing import Any, Optional, Sequence - -RATING_CLASS_TEXT_MAP = { - 0: "Past", - 1: "Present", - 2: "Future", - 3: "Beyond", -} - -RATING_CLASS_SHORT_TEXT_MAP = { - 0: "PST", - 1: "PRS", - 2: "FTR", - 3: "BYD", -} - - -def rating_class_to_text(rating_class: int) -> Optional[str]: - return RATING_CLASS_TEXT_MAP.get(rating_class) - - -def rating_class_to_short_text(rating_class: int) -> Optional[str]: - return RATING_CLASS_SHORT_TEXT_MAP.get(rating_class) - - -SCORE_GRADE_FLOOR = [9900000, 9800000, 9500000, 9200000, 8900000, 8600000, 0] -SCORE_GRADE_TEXTS = ["EX+", "EX", "AA", "A", "B", "C", "D"] - - -def zip_score_grade(score: int, __seq: Sequence, default: Any = "__PRESERVE__"): - """ - zip_score_grade is a simple wrapper that equals to: - ```py - for score_floor, val in zip(SCORE_GRADE_FLOOR, __seq): - if score >= score_floor: - return val - return seq[-1] if default == "__PRESERVE__" else default - ``` - Could be useful in specific cases. - """ - return next( - ( - val - for score_floor, val in zip(SCORE_GRADE_FLOOR, __seq) - if score >= score_floor - ), - __seq[-1] if default == "__PRESERVE__" else default, - ) - - -def score_to_grade_text(score: int) -> str: - return zip_score_grade(score, SCORE_GRADE_TEXTS) diff --git a/src/arcaea_offline/utils/singleton.py b/src/arcaea_offline/utils/singleton.py deleted file mode 100644 index 6776678..0000000 --- a/src/arcaea_offline/utils/singleton.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Generic, TypeVar - -T = TypeVar("T") - - -class Singleton(type, Generic[T]): - _instance = None - - def __call__(cls, *args, **kwargs) -> T: - if cls._instance is None: - cls._instance = super().__call__(*args, **kwargs) - return cls._instance diff --git a/src/arcaea_offline/utils/types.py b/src/arcaea_offline/utils/types.py deleted file mode 100644 index ef27e08..0000000 --- a/src/arcaea_offline/utils/types.py +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Any, ClassVar, Dict, Protocol - - -class TDataclass(Protocol): - __dataclass_fields__: ClassVar[Dict] - - def __call__(self, *args: Any, **kwds: Any) -> Any: - ...