Files
arcaea-apk-assets/arcaea_apk_assets/parsers/packlist.py
2025-07-06 18:43:00 +08:00

180 lines
5.3 KiB
Python

"""
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 <https://www.gnu.org/licenses/>.
"""
from __future__ import annotations
import logging
from arcaea_offline_schemas.dis.v5.dataclass import AodisPack, AodisPackLocalization
from typeguard import TypeCheckError, check_type
from ._shared import blank_str_to_none
from .defs import ARCAEA_LANGUAGE_KEYS
logger = logging.getLogger(__name__)
class PacklistFormatError(Exception):
pass
class ArcaeaPacklistParser:
@staticmethod
def check_root_content(root: dict) -> None:
try:
check_type(root, dict)
check_type(root["packs"], list[dict])
except (KeyError, TypeCheckError) as e:
raise PacklistFormatError from e
@staticmethod
def check_pack_object(obj: dict) -> None:
try:
check_type(obj, dict)
check_type(obj["id"], str)
except (KeyError, TypeCheckError) as e:
raise PacklistFormatError from e
@staticmethod
def parse_pack(pack: dict) -> AodisPack:
id_ = pack["id"]
name_localized = pack.get("name_localized", {})
description_localized = pack.get("description_localized", {})
name = blank_str_to_none(name_localized.get("en"))
description = blank_str_to_none(description_localized.get("en"))
section = blank_str_to_none(pack.get("section"))
append_parent_id = pack.get("pack_parent")
plus_character = (
pack["plus_character"] if pack.get("plus_character", -1) > -1 else None
)
return AodisPack(
id=id_,
name=name or "",
isWorldExtend=pack.get("is_extend_pack") is True,
description=description,
section=section,
unlocksPartner=plus_character,
appendParentId=append_parent_id,
)
@staticmethod
def parse_pack_localizations(pack: dict) -> list[AodisPackLocalization]:
results = []
name_localized = pack.get("name_localized", {})
description_localized = pack.get("description_localized", {})
id_ = pack["id"]
for lang_key in ARCAEA_LANGUAGE_KEYS:
name_l10n = blank_str_to_none(name_localized.get(lang_key))
description_l10n = blank_str_to_none(
description_localized.get(lang_key),
)
if name_l10n or description_l10n:
results.append(
AodisPackLocalization(
id=id_,
lang=lang_key,
name=name_l10n,
description=description_l10n,
),
)
return results
@classmethod
def items(
cls,
packlist_content: dict,
*,
skip_format_checks: bool = False,
) -> list[AodisPack | AodisPackLocalization]:
try:
cls.check_root_content(packlist_content)
except PacklistFormatError:
if skip_format_checks:
logger.exception("Error skipped during packlist parsing:")
return []
raise
packs = packlist_content["packs"]
results: list[AodisPack | AodisPackLocalization] = [
AodisPack(
id="single",
name="Memory Archive",
isWorldExtend=False,
description=None,
section=None,
unlocksPartner=None,
appendParentId=None,
),
]
for pack in packs:
try:
cls.check_pack_object(pack)
except PacklistFormatError:
if skip_format_checks:
logger.exception("Error skipped during packlist parsing:")
continue
raise
results.append(cls.parse_pack(pack))
results.extend(cls.parse_pack_localizations(pack))
return results
@classmethod
def packs(
cls,
packlist_content: dict,
*,
skip_format_checks: bool = False,
) -> list[AodisPack]:
return [
item
for item in cls.items(
packlist_content,
skip_format_checks=skip_format_checks,
)
if isinstance(item, AodisPack)
]
@classmethod
def pack_localizations(
cls,
packlist_content: dict,
*,
skip_format_checks: bool = False,
) -> list[AodisPackLocalization]:
return [
item
for item in cls.items(
packlist_content,
skip_format_checks=skip_format_checks,
)
if isinstance(item, AodisPackLocalization)
]