diff --git a/.gitignore b/.gitignore index 09c0165..750dd16 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,4 @@ __pycache__ keystore.jks help dev_patches -dev.config.json -release_patches -release.config.json +dev.config.json \ No newline at end of file diff --git a/main.py b/main.py index 2b12d95..75e0efd 100644 --- a/main.py +++ b/main.py @@ -1,13 +1,7 @@ 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 @@ -16,19 +10,9 @@ 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, app_version, int(app_build)) + statuses = apply_patches(patches) statuses_ok = [] statuses_err = [] @@ -45,7 +29,7 @@ def patch(): if __name__ == "__main__": check_and_download_all_tools() check_java_version() - + if args.init: init_patch() exit(0) diff --git a/patches/add_settings_menu_items.config.json b/patches/add_settings_menu_items.config.json deleted file mode 100644 index e340672..0000000 --- a/patches/add_settings_menu_items.config.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "add_patch_info": true, - "main_settings_categories": [ - { - "title": "anixart-patcher", - "items": [ - { - "title": "Radiquum", - "summary": "Разработчик", - "url": "https://radiquum.wah.su/", - "icon": "@drawable/solar_code_2_bold", - "icon_space_reserved": false - }, - { - "title": "Репозиторий", - "summary": "https://github.com/Radiquum/anixart-patcher", - "url": "https://github.com/Radiquum/anixart-patcher", - "icon": "@drawable/github_mark", - "icon_space_reserved": false - } - ] - } - ] -} \ No newline at end of file diff --git a/patches/add_settings_menu_items.py b/patches/add_settings_menu_items.py deleted file mode 100644 index 8d2b0c5..0000000 --- a/patches/add_settings_menu_items.py +++ /dev/null @@ -1,210 +0,0 @@ -"""Adds used patches and custom menu items to app settings""" -# Developer: Radiquum -# URL: - -# patch settings -# priority, default: -95 -priority = -95 - -# imports -## bundled -import os -import shutil -import random -import string -from typing import TypedDict - -## installed -from lxml import etree - -## custom -from config import config, log - - -# Patch -class PatchConfig_AddSettingsMenuItemsCategoryItem(TypedDict): - title: str - summary: str | None - url: str | None - icon: str | None - icon_space_reserved: bool - - -class PatchConfig_AddSettingsMenuItemsCategory(TypedDict): - title: str - items: list[PatchConfig_AddSettingsMenuItemsCategoryItem] - - -class PatchConfig_AddSettingsMenuItems(TypedDict): - _internal_all_patch_statuses: list - add_patch_info: bool - main_settings_categories: list[PatchConfig_AddSettingsMenuItemsCategory] - - -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, - summary: 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", summary 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_icons(): - src_icon_path = f"{config["folders"]["patches"]}/resources/icons" - src_icon_night_path = f"{config["folders"]["patches"]}/resources/icons-night" - dst_icon_path = f"{config["folders"]["decompiled"]}/res/drawable" - dst_icon_night_path = f"{config["folders"]["decompiled"]}/res/drawable-night" - icons = os.listdir(src_icon_path) - if len(icons) == 0: - return - - for icon in icons: - shutil.copy(f"{src_icon_path}/{icon}", f"{dst_icon_path}/{icon}") - if os.path.exists(f"{src_icon_night_path}/{icon}"): - shutil.copy( - f"{src_icon_night_path}/{icon}", f"{dst_icon_night_path}/{icon}" - ) - - -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 add_custom_category( - title: str, items: list[PatchConfig_AddSettingsMenuItemsCategoryItem] -): - category = create_PreferenceCategory(title) - for item in items: - new_item = create_Preference( - item["title"], - item["summary"], - item["icon"], - item["icon_space_reserved"], - ) - if item["url"]: - new_item.append(create_intent(data=item["url"])) - category.append(new_item) - return category - - -def apply(patch_conf: PatchConfig_AddSettingsMenuItems) -> bool: - parser = etree.XMLParser(remove_blank_text=True) - preference_main_xml = ( - f"{config['folders']['decompiled']}/res/xml/preference_main.xml" - ) - preference_additional_xml = ( - f"{config['folders']['decompiled']}/res/xml/preference_additional.xml" - ) - - add_icons() - - if os.path.exists(preference_main_xml): - tree = etree.parse(preference_main_xml, parser) - root = tree.getroot() - - last = root[-1]; pos = root.index(last) - for item in patch_conf["main_settings_categories"]: - root.insert(pos, add_custom_category(item["title"], item["items"])); pos += 1 - - tree.write( - preference_main_xml, - pretty_print=True, - xml_declaration=True, - encoding="utf-8", - ) - - 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/patches/change_app_version.config.json b/patches/change_app_version.config.json deleted file mode 100644 index d2ddc6d..0000000 --- a/patches/change_app_version.config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "version_code": 25082901, - "version_name": "9.0 BETA 7" -} \ No newline at end of file diff --git a/patches/change_app_version.py b/patches/change_app_version.py deleted file mode 100644 index 1ba1049..0000000 --- a/patches/change_app_version.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Changes the version string and build number""" -# Developer: Radiquum - -# patch settings -# priority, default: -98 -priority = -98 - -# imports -## bundled -from typing import TypedDict - -## installed -import yaml - -## custom -from config import config, log - - -# Patch -class PatchConfig_ChangeAppVersion(TypedDict): - _internal_app_version: str - _internal_app_build: int - version_name: str - version_code: int - - -def apply(patch_conf: PatchConfig_ChangeAppVersion) -> bool: - apktool_yaml = None - with open( - f"{config['folders']['decompiled']}/apktool.yml", "r", encoding="utf-8" - ) as f: - apktool_yaml = yaml.load(f.read(), Loader=yaml.Loader) - - apktool_yaml.update( - { - "versionInfo": { - "versionName": patch_conf["version_name"] - or patch_conf["_internal_app_version"], - "versionCode": patch_conf["version_code"] - or patch_conf["_internal_app_build"], - } - } - ) - - with open( - f"{config['folders']['decompiled']}/apktool.yml", "w", encoding="utf-8" - ) as f: - apktool_yaml = yaml.dump(apktool_yaml, f, indent=2, Dumper=yaml.Dumper) - - return True diff --git a/patches/change_color_theme.py b/patches/change_color_theme.py index 57d060a..889e035 100644 --- a/patches/change_color_theme.py +++ b/patches/change_color_theme.py @@ -1,5 +1,4 @@ """Change app color theme""" -# Developer: Radiquum, themes based on code by Seele # patch settings # priority, default: -99 (run before last) @@ -29,14 +28,14 @@ class PatchConfig_ChangeColorTheme(TypedDict): def apply(patch_config: PatchConfig_ChangeColorTheme) -> bool: - + console.print("select color theme to apply (press [bold]enter[/bold] to confirm)") theme = select(patch_config["themes"], cursor="->", cursor_style="cyan") if not theme: console.print(f"theme: default") return False console.print(f"theme: {theme}") - + theme_attr = patch_config[theme]["attributes"] theme_text = patch_config[theme]["text"] theme_files = patch_config[theme]["files"] diff --git a/patches/change_navigation_bar.py b/patches/change_navigation_bar.py index d6fca80..0202cc0 100644 --- a/patches/change_navigation_bar.py +++ b/patches/change_navigation_bar.py @@ -1,5 +1,4 @@ """Move and replace navigation bar tabs""" -# Developer: Radiquum # patch settings # priority, default: 0 @@ -31,7 +30,7 @@ def modify_menu(menu: list[str], path: str) -> None: log.warning(f"menu item `{item}` is not allowed, removing from list") menu.remove(item) - root = etree.Element("menu", nsmap={"android": config["xml_ns"]["android"]}) + root = etree.Element("menu", nsmap={"android": config['xml_ns']['android']}) for item in menu: element = etree.SubElement(root, "item") element.set(f"{{{config['xml_ns']['android']}}}icon", f"@drawable/nav_{item}") @@ -48,11 +47,6 @@ def modify_menu(menu: list[str], path: str) -> None: def apply(patch_conf: PatchConfig_ChangeNavigationBar) -> bool: - modify_menu( - patch_conf["portrait"], f"{config['folders']['decompiled']}/res/menu/bottom.xml" - ) - modify_menu( - patch_conf["landscape"], - f"{config['folders']['decompiled']}/res/menu/navigation_rail_menu.xml", - ) + modify_menu(patch_conf["portrait"], f"{config['folders']['decompiled']}/res/menu/bottom.xml") + modify_menu(patch_conf["landscape"], f"{config['folders']['decompiled']}/res/menu/navigation_rail_menu.xml") return True diff --git a/patches/change_package_name.py b/patches/change_package_name.py index 671d698..daae8f9 100644 --- a/patches/change_package_name.py +++ b/patches/change_package_name.py @@ -1,6 +1,4 @@ """Change package name""" -# Developer: Radiquum, based of similar patch by wowlikon -# URL: # patch settings # priority, default: -100 (run last) diff --git a/patches/compress.py b/patches/compress.py index 22799d6..6b2c83f 100644 --- a/patches/compress.py +++ b/patches/compress.py @@ -1,6 +1,4 @@ """Remove and compress resources""" -# Developer: Radiquum, based of similar patch by wowlikon -# URL: https://github.com/Radiquum/anixart-patcher/blob/master/patches/compress.md # patch settings # priority, default: 0 diff --git a/patches/disable_ad.py b/patches/disable_ad.py index bc76040..6bac24e 100644 --- a/patches/disable_ad.py +++ b/patches/disable_ad.py @@ -1,6 +1,4 @@ """Disable ad banners""" -# Developer: Radiquum, based of code by seele -# URL: # patch settings # priority, default: 0 @@ -22,7 +20,7 @@ replace = """ .locals 0 const/4 p0, 0x1 - return p0 + return p0 """ diff --git a/patches/disable_beta_banner.py b/patches/disable_beta_banner.py index b4bcc9e..a8e02fc 100644 --- a/patches/disable_beta_banner.py +++ b/patches/disable_beta_banner.py @@ -1,6 +1,4 @@ """Remove beta banner""" -# Developer: Radiquum, based of code by ModdingApps -# URL: # patch settings # priority, default: 0 diff --git a/patches/force_static_request_urls.py b/patches/force_static_request_urls.py index 68e1a33..59f8a52 100644 --- a/patches/force_static_request_urls.py +++ b/patches/force_static_request_urls.py @@ -1,6 +1,4 @@ """Change `value="something/endpoint"` to `value="https://example.com/something/endpoint" """ -# Developer: Radiquum -# URL: # patch settings # priority, default: 0 @@ -17,6 +15,9 @@ from scripts.smali_parser import ( get_smali_lines, save_smali_lines, find_and_replace_smali_line, + find_smali_method_start, + find_smali_method_end, + replace_smali_method_body, ) @@ -38,13 +39,21 @@ class PatchConfig_ForceStaticRequestUrls(TypedDict): constants: PatchConfig_ForceStaticRequestUrlsConst +replace_should_use_mirror_urls = """ .locals 0 + + const/4 p0, 0x0 + + return p0 +""" + + def apply(patch_config: PatchConfig_ForceStaticRequestUrls) -> bool: for value in patch_config["values"]: if os.path.exists(f"{config['folders']['decompiled']}/{value['file_path']}"): path = f"{config['folders']['decompiled']}/{value['file_path']}" lines = get_smali_lines(path) lines = find_and_replace_smali_line( - lines, f'value = "{value['value']}"', f'value = "{patch_config['base_url']}{value['value']}"' + lines, value["value"], f"{patch_config['base_url']}{value['value']}" ) save_smali_lines(path, lines) log.debug(f"[FORCE_STATIC_REQUEST_URLS] file {path} has been modified") @@ -62,6 +71,21 @@ def apply(patch_config: PatchConfig_ForceStaticRequestUrls) -> bool: save_smali_lines(path, lines) log.debug(f"[FORCE_STATIC_REQUEST_URLS] file {path} has been modified") + # IDK If it is actually needed, will leave it for now, but seems like it should not be needed, since patch is working + # path = f"{config['folders']['decompiled']}/smali_classes2/com/swiftsoft/anixartd/Prefs.smali" + # if os.path.exists(path): + # lines = get_smali_lines(path) + # new_content = [] + # for index, line in enumerate(lines): + # if line.find("SHOULD_USE_MIRROR_URLS") >= 0: + # method_start = find_smali_method_start(lines, index) + # method_end = find_smali_method_end(lines, index) + # new_content = replace_smali_method_body( + # lines, method_start, method_end, replace_should_use_mirror_urls + # ) + # save_smali_lines(path, new_content) + # log.debug(f"[FORCE_STATIC_REQUEST_URLS] file {path} has been modified") + path = f"{config['folders']['decompiled']}/smali_classes2/com/swiftsoft/anixartd/DaggerApp_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.smali" pathInterceptor = f"{config['folders']['decompiled']}/smali_classes2/com/swiftsoft/anixartd/dagger/module/ApiModule$provideRetrofit$lambda$2$$inlined$-addInterceptor$1.smali" if os.path.exists(path) and os.path.exists(pathInterceptor): @@ -69,9 +93,10 @@ def apply(patch_config: PatchConfig_ForceStaticRequestUrls) -> bool: new_content = [] for index, line in enumerate(lines): if line.find("addInterceptor") >= 0: - continue + continue new_content.append(line) save_smali_lines(path, new_content) log.debug(f"[FORCE_STATIC_REQUEST_URLS] file {path} has been modified") + return True diff --git a/patches/resources/icons-night/github_mark.xml b/patches/resources/icons-night/github_mark.xml deleted file mode 100644 index 42c9d27..0000000 --- a/patches/resources/icons-night/github_mark.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/patches/resources/icons/github_mark.xml b/patches/resources/icons/github_mark.xml deleted file mode 100644 index ce12ac8..0000000 --- a/patches/resources/icons/github_mark.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/patches/resources/icons/solar_code_2_bold.xml b/patches/resources/icons/solar_code_2_bold.xml deleted file mode 100644 index 8f42ffc..0000000 --- a/patches/resources/icons/solar_code_2_bold.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/scripts/select_patches.py b/scripts/select_patches.py index 06a90c0..2c44a79 100644 --- a/scripts/select_patches.py +++ b/scripts/select_patches.py @@ -69,29 +69,7 @@ progress = Progress( ) -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]: +def apply_patches(patches: list[str]) -> list[PatchStatus]: modules = [] statuses = [] @@ -106,7 +84,19 @@ def apply_patches( task = progress.add_task("applying patch:", total=len(modules), patch="") for module in modules: progress.update(task, patch=module.name) - status = module.apply(get_patch_config(module.name, statuses, app_version, app_build)) + + 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) statuses.append({"name": module.name, "status": status}) progress.update(task, advance=1) diff --git a/scripts/utils.py b/scripts/utils.py index 1214a1f..310e5d4 100644 --- a/scripts/utils.py +++ b/scripts/utils.py @@ -137,14 +137,10 @@ def init_patch(): f.write("") name = prompt("Patch name: ", lambda x: x.strip().lower().replace(" ", "_")) - summary = prompt("Patch summary: ", lambda x: x.strip()) - developer = prompt("Patch developer: ", lambda x: x.strip()) - URL = prompt("URL: ", lambda x: x.strip()) + description = prompt("Patch description: ", lambda x: x.strip()) priority = prompt("Patch priority: ", target_type=int, initial_value="0") - patch_content = f"""\"\"\"{summary}\"\"\" -# Developer: {developer} -# URL: {URL} + patch_content = f"""\"\"\"{description}\"\"\" # patch settings # priority, default: {priority}