""" Copyright (C) 2025 283375 This file is part of "arcaea-apk-assets" (stated as "this program" below). This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ from __future__ import annotations import abc import dataclasses import re from typing import ClassVar __all__ = [ "ArcaeaApkAsset", "ArcaeaApkAssetJacket", "ArcaeaApkAssetList", "ArcaeaApkAssetPartnerIcon", ] @dataclasses.dataclass class ArcaeaApkAsset(metaclass=abc.ABCMeta): PATTERN: ClassVar[re.Pattern] zip_filename: str @classmethod def _get_match(cls, string: str) -> re.Match | None: return cls.PATTERN.match(string) @classmethod @abc.abstractmethod def from_zip_filename( cls, asset_zip_filename: str, ) -> ArcaeaApkAsset | None: ... @dataclasses.dataclass class ArcaeaApkAssetJacket(ArcaeaApkAsset): PATTERN = re.compile( r"^assets/songs/(?P.*)/(1080_)?(?P\d|base)(_(?P.*))?\.(jpg|png)", ) song_id: str rating_class: str | None lang: str | None @classmethod def from_zip_filename(cls, asset_zip_filename: str) -> ArcaeaApkAssetJacket | None: match = cls._get_match(asset_zip_filename) if match is None: return None return cls( zip_filename=asset_zip_filename, song_id=match.group("raw_song_id").replace("dl_", ""), rating_class=( None if match.group("raw_rating_class") == "base" else match.group("raw_rating_class") ), lang=match.group("lang"), ) @dataclasses.dataclass class ArcaeaApkAssetPartnerIcon(ArcaeaApkAsset): PATTERN = re.compile(r"^assets/char/(?P\d+u?)_icon\.(jpg|png)") char_id: str @classmethod def from_zip_filename( cls, asset_zip_filename: str, ) -> ArcaeaApkAssetPartnerIcon | None: match = cls._get_match(asset_zip_filename) if match is None: return None return cls( zip_filename=asset_zip_filename, char_id=match.group("char_id"), ) @dataclasses.dataclass class ArcaeaApkAssetList(ArcaeaApkAsset): PATTERN = re.compile(r"^assets/songs/(?P(pack|song)list|unlocks)") filename: str @classmethod def from_zip_filename(cls, asset_zip_filename: str) -> ArcaeaApkAssetList | None: match = cls._get_match(asset_zip_filename) if match is None: return None return cls( zip_filename=asset_zip_filename, filename=match.group("filename"), )