From 5ff882a8d5d1ca37a1b6092f15325fefbfde0a49 Mon Sep 17 00:00:00 2001 From: wowlikon Date: Sat, 20 Sep 2025 23:00:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BF=D0=B0=D1=82=D1=87=D0=B5=D0=B9?= =?UTF-8?q?,=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=A1=D0=BF=D0=B8=D1=81=D0=BE=D0=BA=20=D0=BF=D0=B0?= =?UTF-8?q?=D1=82=D1=87=D0=B5=D0=B9:=20=20=20settings=5Furls:=20=E2=9C=94?= =?UTF-8?q?=20enabled=20=20=20disable=5Fad:=20=E2=9C=94=20enabled=20=20=20?= =?UTF-8?q?disable=5Fbeta=5Fbanner:=20=E2=9C=94=20enabled=20=20=20insert?= =?UTF-8?q?=5Fnew:=20=E2=9C=94=20enabled=20=20=20color=5Ftheme:=20?= =?UTF-8?q?=E2=9C=94=20enabled=20=20=20change=5Fserver:=20=E2=9C=98=20disa?= =?UTF-8?q?bled=20=20=20package=5Fname:=20=E2=9C=94=20enabled=20=20=20repl?= =?UTF-8?q?ace=5Fnavbar:=20=E2=9C=94=20enabled=20=20=20compress:=20?= =?UTF-8?q?=E2=9C=94=20enabled,=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BE=D0=BF=D0=B8=D1=81=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 2 +- patches/change_server.py | 13 ++++++++++- patches/color_theme.py | 8 +++++-- patches/compress.md | 30 ------------------------- patches/compress.py | 29 +++++++++++++++++++++++- patches/disable_ad.py | 26 +++++++++++++--------- patches/disable_beta_banner.py | 12 ++++++++-- patches/insert_new.py | 12 +++++++--- patches/package_name.py | 6 ++++- patches/replace_navbar.py | 7 +++++- patches/settings_urls.py | 6 ++++- patches/todo_application_icon.py | 6 ----- patches/todo_custom_speed.py | 7 +++++- patches/todo_example.py | 38 ++++++++++++++++++++++++++++++++ 14 files changed, 142 insertions(+), 60 deletions(-) delete mode 100644 patches/compress.md delete mode 100644 patches/todo_application_icon.py create mode 100644 patches/todo_example.py diff --git a/main.py b/main.py index 6cfa7b5..3155c3a 100644 --- a/main.py +++ b/main.py @@ -118,7 +118,7 @@ def info(patch_name: str = ""): """Вывод информации о патче""" conf = load_config().model_dump() if patch_name: - patch = Patch(patch_name, __import__(f"patcher.patches.{patch_name}")) + patch = Patch(patch_name, __import__(f"patches.{patch_name}", fromlist=[''])) console.print(f"[green]Информация о патче {patch.name}:") console.print(f" [yellow]Приоритет: {patch.priority}") console.print(f" [yellow]Описание: {patch.module.__doc__}") diff --git a/patches/change_server.py b/patches/change_server.py index 5202bd2..045ad2c 100644 --- a/patches/change_server.py +++ b/patches/change_server.py @@ -1,26 +1,33 @@ """ -Заменяет сервер api + Заменяет сервер api "change_server": { + "enabled": true, "server": "https://anixarty.wowlikon.tech/modding" } """ + priority = 0 +# imports import json import requests from tqdm import tqdm +# Patch def apply(config: dict) -> bool: response = requests.get(config['server']) assert response.status_code == 200, f"Failed to fetch data {response.status_code} {response.text}" + new_api = json.loads(response.text) for item in new_api['modifications']: tqdm.write(f"Изменение {item['file']}") filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/network/api/'+item['file'] + with open(filepath, 'r') as f: content = f.read() + with open(filepath, 'w') as f: if content.count(item['src']) == 0: tqdm.write(f"⚠ Не найдено {item['src']}") @@ -28,18 +35,22 @@ def apply(config: dict) -> bool: tqdm.write(f"Изменение Github ссылки") filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/utils/anixnet/GithubPagesNetFetcher.smali' + with open(filepath, 'r') as f: content = f.read() + with open(filepath, 'w') as f: f.write(content.replace('const-string v1, "https://anixhelper.github.io/pages/urls.json"', f'const-string v1, "{new_api["gh"]}"')) content = "" tqdm.write("Удаление динамического выбора сервера") filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/DaggerApp_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.smali' + with open(filepath, 'r') as f: for line in f.readlines(): if "addInterceptor" in line: continue content += line + with open(filepath, 'w') as f: f.write(content) diff --git a/patches/color_theme.py b/patches/color_theme.py index 8d95675..f763ccd 100644 --- a/patches/color_theme.py +++ b/patches/color_theme.py @@ -1,7 +1,8 @@ """ -Изменяет цветовую тему приложения и иконку + Изменяет цветовую тему приложения и иконку "color_theme": { + "enabled": true, "colors": { "primary": "#ccff00", "secondary": "#ffffd700", @@ -15,10 +16,11 @@ } } """ + priority = 0 +# imports from lxml import etree - from utils.public import ( insert_after_public, insert_after_color, @@ -26,6 +28,7 @@ from utils.public import ( ) +# Patch def apply(config: dict) -> bool: main_color = config["colors"]["primary"] splash_color = config["colors"]["secondary"] @@ -103,6 +106,7 @@ def apply(config: dict) -> bool: change_color("accent_alpha_20", main_color[0]+'33'+main_color[1:]) change_color("accent_alpha_50", main_color[0]+'80'+main_color[1:]) change_color("accent_alpha_70", main_color[0]+'b3'+main_color[1:]) + change_color("colorAccent", main_color[0]+'ff'+main_color[1:]) change_color("link_color", main_color[0]+'ff'+main_color[1:]) change_color("link_color_alpha_70", main_color[0]+'b3'+main_color[1:]) diff --git a/patches/compress.md b/patches/compress.md deleted file mode 100644 index ca2bf88..0000000 --- a/patches/compress.md +++ /dev/null @@ -1,30 +0,0 @@ -# Compress - -Патч удаляет ненужные ресурсы что-бы уменьшить размер АПК - -## настройки (compress в config.json) - -- remove_unknown_files: true/false - удаляет файлы из директории decompiled/unknown -- remove_unknown_files_keep_dirs: list[str] - оставляет указанные директории в decompiled/unknown -- remove_debug_lines: true/false - удаляет строки `.line n` из декомпилированных smali файлов использованные для дебага -- remove_AI_voiceover: true/false - заменяет ИИ озвучку маскота аниксы пустыми mp3 файлами -- compress_png_files: true/false - сжимает PNG в директории decompiled/res -- remove_drawable_files: true/false - удаляет неиспользованные drawable-* из директории decompiled/res -- remove_language_files: true/false - удаляет все языки кроме русского и английского - -## efficiency - -Проверено с версией 9.0 Beta 7 - -разница = оригинальный размер апк - патченный размер апк, не учитывая другие патчи - -| Настройка | Размер файла | Разница | % | -| :----------- | :-------------------: | :-----------------: | :-: | -| None | 17092 bytes - 17.1 MB | - | - | -| Compress PNG | 17072 bytes - 17.1 MB | 20 bytes - 0.0 MB | 0.11% | -| Remove files | 17020 bytes - 17.0 MB | 72 bytes - 0.1 MB | 0.42% | -| Remove draws | 16940 bytes - 16.9 MB | 152 bytes - 0.2 MB | 0.89% | -| Remove lines | 16444 bytes - 16.4 MB | 648 bytes - 0.7 MB | 3.79% | -| Remove ai vo | 15812 bytes - 15.8 MB | 1280 bytes - 1.3 MB | 7.49% | -| Remove langs | 15764 bytes - 15.7 MB | 1328 bytes - 1.3 MB | 7.76% | -| Все включены | 13592 bytes - 13.6 MB | 3500 bytes - 4.8 MB | 20.5% | diff --git a/patches/compress.py b/patches/compress.py index 8fd6fac..8711ef3 100644 --- a/patches/compress.py +++ b/patches/compress.py @@ -1,4 +1,31 @@ -"""Remove and compress resources""" +""" + Удаляет ненужное и сжимает ресурсы что-бы уменьшить размер АПК + +Эффективность на проверена на версии 9.0 Beta 7 +разница = оригинальный размер апк - патченный размер апк, не учитывая другие патчи + +| Настройка | Размер файла | Разница | % | +| :----------- | :-------------------: | :-----------------: | :-: | +| None | 17092 bytes - 17.1 MB | - | - | +| Compress PNG | 17072 bytes - 17.1 MB | 20 bytes - 0.0 MB | 0.11% | +| Remove files | 17020 bytes - 17.0 MB | 72 bytes - 0.1 MB | 0.42% | +| Remove draws | 16940 bytes - 16.9 MB | 152 bytes - 0.2 MB | 0.89% | +| Remove lines | 16444 bytes - 16.4 MB | 648 bytes - 0.7 MB | 3.79% | +| Remove ai vo | 15812 bytes - 15.8 MB | 1280 bytes - 1.3 MB | 7.49% | +| Remove langs | 15764 bytes - 15.7 MB | 1328 bytes - 1.3 MB | 7.76% | +| Все включены | 13592 bytes - 13.6 MB | 3500 bytes - 4.8 MB | 20.5% | + +"compress": { + "enabled": true, + "remove_language_files": true, // удаляет все языки кроме русского и английского + "remove_AI_voiceover": true, // заменяет ИИ озвучку маскота аниксы пустыми mp3 файлами + "remove_debug_lines": false, // удаляет строки `.line n` из smali файлов использованные для дебага + "remove_drawable_files": false, // удаляет неиспользованные drawable-* из директории decompiled/res + "remove_unknown_files": true, // удаляет файлы из директории decompiled/unknown + "remove_unknown_files_keep_dirs": ["META-INF", "kotlin"], // оставляет указанные директории в decompiled/unknown + "compress_png_files": true // сжимает PNG в директории decompiled/res +} +""" priority = -1 diff --git a/patches/disable_ad.py b/patches/disable_ad.py index 9457487..14cee1b 100644 --- a/patches/disable_ad.py +++ b/patches/disable_ad.py @@ -1,8 +1,15 @@ """ -Удаляет баннеры рекламы + Удаляет баннеры рекламы + +"disable_ad": { + "enabled": true +} """ + priority = 0 +# imports +import textwrap from utils.smali_parser import ( find_smali_method_end, find_smali_method_start, @@ -11,15 +18,14 @@ from utils.smali_parser import ( ) -replace = """ .locals 0 - - const/4 p0, 0x1 - - return p0 -""" - - +# Patch def apply(config) -> bool: + replacement = textwrap.dedent("""\ + .locals 0 + const/4 p0, 0x1 + return p0 + """).splitlines() + path = "./decompiled/smali_classes2/com/swiftsoft/anixartd/Prefs.smali" lines = get_smali_lines(path) for index, line in enumerate(lines): @@ -27,7 +33,7 @@ def apply(config) -> bool: 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 + lines, method_start, method_end, replacement ) with open(path, "w", encoding="utf-8") as file: diff --git a/patches/disable_beta_banner.py b/patches/disable_beta_banner.py index 6655099..6c3205f 100644 --- a/patches/disable_beta_banner.py +++ b/patches/disable_beta_banner.py @@ -1,13 +1,20 @@ """ -Удаляет баннеры бета-версии + Удаляет баннеры бета-версии + +"disable_beta_banner": { + "enabled": true +} """ + priority = 0 +# imports import os from tqdm import tqdm from lxml import etree +# Patch def apply(config) -> bool: attributes = [ "paddingTop", @@ -29,7 +36,8 @@ def apply(config) -> bool: root = tree.getroot() for attr in attributes: - # tqdm.write(f"set {attr} = 0.0dip") + if config["verbose"]: + tqdm.write(f"set {attr} = 0.0dip") root.set(f"{{{config["xml_ns"]['android']}}}{attr}", "0.0dip") tree.write( diff --git a/patches/insert_new.py b/patches/insert_new.py index 400d3b7..0a430ea 100644 --- a/patches/insert_new.py +++ b/patches/insert_new.py @@ -1,14 +1,20 @@ """ -Вставляет новые файлы в проект + Вставляет новые файлы в проект + +"insert_new": { + "enabled": true +} """ + priority = 0 -import shutil +# imports import os - +import shutil from utils.public import insert_after_public +# Patch def apply(config: dict) -> bool: # Mod first launch window shutil.copytree( diff --git a/patches/package_name.py b/patches/package_name.py index 6bb14f3..1922cc0 100644 --- a/patches/package_name.py +++ b/patches/package_name.py @@ -1,16 +1,20 @@ """ -Изменяет имя пакета в apk, удаляет вход по google и vk + Изменяет имя пакета в apk, удаляет вход по google и vk "package_name": { + "enabled": true, "new_package_name": "com.wowlikon.anixart" } """ + priority = -1 +# imports import os from lxml import etree +# Patch def rename_dir(src, dst): os.makedirs(os.path.dirname(dst), exist_ok=True) os.rename(src, dst) diff --git a/patches/replace_navbar.py b/patches/replace_navbar.py index aa0c068..9a8f14f 100644 --- a/patches/replace_navbar.py +++ b/patches/replace_navbar.py @@ -1,15 +1,20 @@ """ -Меняет порядок вкладок в панели навигации + Меняет порядок вкладок в панели навигации "replace_navbar": { + "enabled": true, "items": ["home", "discover", "feed", "bookmarks", "profile"] } """ + priority = 0 +# imports from lxml import etree from tqdm import tqdm + +# Patch def apply(config: dict) -> bool: file_path = "./decompiled/res/menu/bottom.xml" diff --git a/patches/settings_urls.py b/patches/settings_urls.py index 153a3c9..6a5de96 100644 --- a/patches/settings_urls.py +++ b/patches/settings_urls.py @@ -1,7 +1,8 @@ """ -Добавляет в настройки ссылки и доавляет текст к версии приложения + Добавляет в настройки ссылки и добвляет текст к версии приложения "settings_urls": { + "enabled": true, "menu": { "Раздел": [ { @@ -19,11 +20,14 @@ "version": " by wowlikon" } """ + priority = 0 +# imports from lxml import etree +# Patch def make_category(ns, name, items): cat = etree.Element("PreferenceCategory", nsmap=ns) cat.set(f"{{{ns['android']}}}title", name) diff --git a/patches/todo_application_icon.py b/patches/todo_application_icon.py deleted file mode 100644 index 64a567f..0000000 --- a/patches/todo_application_icon.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Change application icon""" -priority = 0 - - -def apply(config: dict) -> bool: - return False diff --git a/patches/todo_custom_speed.py b/patches/todo_custom_speed.py index 5350a3d..7bd9ece 100644 --- a/patches/todo_custom_speed.py +++ b/patches/todo_custom_speed.py @@ -1,18 +1,23 @@ """ -Добавляет пользовательские скорости воспроизведения видео + Добавляет пользовательские скорости воспроизведения видео "custom_speed": { + "enabled": true, "speeds": [9.0] } """ + priority = 0 +# imports from utils.smali_parser import float_to_hex from utils.public import ( insert_after_public, insert_after_id, ) + +# Patch def apply(config: dict) -> bool: assert float_to_hex(1.5) == "0x3fc00000" diff --git a/patches/todo_example.py b/patches/todo_example.py new file mode 100644 index 0000000..dcc659d --- /dev/null +++ b/patches/todo_example.py @@ -0,0 +1,38 @@ +""" + Шаблон патча + +Здесь вы можете добавить описание патча, его назначение и другие детали. + +Каждый патч должен независеть от других патчей и проверять себя при применении. Он не должен вернуть True, если есть проблемы. +На данный момент каждый патч должен иметь функцию `apply`, которая принимает на вход конфигурацию и возвращает True или False. +При успешном применении патча, функция apply должна вернуть True, иначе False. +Ошибка будет интерпретирована как False. С выводом ошибки в консоль. +Ещё патч должен иметь переменную `priority`, которая указывает приоритет патча, чем выше, тем раньше он будет применен. + +Коротко о конфигурации. Она получается из `config.json` из config["patches"][patch_name]. +Дополнительно в основном методе `apply` кроме этого есть "verbose" и содержимое "base". +Эти поля передаются всем патчам. `verbose` может быть указан так-же как флаг запуска: +``` +python ./main.py build --verbose +``` + +В конце файла должно быть описание конфигурации патча. +Это может быть как короткий фрагмент из названия патча и одной опции "enabled", которая обрабатывается в коде патчера. + +"todo_template": { + "enabled": true // Пример описания тк этот текст просто пример +} +""" + +priority = 0 # Приоритет патча, чем выше, тем раньше он будет применен + +# imports +from tqdm import tqdm + + +# Patch +def apply(config: dict) -> bool: # Анотации типов для удобства, читаемости и поддержки IDE + tqdm.write("Вывод информации через tqdm, чтобы не мешать прогресс-бару") + if config["verbose"]: + tqdm.write("Для вывода подробной и отладочной информации используйте флаг --verbose") + return True