""" 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 . """ import logging from typing import Any from ._shared import blank_str_to_none from .defs import ARCAEA_LANGUAGE_KEYS, Pack, PackLocalization logger = logging.getLogger(__name__) class PacklistFormatError(Exception): pass class ArcaeaPacklistParser: @staticmethod def _assert_root_content(root: Any): if not isinstance(root, dict): msg = f"packlist root should be `dict`, got {type(root)}" raise PacklistFormatError(msg) packs = root.get("packs") if packs is None: msg = "`packs` field does not exist" raise PacklistFormatError(msg) if not isinstance(packs, list): msg = f"`packs` field should be `list`, got {type(packs)}" raise PacklistFormatError(msg) @staticmethod def _assert_pack_object(obj: Any): if not isinstance(obj, dict): msg = f"A pack object should be `dict`, got {type(obj)}" raise PacklistFormatError(msg) id_ = obj.get("id") if not isinstance(id_, str): msg = f"`id` attribute of a pack should be `str`, got value {id_!r}" raise PacklistFormatError(msg) @classmethod def items( cls, packlist_content: dict, *, skip_asserts: bool = False ) -> list[Pack | PackLocalization]: try: cls._assert_root_content(packlist_content) except PacklistFormatError as e: if skip_asserts: logger.exception("Error skipped during packlist parsing:") return [] raise e packs = packlist_content["packs"] results: list[Pack | PackLocalization] = [ Pack( id="single", name="Memory Archive", description=None, section=None, plus_character=None, append_parent_id=None, ) ] for pack in packs: try: cls._assert_pack_object(pack) except PacklistFormatError as e: if skip_asserts: logger.exception("Error skipped during packlist parsing:") continue raise e name_localized = pack.get("name_localized", {}) description_localized = pack.get("description_localized", {}) id_ = pack["id"] 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 ) results.append( Pack( id=id_, name=name, description=description, section=section, plus_character=plus_character, append_parent_id=append_parent_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( PackLocalization( id=id_, lang=lang_key, name=name_l10n, description=description_l10n, ) ) return results @classmethod def packs(cls, packlist_content: dict, *, skip_asserts: bool = False) -> list[Pack]: return [ item for item in cls.items(packlist_content, skip_asserts=skip_asserts) if isinstance(item, Pack) ] @classmethod def pack_localizations( cls, packlist_content: dict, *, skip_asserts: bool = False ) -> list[PackLocalization]: return [ item for item in cls.items(packlist_content, skip_asserts=skip_asserts) if isinstance(item, PackLocalization) ]