Skip to content

Commit

Permalink
refactor: arcsong database importer & arcsong json exporter
Browse files Browse the repository at this point in the history
  • Loading branch information
283375 committed Sep 30, 2024
1 parent d270636 commit b062bbd
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 194 deletions.
3 changes: 0 additions & 3 deletions src/arcaea_offline/external/arcsong/__init__.py

This file was deleted.

34 changes: 0 additions & 34 deletions src/arcaea_offline/external/arcsong/arcsong_db.py

This file was deleted.

157 changes: 0 additions & 157 deletions src/arcaea_offline/external/arcsong/arcsong_json.py

This file was deleted.

3 changes: 3 additions & 0 deletions src/arcaea_offline/external/exporters/arcsong/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .json import ArcsongJsonExporter

__all__ = ["ArcsongJsonExporter"]
35 changes: 35 additions & 0 deletions src/arcaea_offline/external/exporters/arcsong/definitions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import List, TypedDict


class ArcsongJsonDifficultyItem(TypedDict):
name_en: str
name_jp: str
artist: str
bpm: str
bpm_base: float
set: str
set_friendly: str
time: int
side: int
world_unlock: bool
remote_download: bool
bg: str
date: int
version: str
difficulty: int
rating: int
note: int
chart_designer: str
jacket_designer: str
jacket_override: bool
audio_override: bool


class ArcsongJsonSongItem(TypedDict):
song_id: str
difficulties: List[ArcsongJsonDifficultyItem]
alias: List[str]


class ArcsongJsonRoot(TypedDict):
songs: List[ArcsongJsonSongItem]
98 changes: 98 additions & 0 deletions src/arcaea_offline/external/exporters/arcsong/json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import logging
import re
from typing import List, Optional

from sqlalchemy import select
from sqlalchemy.orm import Session

from arcaea_offline.constants.enums.arcaea import ArcaeaLanguage
from arcaea_offline.database.models.v5 import Difficulty, Pack, Song

from .definitions import ArcsongJsonDifficultyItem, ArcsongJsonRoot, ArcsongJsonSongItem

logger = logging.getLogger(__name__)


class ArcsongJsonExporter:
@staticmethod
def craft_difficulty_item(
difficulty: Difficulty, *, base_pack: Optional[Pack]
) -> ArcsongJsonDifficultyItem:
song = difficulty.song
pack = song.pack
chart_info = difficulty.chart_info

song_localized_ja = next(
(lo for lo in song.localized_objects if lo.lang == ArcaeaLanguage.JA),
None,
)
difficulty_localized_ja = next(
(lo for lo in difficulty.localized_objects if lo.lang == ArcaeaLanguage.JA),
None,
)

if difficulty_localized_ja:
name_jp = difficulty_localized_ja.title or ""
elif song_localized_ja:
name_jp = song_localized_ja.title or ""
else:
name_jp = ""

return {
"name_en": difficulty.title or song.title,
"name_jp": name_jp,
"artist": difficulty.artist or song.artist,
"bpm": difficulty.bpm or song.bpm or "",
"bpm_base": difficulty.bpm_base or song.bpm_base or 0.0,
"set": song.pack_id,
"set_friendly": f"{base_pack.name} - {pack.name}"
if base_pack
else pack.name,
"time": 0,
"side": song.side or 0,
"world_unlock": False,
"remote_download": False,
"bg": difficulty.bg or song.bg or "",
"date": difficulty.date or song.date or 0,
"version": difficulty.version or song.version or "",
"difficulty": difficulty.rating * 2 + int(difficulty.rating_plus),
"rating": chart_info.constant or 0 if chart_info else 0,
"note": chart_info.notes or 0 if chart_info else 0,
"chart_designer": difficulty.chart_designer or "",
"jacket_designer": difficulty.jacket_desginer or "",
"jacket_override": difficulty.jacket_override,
"audio_override": difficulty.audio_override,
}

@classmethod
def craft(cls, session: Session) -> ArcsongJsonRoot:
songs = session.scalars(select(Song))

arcsong_songs: List[ArcsongJsonSongItem] = []
for song in songs:
if len(song.difficulties) == 0:
continue

pack = song.pack
if "_append_" in pack.id:
base_pack = session.scalar(
select(Pack).where(Pack.id == re.sub(r"_append_.*$", "", pack.id))
)
else:
base_pack = None

arcsong_difficulties = []
for difficulty in song.difficulties:
arcsong_difficulties.append(
cls.craft_difficulty_item(difficulty, base_pack=base_pack)
)

arcsong_songs.append(
{
"song_id": song.id,
"difficulties": arcsong_difficulties,
"alias": [],
}
)

return {"songs": arcsong_songs}
38 changes: 38 additions & 0 deletions src/arcaea_offline/external/importers/arcsong.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import sqlite3
from typing import List, overload

from arcaea_offline.constants.enums.arcaea import ArcaeaRatingClass
from arcaea_offline.database.models.v5 import ChartInfo


class ArcsongDatabaseImporter:
@classmethod
@overload
def parse(cls, conn: sqlite3.Connection) -> List[ChartInfo]: ...

@classmethod
@overload
def parse(cls, conn: sqlite3.Cursor) -> List[ChartInfo]: ...

@classmethod
def parse(cls, conn) -> List[ChartInfo]:
if isinstance(conn, sqlite3.Connection):
return cls.parse(conn.cursor())

assert isinstance(conn, sqlite3.Cursor)

results = []
db_results = conn.execute(
"SELECT song_id, rating_class, rating, note FROM charts"
)
for result in db_results:
results.append(
ChartInfo(
song_id=result[0],
rating_class=ArcaeaRatingClass(result[1]),
constant=result[2],
notes=result[3] or None,
)
)

return results
Loading

0 comments on commit b062bbd

Please sign in to comment.