231 lines
6.1 KiB
Python
231 lines
6.1 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from dataclasses import field
|
|
|
|
import xmltodict
|
|
|
|
|
|
@dataclass
|
|
class DRSSheetDataZetaraku:
|
|
type: str
|
|
difficulty: str
|
|
level: str
|
|
levelValue: int
|
|
|
|
|
|
@dataclass
|
|
class DRSSongDataZetaraku:
|
|
songId: str
|
|
category: str
|
|
title: str
|
|
artist: str
|
|
bpm: int
|
|
imageName: str
|
|
version: str | None = None
|
|
releaseDate: str | None = None
|
|
isNew: bool | None = None
|
|
isLocked: bool = False
|
|
sheets: list[DRSSheetDataZetaraku] = field(default_factory=list)
|
|
|
|
@classmethod
|
|
def from_dict(cls, data_dict):
|
|
sheets_data = data_dict.get('sheets') or []
|
|
sheets = [DRSSheetDataZetaraku(**sheet) for sheet in sheets_data]
|
|
return cls(**{**data_dict, 'sheets': sheets})
|
|
|
|
|
|
@dataclass
|
|
class DRSSongInfo:
|
|
artist_name: str
|
|
artist_yomigana: str
|
|
genre: int
|
|
title_name: str
|
|
title_yomigana: str
|
|
bpm_max: int
|
|
bpm_min: int
|
|
distribution_date: int
|
|
license: str
|
|
region: str
|
|
volume: int
|
|
|
|
|
|
@dataclass
|
|
class DRSSongDifficulty:
|
|
track: DRSTrack
|
|
difnum: int | None = None
|
|
|
|
|
|
@dataclass
|
|
class DRSSongDifficulties:
|
|
difficulty_1a: DRSSongDifficulty | None = None
|
|
difficulty_1b: DRSSongDifficulty | None = None
|
|
difficulty_2a: DRSSongDifficulty | None = None
|
|
difficulty_2b: DRSSongDifficulty | None = None
|
|
|
|
|
|
@dataclass
|
|
class DRSSongData:
|
|
song_id: int
|
|
difficulties: DRSSongDifficulties | None = None
|
|
info: DRSSongInfo | None = None
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict, difficulties: DRSSongDifficulties) -> DRSSongData:
|
|
return cls(
|
|
song_id=int(data['@id']),
|
|
difficulties=difficulties,
|
|
info=DRSSongInfo(
|
|
artist_name=data['info']['artist_name'].get('#text'),
|
|
artist_yomigana=data['info']['artist_yomigana'].get('#text'),
|
|
genre=int(data['info']['genre']['#text']),
|
|
title_name=data['info']['title_name']['#text'],
|
|
title_yomigana=data['info']['title_yomigana']['#text'],
|
|
bpm_max=int(data['info']['bpm_max']['#text']),
|
|
bpm_min=int(data['info']['bpm_min']['#text']),
|
|
distribution_date=int(
|
|
data['info']['distribution_date']['#text'],
|
|
),
|
|
license=data['info']['license'].get('#text'),
|
|
region=data['info']['region']['#text'],
|
|
volume=int(data['info']['volume']['#text']),
|
|
),
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackBPMInfo:
|
|
bpm: int
|
|
tick: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackMeasureInfo:
|
|
denomi: int
|
|
num: int
|
|
tick: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackTimeInfo:
|
|
time_unit: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackInfo:
|
|
end_tick: int
|
|
time_unit: DRSTrackTimeInfo
|
|
bpm_info: list[DRSTrackBPMInfo] = field(default_factory=list)
|
|
measure_info: list[DRSTrackMeasureInfo] = field(default_factory=list)
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict):
|
|
if type(data['measure_info']['measure']) is list:
|
|
drs_track_measure_info = [
|
|
DRSTrackMeasureInfo(
|
|
int(measure['denomi']['#text']),
|
|
int(measure['num']['#text']),
|
|
int(measure['tick']['#text']),
|
|
) for measure in data['measure_info']['measure']
|
|
]
|
|
else:
|
|
drs_track_measure_info = [
|
|
DRSTrackMeasureInfo(
|
|
int(data['measure_info']['measure']['denomi']['#text']),
|
|
int(data['measure_info']['measure']['num']['#text']),
|
|
int(data['measure_info']['measure']['tick']['#text']),
|
|
),
|
|
]
|
|
|
|
if type(data['bpm_info']['bpm']) is list:
|
|
drs_track_bpm_info = [
|
|
DRSTrackBPMInfo(
|
|
int(bpm['bpm']['#text']),
|
|
int(bpm['tick']['#text']),
|
|
) for bpm in data['bpm_info']['bpm']
|
|
]
|
|
else:
|
|
drs_track_bpm_info = [
|
|
DRSTrackBPMInfo(
|
|
int(data['bpm_info']['bpm']['bpm']['#text']),
|
|
int(data['bpm_info']['bpm']['tick']['#text']),
|
|
),
|
|
]
|
|
|
|
return cls(
|
|
end_tick=int(data['end_tick']['#text']),
|
|
time_unit=DRSTrackTimeInfo(int(data['time_unit']['#text'])),
|
|
bpm_info=drs_track_bpm_info,
|
|
measure_info=drs_track_measure_info,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackStepTickInfo:
|
|
start_tick: int
|
|
end_tick: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackStepPositionInfo:
|
|
left_pos: int
|
|
right_pos: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackStepPlayerInfo:
|
|
player_id: int
|
|
|
|
|
|
@dataclass
|
|
class DRSTrackStep:
|
|
tick_info: DRSTrackStepTickInfo
|
|
kind: int
|
|
position_info: DRSTrackStepPositionInfo
|
|
long_point: bool | None
|
|
player_info: DRSTrackStepPlayerInfo
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict):
|
|
return cls(
|
|
DRSTrackStepTickInfo(
|
|
int(data['start_tick']['#text']), int(
|
|
data['end_tick']['#text'],
|
|
),
|
|
),
|
|
int(data['kind']['#text']),
|
|
DRSTrackStepPositionInfo(
|
|
int(data['left_pos']['#text']), int(
|
|
data['right_pos']['#text'],
|
|
),
|
|
),
|
|
bool(data.get('long_point')), # Optional field
|
|
DRSTrackStepPlayerInfo(int(data['player_id']['#text'])),
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class DRSTrack:
|
|
seq_version: int
|
|
info: DRSTrackInfo
|
|
sequence_data: list[DRSTrackStep] = field(default_factory=list)
|
|
extend_data = None # TODO: Implement this ???
|
|
rec_data = None # TODO: Implement this ???
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: dict):
|
|
data = data['data']
|
|
return cls(
|
|
int(data['seq_version']['#text']),
|
|
DRSTrackInfo.from_dict(data['info']),
|
|
[
|
|
DRSTrackStep.from_dict(step)
|
|
for step in data['sequence_data']['step']
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
def from_xml(cls, path: str):
|
|
data = open(path, encoding='utf-8').read()
|
|
return cls.from_dict(xmltodict.parse(data))
|