diff --git a/main.py b/main.py index cb3a102..2b12d95 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,13 @@ from scripts.download_tools import check_and_download_all_tools from scripts.select_apk import get_apks, select_apk from scripts.select_patches import apply_patches, get_patches, select_patches -from scripts.utils import check_java_version, compile_apk, decompile_apk, sign_apk, init_patch +from scripts.utils import ( + check_java_version, + compile_apk, + decompile_apk, + sign_apk, + init_patch, +) from config import args, config, log, console from time import time @@ -10,9 +16,19 @@ import yaml def patch(): + app_version: str = None + app_build: str = None + + with open( + f"{config['folders']['decompiled']}/apktool.yml", "r", encoding="utf-8" + ) as f: + data = yaml.load(f.read(), Loader=yaml.Loader) + app_version = data.get("versionInfo").get("versionName", "None") + app_build = data.get("versionInfo").get("versionCode", 0) + patches = get_patches() patches = select_patches(patches) - statuses = apply_patches(patches) + statuses = apply_patches(patches, app_version, int(app_build)) statuses_ok = [] statuses_err = [] diff --git a/patches/add_settings_menu_items.config.json b/patches/add_settings_menu_items.config.json new file mode 100644 index 0000000..3c8312d --- /dev/null +++ b/patches/add_settings_menu_items.config.json @@ -0,0 +1,3 @@ +{ + "add_patch_info": true +} \ No newline at end of file diff --git a/patches/add_settings_menu_items.py b/patches/add_settings_menu_items.py new file mode 100644 index 0000000..af990b1 --- /dev/null +++ b/patches/add_settings_menu_items.py @@ -0,0 +1,136 @@ +"""Adds a patch and other infos to app settings""" + +# patch settings +# priority, default: -95 +priority = -95 + +# imports +## bundled +import os +import random +import string +from typing import TypedDict + +## installed +from lxml import etree + +## custom +from config import config, log + + +# Patch +class PatchConfig_AddSettingsMenuItems(TypedDict): + _internal_all_patch_statuses: list + add_patch_info: bool + + +def random_key(): + return "".join(random.choices(string.ascii_letters, k=8)) + + +def add_separator(): + ns = config["xml_ns"] + item = etree.Element("Preference", nsmap=ns) + item.set(f"{{{ns['android']}}}layout", "@layout/preference_separator") + item.set(f"{{{ns['android']}}}selectable", "false") + item.set(f"{{{ns['android']}}}key", f"separator_{random_key()}") + + +def create_intent( + action: str = "android.intent.action.VIEW", + data: str | None = None, +): + ns = config["xml_ns"] + item = etree.Element("intent", nsmap=ns) + item.set(f"{{{ns['android']}}}action", action) + item.set(f"{{{ns['android']}}}data", data or "") + item.set(f"{{{ns['app']}}}iconSpaceReserved", "false") + item.set(f"{{{ns['android']}}}key", f"intent_{random_key()}") + return item + + +def create_Preference( + title: str, + description: str | None = None, + icon: str | None = None, + icon_space_reserved: bool = False, +): + ns = config["xml_ns"] + item = etree.Element("Preference", nsmap=ns) + item.set(f"{{{ns['android']}}}title", title) + item.set(f"{{{ns['android']}}}summary", description or "") + if icon: + item.set(f"{{{ns['app']}}}icon", icon) + item.set(f"{{{ns['app']}}}iconSpaceReserved", str(icon_space_reserved).lower()) + item.set(f"{{{ns['android']}}}key", f"preference_{random_key()}") + return item + + +def create_PreferenceCategory(title: str): + ns = config["xml_ns"] + category = etree.Element("PreferenceCategory", nsmap=ns) + category.set(f"{{{ns['android']}}}title", title) + category.set(f"{{{ns['app']}}}iconSpaceReserved", "false") + category.set(f"{{{ns['android']}}}key", f"category_{random_key()}") + return category + + +def add_patch_info(patch_statuses: list): + category = create_PreferenceCategory("Использованные патчи") + for patch in patch_statuses: + if patch["status"] is True: + description = [] + url = None + if os.path.exists(f"{config['folders']['patches']}/{patch['name']}.py"): + with open( + f"{config['folders']['patches']}/{patch['name']}.py", + "r", + encoding="utf-8", + ) as f: + line = f.readline() + if line.startswith('"""'): + description.append(line.strip().removeprefix('"""').removesuffix('"""').strip()) + line = f.readline() + if line.startswith("# Developer:"): + description.append("by") + description.append(line.strip().removeprefix("# Developer:").strip()) + line = f.readline() + if line.startswith("# URL:"): + url = line.strip().removeprefix("# URL:").strip() + + item = create_Preference(patch["name"].replace("_", " ").strip().title(), description=" ".join(description)) + if url: + item.append(create_intent(data = url)) + category.append(item) + return category + + +def apply(patch_conf: PatchConfig_AddSettingsMenuItems) -> bool: + preference_main_xml = ( + f"{config['folders']['decompiled']}/res/xml/preference_main.xml" + ) + preference_additional_xml = ( + f"{config['folders']['decompiled']}/res/xml/preference_additional.xml" + ) + + parser = etree.XMLParser(remove_blank_text=True) + + if os.path.exists(preference_additional_xml): + tree = etree.parse(preference_additional_xml, parser) + root = tree.getroot() + + if patch_conf["add_patch_info"]: + root.append(add_patch_info(patch_conf["_internal_all_patch_statuses"])) + + tree.write( + preference_additional_xml, + pretty_print=True, + xml_declaration=True, + encoding="utf-8", + ) + + return True + + +if __name__ == "__main__": + apply({}) diff --git a/scripts/select_patches.py b/scripts/select_patches.py index 2c44a79..06a90c0 100644 --- a/scripts/select_patches.py +++ b/scripts/select_patches.py @@ -69,7 +69,29 @@ progress = Progress( ) -def apply_patches(patches: list[str]) -> list[PatchStatus]: +def get_patch_config( + patch_name: str, + all_patch_statuses: list, + app_version: str, + app_build: int, +) -> dict: + _config = {} + if os.path.exists(f"{config['folders']['patches']}/{patch_name}.config.json"): + with open( + f"{config['folders']['patches']}/{patch_name}.config.json", + "r", + encoding="utf-8", + ) as f: + _config = json.loads(f.read()) + _config["_internal_all_patch_statuses"] = all_patch_statuses + _config["_internal_app_version"] = app_version + _config["_internal_app_build"] = app_build + return _config + + +def apply_patches( + patches: list[str], app_version: str, app_build: int +) -> list[PatchStatus]: modules = [] statuses = [] @@ -84,19 +106,7 @@ def apply_patches(patches: list[str]) -> list[PatchStatus]: task = progress.add_task("applying patch:", total=len(modules), patch="") for module in modules: progress.update(task, patch=module.name) - - patch_conf = {} - if os.path.exists( - f"{config['folders']['patches']}/{module.name}.config.json" - ): - with open( - f"{config['folders']['patches']}/{module.name}.config.json", - "r", - encoding="utf-8", - ) as f: - patch_conf = json.loads(f.read()) - - status = module.apply(patch_conf) + status = module.apply(get_patch_config(module.name, statuses, app_version, app_build)) statuses.append({"name": module.name, "status": status}) progress.update(task, advance=1) diff --git a/scripts/utils.py b/scripts/utils.py index 310e5d4..1214a1f 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -137,10 +137,14 @@ def init_patch(): f.write("") name = prompt("Patch name: ", lambda x: x.strip().lower().replace(" ", "_")) - description = prompt("Patch description: ", lambda x: x.strip()) + summary = prompt("Patch summary: ", lambda x: x.strip()) + developer = prompt("Patch developer: ", lambda x: x.strip()) + URL = prompt("URL: ", lambda x: x.strip()) priority = prompt("Patch priority: ", target_type=int, initial_value="0") - patch_content = f"""\"\"\"{description}\"\"\" + patch_content = f"""\"\"\"{summary}\"\"\" +# Developer: {developer} +# URL: {URL} # patch settings # priority, default: {priority}