diff --git a/sync/__version__.py b/sync/__version__.py index 8b37902..d486078 100644 --- a/sync/__version__.py +++ b/sync/__version__.py @@ -1,9 +1,9 @@ def get_version() -> str: - return "2.7.8" + return "2.8.8" def get_version_code() -> int: - return 278 + return 288 __all__ = [ diff --git a/sync/model/LocalModule.py b/sync/model/LocalModule.py index 411f5b6..9e2599d 100644 --- a/sync/model/LocalModule.py +++ b/sync/model/LocalModule.py @@ -1,5 +1,4 @@ import json - from zipfile import ZipFile from pathlib import Path @@ -10,6 +9,7 @@ from .ModuleNote import ModuleNote from .ModuleFeatures import ModuleFeatures +from .ModuleManager import ModuleManager from .RootSolutions import RootSolutions class LocalModule(AttrDict): @@ -45,12 +45,29 @@ class LocalModule(AttrDict): note: ModuleNote features: ModuleFeatures root: RootSolutions + manager: ModuleManager + + @classmethod + def clean_json(cls, data): + if isinstance(data, dict): + cleaned_dict = { + key: cls.clean_json(value) + for key, value in data.items() + if value not in (None, [], {}) + } + return {k: v for k, v in cleaned_dict.items() if v not in (None, [], {})} + elif isinstance(data, list): + cleaned_list = [cls.clean_json(item) for item in data] + return [item for item in cleaned_list if item not in (None, [], {})] + return data @classmethod def load(cls, file, track, config): cls._zipfile = ZipFile(file, "r") fields = cls.expected_fields() + cleaned_track = cls.clean_json(track) + try: if ("#MAGISK" not in cls.file_read("META-INF/com/google/android/updater-script")): raise @@ -61,7 +78,7 @@ def load(cls, file, track, config): raise MagiskModuleError(msg) try: - props = cls.file_read( "module.prop") + props = cls.file_read("module.prop") except BaseException as err: raise MagiskModuleError(err.args) @@ -80,15 +97,16 @@ def load(cls, file, track, config): local_module = LocalModule() for key in fields.keys(): - if config.allowedCategories and key == "categories" and track.get("categories"): - local_module[key] = JsonIO.filterArray(config.allowedCategories, track.get(key)) + if config.allowedCategories and key == "categories" and cleaned_track.get("categories"): + local_module[key] = JsonIO.filterArray(config.allowedCategories, cleaned_track.get(key)) else: - value = track.get(key) if track.get(key) is not None else obj.get(key) + value = cleaned_track.get(key) if cleaned_track.get(key) is not None else obj.get(key) if value is not None and value is not False: # Filter out None and False values local_module[key] = value try: raw_json = json.loads(cls.file_read("common/repo.json")) + raw_json = cls.clean_json(raw_json) # Clean the raw JSON data for item in raw_json.items(): key, value = item @@ -117,7 +135,8 @@ def load(cls, file, track, config): "sepolicy": cls.file_exist(f"sepolicy.rule"), "zygisk": cls.file_exist(f"zygisk/"), - + "action": cls.file_exist(f"action.sh") or cls.file_exist(f"common/action.sh"), + # KernelSU "webroot": cls.file_exist(f"webroot/index.html"), "post_mount": cls.file_exist(f"post-mount.sh") or cls.file_exist(f"common/post-mount.sh"), @@ -131,7 +150,7 @@ def load(cls, file, track, config): local_module.features = {k: v for k, v in features.items() if v is not None and v is not False} - return local_module + return cls.clean_json(local_module) @classmethod def file_exist(cls, name: str): diff --git a/sync/model/ModuleManager.py b/sync/model/ModuleManager.py new file mode 100644 index 0000000..cd46cb9 --- /dev/null +++ b/sync/model/ModuleManager.py @@ -0,0 +1,27 @@ +from .AttrDict import AttrDict + +class ModuleManagerSolution(AttrDict): + min: int + devices: list[str] + arch: list[str] + require: list[str] + + @classmethod + def expected_fields(cls, __type=True): + if __type: + return cls.__annotations__ + + return {k: v.__name__ for k, v in cls.__annotations__.items() if v is not None and v is not False} + +class ModuleManager(AttrDict): + magisk: ModuleManagerSolution + kernelsu: ModuleManagerSolution + apatch: ModuleManagerSolution + + @classmethod + def expected_fields(cls, __type=True): + if __type: + return cls.__annotations__ + + return {k: v.__name__ for k, v in cls.__annotations__.items() if v is not None and v is not False} + \ No newline at end of file diff --git a/sync/model/TrackJson.py b/sync/model/TrackJson.py index 7ccab93..644832f 100644 --- a/sync/model/TrackJson.py +++ b/sync/model/TrackJson.py @@ -4,6 +4,9 @@ from .JsonIO import JsonIO from .ModuleNote import ModuleNote +from .ModuleFeatures import ModuleFeatures +from .ModuleManager import ModuleManager +from .RootSolutions import RootSolutions class TrackJson(AttrDict, JsonIO): id: str @@ -17,18 +20,31 @@ class TrackJson(AttrDict, JsonIO): support: str donate: str max_num: int - # author: str - # contributors: list[str] - cover: str - icon:str - screenshots: list[str] - require: list[str] + + # FoxMMM supported props + maxApi: int + minApi: int + + # MMRL supported props category: str categories: list[str] + icon: str + homepage: str + donate: str + support: str + cover: str + screenshots: list[str] + license: str + screenshots: list[str] readme: str require: list[str] - antifeatures: list[str] + verified: bool note: ModuleNote + features: ModuleFeatures + root: RootSolutions + manager: ModuleManager + + antifeatures: list[str] # noinspection PyAttributeOutsideInit @property