forked from anixart-mod/patcher
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec047cd3a5 | |||
| 2fe61c1445 | |||
| 28c60aa7a3 | |||
| b646dbf6fe | |||
| f46425b169 |
+20
-13
@@ -1,4 +1,4 @@
|
||||
name: Build mod
|
||||
name: Сборка мода
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -16,25 +16,25 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download APK
|
||||
- name: Скачивание APK
|
||||
run: |
|
||||
curl -L -o app.apk "https://mirror-dl.anixart-app.com/anixart-beta.apk"
|
||||
|
||||
- name: Ensure aapt is installed
|
||||
- name: Проверка наличия aapt
|
||||
run: |
|
||||
if ! command -v aapt &> /dev/null; then
|
||||
echo "aapt не найден, устанавливаем..."
|
||||
sudo apt-get update && sudo apt-get install -y --no-install-recommends android-sdk-build-tools
|
||||
fi
|
||||
|
||||
- name: Ensure pngquant is installed
|
||||
- name: Проверка наличия pngquant
|
||||
run: |
|
||||
if ! command -v pngquant &> /dev/null; then
|
||||
echo "pngquant не найден, устанавливаем..."
|
||||
sudo apt-get update && sudo apt-get install -y --no-install-recommends pngquant
|
||||
fi
|
||||
|
||||
- name: Export secrets
|
||||
- name: Извлечение хранилища ключей
|
||||
env:
|
||||
KEYSTORE: ${{ secrets.KEYSTORE }}
|
||||
KEYSTORE_PASS: ${{ secrets.KEYSTORE_PASS }}
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
echo "$KEYSTORE" | base64 -d > keystore.jks
|
||||
echo "$KEYSTORE_PASS" > keystore.pass
|
||||
|
||||
- name: Prepare to build APK
|
||||
- name: Подготовка к модифицированию APK
|
||||
id: build
|
||||
run: |
|
||||
mkdir original
|
||||
@@ -51,32 +51,39 @@ jobs:
|
||||
pip install -r ./requirements.txt --break-system-packages
|
||||
python ./main.py init
|
||||
|
||||
- name: Build APK
|
||||
- name: Пересборка APK
|
||||
id: build
|
||||
run: |
|
||||
python ./main.py build -f
|
||||
|
||||
- name: Read title from report.log
|
||||
- name: Чтение title из report.log
|
||||
id: get_title
|
||||
run: |
|
||||
TITLE=$(head -n 1 modified/report.log)
|
||||
tail -n +2 modified/report.log > modified/report.log.tmp
|
||||
echo "title=${TITLE}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup go
|
||||
- name: Чтение body из report.log
|
||||
id: get_body
|
||||
run: |
|
||||
BODY=$(tail -n +2 modified/report.log)
|
||||
echo "body<<EOF" >> $GITHUB_OUTPUT
|
||||
echo "$BODY" >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Установка go
|
||||
if: steps.build.outputs.BUILD_EXIT == '0'
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20'
|
||||
|
||||
- name: Make release
|
||||
- name: Создание релиза
|
||||
if: steps.build.outputs.BUILD_EXIT == '0'
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
title: ${{ steps.get_title.outputs.title }}
|
||||
body_path: modified/report.log.tmp
|
||||
body: ${{ steps.get_body.outputs.body }}
|
||||
draft: true
|
||||
api_key: '${{secrets.RELEASE_TOKEN}}'
|
||||
files: |-
|
||||
modified/**-mod.apk
|
||||
modified/*-mod.apk
|
||||
modified/report.log
|
||||
|
||||
@@ -76,6 +76,6 @@ flowchart TD
|
||||
Этот проект лицензирован под лицензией MIT. См. [LICENSE](./LICENSE) для получения подробной информации.
|
||||
|
||||
### Вклад в проект:
|
||||
- Kentai Radiquum - Значительный вклад в развитие патчера, разработка [anix](https://github.com/AniX-org/AniX) и помощь с API [[GitHub](https://github.com/adiquum) | [Telegram](https://t.me/radiquum)]
|
||||
- Seele - Оригинальные патчи в начале разработки основаны на модификации от Seele
|
||||
- ReCode Liner - Помощь в изучении моддинга приложения [[Telegram](https://t.me/recodius)]
|
||||
- [Kentai Radiquum](https://git.0x174.su/Radiquum) - Значительный вклад в развитие патчера, разработка [anix](https://github.com/AniX-org/AniX) и помощь с API [[GitHub](https://github.com/adiquum) | [Telegram](https://t.me/radiquum)]
|
||||
- [Seele](https://git.0x174.su/seele_archive) - Оригинальные патчи в начале разработки основаны на модификации от Seele
|
||||
- [ReCode Liner](https://git.0x174.su/ReCodeLiner) - Помощь в изучении моддинга приложения [[Telegram](https://t.me/recodius)]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"enabled":true,"replace":true,"custom_icons":true,"icon_size":"18.0dip"}
|
||||
@@ -1 +0,0 @@
|
||||
{"enabled":true}
|
||||
@@ -0,0 +1 @@
|
||||
{"enabled":true,"format":{"share_channel_text":"Канал: «%1$s»\n%2$schannel/%3$d","share_collection_text":"Коллекция: «%1$s»\n%2$scollection/%3$d","share_profile_text":"Профиль пользователя «%1$s»\n%2$sprofile/%3$d","share_release_text":"Релиз: «%1$s»\n%2$srelease/%3$d"}}
|
||||
@@ -0,0 +1 @@
|
||||
{"enabled":true,"title":"Anixarty","description":"Описание","link_text":"МЫ В TELEGRAM","link_url":"https://t.me/http_teapod","skip_text":"Пропустить","title_bg_color":"#FFFFFF"}
|
||||
@@ -13,7 +13,6 @@ from rich.prompt import Prompt
|
||||
from utils.config import *
|
||||
from utils.tools import *
|
||||
|
||||
# --- Paths ---
|
||||
|
||||
console = Console()
|
||||
app = typer.Typer()
|
||||
@@ -30,6 +29,7 @@ class Patch:
|
||||
self.config = module.Config.model_validate_json((CONFIGS / f"{name}.json").read_text())
|
||||
except Exception as e:
|
||||
console.print(f"[red]Ошибка при загрузке конфигурации патча {name}: {e}")
|
||||
console.print(f"[yellow]Используются значения по умолчанию")
|
||||
self.config = module.Config()
|
||||
|
||||
def apply(self, conf: Dict[str, Any]) -> bool:
|
||||
@@ -42,7 +42,7 @@ class Patch:
|
||||
return False
|
||||
|
||||
|
||||
# ======================= INIT =========================
|
||||
# ========================= INIT =========================
|
||||
@app.command()
|
||||
def init():
|
||||
"""Создание директорий и скачивание инструментов"""
|
||||
@@ -71,7 +71,7 @@ def init():
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
# ======================= INFO =========================
|
||||
# ========================= INFO =========================
|
||||
@app.command()
|
||||
def info(patch_name: str = ""):
|
||||
"""Вывод информации о патче"""
|
||||
@@ -81,18 +81,36 @@ def info(patch_name: str = ""):
|
||||
console.print(f"[green]Информация о патче {patch.name}:")
|
||||
console.print(f" [yellow]Приоритет: {patch.priority}")
|
||||
console.print(f" [yellow]Описание: {patch.module.__doc__}")
|
||||
|
||||
console.print(f"[blue]Поля конфигурации")
|
||||
for field_name, field_info in type(patch.config).model_fields.items():
|
||||
field_data = {
|
||||
'type': field_info.annotation.__name__,
|
||||
'description': field_info.description,
|
||||
'default': field_info.default,
|
||||
'json_schema_extra': field_info.json_schema_extra,
|
||||
}
|
||||
console.print(f'{field_name} {field_data}')
|
||||
console.print("\n[blue]" + "="*50 + "\n")
|
||||
|
||||
else:
|
||||
conf = load_config(console)
|
||||
console.print("[cyan]Список патчей:")
|
||||
patch_list = []
|
||||
for f in PATCHES.glob("*.py"):
|
||||
if f.name.startswith("todo_") or f.name == "__init__.py":
|
||||
if f.name == "__init__.py": continue
|
||||
if f.name.startswith("todo_"):
|
||||
try: priority = __import__(f"patches.{f.stem}.priority", fromlist=[""])
|
||||
except: priority = None
|
||||
patch_list.append((priority, f" [{priority}] [yellow]{f.stem}: [yellow]⚠ в разработке"))
|
||||
continue
|
||||
name = f.stem
|
||||
if conf["patches"].get(name, {}).get("enabled", True):
|
||||
console.print(f" [yellow]{name}: [green]✔ enabled")
|
||||
else:
|
||||
console.print(f" [yellow]{name}: [red]✘ disabled")
|
||||
patch = Patch(f.stem, __import__(f"patches.{f.stem}", fromlist=[""]))
|
||||
if patch.config.enabled: patch_list.append((patch.priority, f" [{patch.priority}] [yellow]{f.stem}: [green]✔ включен"))
|
||||
else: patch_list.append((patch.priority, f" [{patch.priority}] [yellow]{f.stem}: [red]✘ выключен"))
|
||||
for _, patch in sorted(patch_list, key=lambda x: (x[0] is None, x[0]), reverse=True): console.print(patch)
|
||||
|
||||
|
||||
# ========================= UTIL =========================
|
||||
def select_apk() -> Path:
|
||||
apks = [f for f in ORIGINAL.glob("*.apk")]
|
||||
if not apks:
|
||||
@@ -174,6 +192,7 @@ def compile(apk: Path, patches: List[Patch]):
|
||||
f.write(f"{'✔' if p.applied else '✘'} {p.name}\n")
|
||||
|
||||
|
||||
# ========================= BUILD =========================
|
||||
@app.command()
|
||||
def build(
|
||||
force: bool = typer.Option(False, "--force", "-f", help="Принудительная сборка"),
|
||||
@@ -219,5 +238,4 @@ def build(
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
if __name__ == "__main__": app()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Заменяет сервер api
|
||||
"""Заменяет сервер api
|
||||
|
||||
"change_server": {
|
||||
"enabled": true,
|
||||
@@ -24,11 +23,11 @@ class Config(PatchConfig):
|
||||
|
||||
# Patch
|
||||
def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
response = requests.get(config.server)
|
||||
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']:
|
||||
for item in new_api['modifications']: # Применяем замены API
|
||||
tqdm.write(f"Изменение {item['file']}")
|
||||
filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/network/api/'+item['file']
|
||||
|
||||
@@ -40,7 +39,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
tqdm.write(f"⚠ Не найдено {item['src']}")
|
||||
f.write(content.replace(item['src'], item['dst']))
|
||||
|
||||
tqdm.write(f"Изменение Github ссылки")
|
||||
tqdm.write(f"Изменение Github ссылки") # Обновление ссылки на поиск серверов в Github
|
||||
filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/utils/anixnet/GithubPagesNetFetcher.smali'
|
||||
|
||||
with open(filepath, 'r') as f:
|
||||
@@ -49,10 +48,10 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
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("Удаление динамического выбора сервера")
|
||||
tqdm.write("Удаление динамического выбора сервера") # Отключение автовыбора сервера
|
||||
filepath = './decompiled/smali_classes2/com/swiftsoft/anixartd/DaggerApp_HiltComponents_SingletonC$SingletonCImpl$SwitchingProvider.smali'
|
||||
|
||||
content = ""
|
||||
with open(filepath, 'r') as f:
|
||||
for line in f.readlines():
|
||||
if "addInterceptor" in line: continue
|
||||
|
||||
+12
-12
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Изменяет цветовую тему приложения и иконку
|
||||
"""Изменяет цветовую тему приложения и иконку
|
||||
|
||||
"color_theme": {
|
||||
"enabled": true,
|
||||
@@ -59,7 +58,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
main_color = config.colors.primary
|
||||
splash_color = config.colors.secondary
|
||||
|
||||
# No connection alert coolor
|
||||
# Обновление сообщения об отсутствии подключения
|
||||
with open("./decompiled/assets/no_connection.html", "r", encoding="utf-8") as file:
|
||||
file_contents = file.read()
|
||||
|
||||
@@ -68,33 +67,32 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
with open("./decompiled/assets/no_connection.html", "w", encoding="utf-8") as file:
|
||||
file.write(new_contents)
|
||||
|
||||
# For logo
|
||||
# Суффиксы лого
|
||||
drawable_types = ["", "-night"]
|
||||
|
||||
for drawable_type in drawable_types:
|
||||
# Application logo gradient colors
|
||||
# Градиент лого приложения
|
||||
file_path = f"./decompiled/res/drawable{drawable_type}/$logo__0.xml"
|
||||
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Change attributes with namespace
|
||||
# Замена атрибутов значениями из конфигурации
|
||||
root.set(f"{{{base['xml_ns']['android']}}}angle", str(config.logo.gradient.angle))
|
||||
root.set(f"{{{base['xml_ns']['android']}}}startColor", config.logo.gradient.start_color)
|
||||
root.set(f"{{{base['xml_ns']['android']}}}endColor", config.logo.gradient.end_color)
|
||||
|
||||
# Save back
|
||||
# Сохранение
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
# Application logo anim color
|
||||
# Замена анимации лого
|
||||
file_path = f"./decompiled/res/drawable{drawable_type}/$logo_splash_anim__0.xml"
|
||||
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Finding "path"
|
||||
for el in root.findall("path", namespaces=base["xml_ns"]):
|
||||
name = el.get(f"{{{base['xml_ns']['android']}}}name")
|
||||
if name == "path":
|
||||
@@ -102,7 +100,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
elif name in ["path_1", "path_2"]:
|
||||
el.set(f"{{{base['xml_ns']['android']}}}fillColor", config.logo.ears_color)
|
||||
|
||||
# Save back
|
||||
# Сохранение
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
for filename in ["$ic_launcher_foreground__0", "$ic_banner_foreground__0"]:
|
||||
@@ -112,21 +110,23 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Change attributes with namespace
|
||||
# Замена атрибутов значениями из конфигурации
|
||||
root.set(f"{{{base['xml_ns']['android']}}}angle", str(config.logo.gradient.angle))
|
||||
items = root.findall("item", namespaces=base['xml_ns'])
|
||||
assert len(items) == 2
|
||||
items[0].set(f"{{{base['xml_ns']['android']}}}color", config.logo.gradient.start_color)
|
||||
items[1].set(f"{{{base['xml_ns']['android']}}}color", config.logo.gradient.end_color)
|
||||
|
||||
# Save back
|
||||
# Сохранение
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
# Добаление новых цветов для темы
|
||||
insert_after_public("carmine", "custom_color")
|
||||
insert_after_public("carmine_alpha_10", "custom_color_alpha_10")
|
||||
insert_after_color("carmine", "custom_color", main_color[0]+'ff'+main_color[1:])
|
||||
insert_after_color("carmine_alpha_10", "custom_color_alpha_10", main_color[0]+'1a'+main_color[1:])
|
||||
|
||||
# Замена цветов
|
||||
change_color("accent_alpha_10", main_color[0]+'1a'+main_color[1:])
|
||||
change_color("accent_alpha_20", main_color[0]+'33'+main_color[1:])
|
||||
change_color("accent_alpha_50", main_color[0]+'80'+main_color[1:])
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Меняет местами кнопки лайка и дизлайка у коментария и иконки
|
||||
|
||||
"comment_vote": {
|
||||
"enabled": true,
|
||||
"replace": true,
|
||||
"custom_icons": true,
|
||||
"icons_size": "14.0dip"
|
||||
}
|
||||
"""
|
||||
|
||||
priority = 0
|
||||
|
||||
# imports
|
||||
import os
|
||||
import shutil
|
||||
from tqdm import tqdm
|
||||
from lxml import etree
|
||||
from pydantic import Field
|
||||
from typing import Dict, Any
|
||||
from utils.config import PatchConfig
|
||||
|
||||
#Config
|
||||
class Config(PatchConfig):
|
||||
replace: bool = Field(True, description="Менять местами лайк/дизлайк")
|
||||
custom_icons: bool = Field(True, description="Кастомные иконки")
|
||||
icon_size: str = Field("18.0dip", description="Размер иконки")
|
||||
|
||||
# Patch
|
||||
def apply(config, base: Dict[str, Any]) -> bool:
|
||||
file_path = "./decompiled/res/layout/item_comment.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
tqdm.write("Меняем размер иконок лайка и дизлайка...")
|
||||
for icon in root.xpath(
|
||||
".//*[@android:id='@id/votePlusInactive']//ImageView | "
|
||||
".//*[@android:id='@id/votePlusActive']//ImageView | "
|
||||
".//*[@android:id='@id/voteMinusInactive']//ImageView | "
|
||||
".//*[@android:id='@id/voteMinusActive']//ImageView",
|
||||
namespaces=base['xml_ns'],
|
||||
):
|
||||
icon.set(f"{{{base['xml_ns']['android']}}}layout_width", config.icon_size)
|
||||
# icon.set(f"{{{base['xml_ns']['android']}}}layout_height", config.icon_size)
|
||||
|
||||
if config.replace:
|
||||
tqdm.write("Меняем местами лайк и дизлайк комментария...")
|
||||
|
||||
containers = root.xpath(
|
||||
".//LinearLayout[.//*[@android:id='@id/voteMinus'] and .//*[@android:id='@id/votePlus']]",
|
||||
namespaces=base["xml_ns"],
|
||||
)
|
||||
|
||||
found = False
|
||||
for container in containers:
|
||||
children = list(container)
|
||||
vote_plus = None
|
||||
vote_minus = None
|
||||
|
||||
for ch in children:
|
||||
cid = ch.get(f'{{{base["xml_ns"]["android"]}}}id')
|
||||
if cid == "@id/votePlus":
|
||||
vote_plus = ch
|
||||
elif cid == "@id/voteMinus":
|
||||
vote_minus = ch
|
||||
|
||||
if vote_plus is not None and vote_minus is not None:
|
||||
found = True
|
||||
i_plus = children.index(vote_plus)
|
||||
i_minus = children.index(vote_minus)
|
||||
children[i_plus], children[i_minus] = children[i_minus], children[i_plus]
|
||||
container[:] = children
|
||||
tqdm.write("Кнопки лайк и дизлайк поменялись местами.")
|
||||
break
|
||||
|
||||
if not found:
|
||||
tqdm.write("Не удалось найти оба узла votePlus/voteMinus даже в общих LinearLayout.")
|
||||
|
||||
if config.custom_icons:
|
||||
tqdm.write("Заменяем иконки лайка и дизлайка на кастомные...")
|
||||
for suffix in ["up", "up_40", "down", "down_40"]:
|
||||
shutil.copy(
|
||||
f"./resources/ic_chevron_{suffix}.xml",
|
||||
f"./decompiled/res/drawable/ic_chevron_{suffix}.xml",
|
||||
)
|
||||
|
||||
for inactive in root.xpath(
|
||||
".//*[@android:id='@id/votePlusInactive'] | .//*[@android:id='@id/voteMinusInactive']",
|
||||
namespaces=base["xml_ns"],
|
||||
):
|
||||
for img in inactive.xpath(".//ImageView[@android:src]", namespaces=base["xml_ns"]):
|
||||
src = img.get(f'{{{base["xml_ns"]["android"]}}}src', "")
|
||||
if src.startswith("@drawable/") and not src.endswith("_40"):
|
||||
img.set(f'{{{base["xml_ns"]["android"]}}}src', src + "_40")
|
||||
|
||||
# Сохраняем
|
||||
tree.write(file_path, encoding="utf-8", xml_declaration=True, pretty_print=True)
|
||||
|
||||
return True
|
||||
+12
-13
@@ -1,19 +1,18 @@
|
||||
"""
|
||||
Удаляет ненужное и сжимает ресурсы что-бы уменьшить размер АПК
|
||||
"""Удаляет ненужное и сжимает ресурсы что-бы уменьшить размер АПК
|
||||
|
||||
Эффективность на проверена на версии 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% |
|
||||
| Настройка | Размер файла | Разница | % |
|
||||
| :--------------: | :-------------------: | :-----------------: | :-: |
|
||||
| Ничего | 17092 bytes - 17.1 MB | - | - |
|
||||
| Сжатие PNG | 17072 bytes - 17.1 MB | 20 bytes - 0.0 MB | 0.11% |
|
||||
| Удалить unknown | 17020 bytes - 17.0 MB | 72 bytes - 0.1 MB | 0.42% |
|
||||
| Удалить draws | 16940 bytes - 16.9 MB | 152 bytes - 0.2 MB | 0.89% |
|
||||
| Удалить lines | 16444 bytes - 16.4 MB | 648 bytes - 0.7 MB | 3.79% |
|
||||
| Удалить ai voice | 15812 bytes - 15.8 MB | 1280 bytes - 1.3 MB | 7.49% |
|
||||
| Удалить языки | 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,
|
||||
@@ -34,8 +33,8 @@ import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from tqdm import tqdm
|
||||
from typing import Dict, List, Any
|
||||
from pydantic import Field
|
||||
from typing import Dict, List, Any
|
||||
|
||||
from utils.config import PatchConfig
|
||||
from utils.smali_parser import get_smali_lines, save_smali_lines
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Удаляет баннеры рекламы
|
||||
"""Удаляет баннеры рекламы
|
||||
|
||||
"disable_ad": {
|
||||
"enabled": true
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Удаляет баннеры бета-версии
|
||||
"""Удаляет баннеры бета-версии
|
||||
|
||||
"disable_beta_banner": {
|
||||
"enabled": true
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
"""
|
||||
Вставляет новые файлы в проект
|
||||
|
||||
"insert_new": {
|
||||
"enabled": true
|
||||
}
|
||||
"""
|
||||
|
||||
priority = 0
|
||||
|
||||
# imports
|
||||
import os
|
||||
import shutil
|
||||
from typing import Dict, Any
|
||||
from utils.config import PatchConfig
|
||||
from utils.public import insert_after_public
|
||||
|
||||
|
||||
#Config
|
||||
class Config(PatchConfig): ...
|
||||
|
||||
# Patch
|
||||
def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
# Mod first launch window
|
||||
shutil.copy("./resources/avatar.png", "./decompiled/assets/avatar.png")
|
||||
shutil.copy(
|
||||
"./resources/OpenSans-Regular.ttf",
|
||||
"./decompiled/assets/OpenSans-Regular.ttf",
|
||||
)
|
||||
shutil.copytree(
|
||||
"./resources/smali_classes4/", "./decompiled/smali_classes4/"
|
||||
)
|
||||
|
||||
return True
|
||||
+10
-5
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Изменяет имя пакета в apk, удаляет вход по google и vk
|
||||
"""Изменяет имя пакета в apk, удаляет вход по google и vk
|
||||
|
||||
"package_name": {
|
||||
"enabled": true,
|
||||
@@ -11,8 +10,8 @@ priority = -1
|
||||
|
||||
# imports
|
||||
import os
|
||||
from lxml import etree
|
||||
from tqdm import tqdm
|
||||
from lxml import etree
|
||||
from typing import Dict, Any
|
||||
from pydantic import Field
|
||||
|
||||
@@ -34,7 +33,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
file_path = os.path.join(root, filename)
|
||||
|
||||
if os.path.isfile(file_path):
|
||||
try:
|
||||
try: # Изменяем имя пакета в файлах
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
file_contents = file.read()
|
||||
|
||||
@@ -44,12 +43,16 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
new_contents = new_contents.replace(
|
||||
"com/swiftsoft/anixartd",
|
||||
config.package_name.replace(".", "/"),
|
||||
).replace(
|
||||
"com/swiftsoft",
|
||||
"/".join(config.package_name.split(".")[:2]),
|
||||
)
|
||||
with open(file_path, "w", encoding="utf-8") as file:
|
||||
file.write(new_contents)
|
||||
except:
|
||||
pass
|
||||
|
||||
# Изменяем названия папок
|
||||
if os.path.exists("./decompiled/smali/com/swiftsoft/anixartd"):
|
||||
rename_dir(
|
||||
"./decompiled/smali/com/swiftsoft/anixartd",
|
||||
@@ -72,7 +75,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
os.path.join(
|
||||
"./decompiled",
|
||||
"smali_classes4",
|
||||
"/".join(config.package_name.split(".")[:-1]),
|
||||
"/".join(config.package_name.split(".")[:2]),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -85,6 +88,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
# ),
|
||||
# )
|
||||
|
||||
# Замена названия пакета для smali_classes4
|
||||
for root, dirs, files in os.walk("./decompiled/smali_classes4/"):
|
||||
for filename in files:
|
||||
file_path = os.path.join(root, filename)
|
||||
@@ -103,6 +107,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
except:
|
||||
pass
|
||||
|
||||
# Скрытие входа по Google и VK (НЕ РАБОТАЮТ В МОДАХ)
|
||||
file_path = "./decompiled/res/layout/fragment_sign_in.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
|
||||
@@ -29,6 +29,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Получение элементов панели навигации
|
||||
items = root.findall("item", namespaces=base['xml_ns'])
|
||||
|
||||
def get_id_suffix(item):
|
||||
@@ -38,11 +39,13 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
items_by_id = {get_id_suffix(item): item for item in items}
|
||||
existing_order = [get_id_suffix(item) for item in items]
|
||||
|
||||
# Размещение в новом порядке
|
||||
ordered_items = []
|
||||
for key in config.items:
|
||||
if key in items_by_id:
|
||||
ordered_items.append(items_by_id[key])
|
||||
|
||||
# Если есть не указанные в конфиге они помещаются в конец списка
|
||||
extra = [i for i in items if get_id_suffix(i) not in config.items]
|
||||
if extra:
|
||||
tqdm.write("⚠Найдены лишние элементы: " + str([get_id_suffix(i) for i in extra]))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Делает текст в описании аниме копируемым
|
||||
"""Делает текст в описании аниме копируемым
|
||||
|
||||
"selectable_text": {
|
||||
"enabled": true
|
||||
@@ -37,7 +36,7 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
if f"{{{base['xml_ns']['android']}}}textIsSelectable" not in element.attrib:
|
||||
element.set(f"{{{base['xml_ns']['android']}}}textIsSelectable", "true")
|
||||
|
||||
# Сохраняем обратно
|
||||
# Сохраняем
|
||||
tree.write(file_path, encoding="utf-8", xml_declaration=True, pretty_print=True)
|
||||
|
||||
return True
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Добавляет в настройки ссылки и добвляет текст к версии приложения
|
||||
"""Добавляет в настройки ссылки и добвляет текст к версии приложения
|
||||
|
||||
"settings_urls": {
|
||||
"enabled": true,
|
||||
@@ -61,7 +60,7 @@ DEFAULT_MENU = {
|
||||
"Прочее": [
|
||||
{
|
||||
"title": "Помочь проекту",
|
||||
"description": "Вы можете помочь нам в разработке мода, написании кода или тестировании.",
|
||||
"description": "Вы можете помочь нам с идеями, написанием кода или тестированием.",
|
||||
"url": "https://git.wowlikon.tech/anixart-mod",
|
||||
"icon": "@drawable/ic_custom_crown",
|
||||
"icon_space_reserved": "false"
|
||||
@@ -94,6 +93,7 @@ def make_category(ns, name, items):
|
||||
return cat
|
||||
|
||||
def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
# Добавление кастомных иконок
|
||||
shutil.copy(
|
||||
"./resources/ic_custom_crown.xml",
|
||||
"./decompiled/res/drawable/ic_custom_crown.xml",
|
||||
@@ -111,16 +111,16 @@ def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Insert new PreferenceCategory before the last element
|
||||
last = root[-1] # last element
|
||||
pos = root.index(last)
|
||||
# Вставка новых пунктов перед последним
|
||||
pos = root.index(root[-1])
|
||||
for section, items in config.menu.items():
|
||||
root.insert(pos, make_category(base["xml_ns"], section, items))
|
||||
pos += 1
|
||||
|
||||
# Save back
|
||||
# Сохранение
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
# Добавление суффикса версии
|
||||
filepaths = [
|
||||
"./decompiled/smali_classes2/com/swiftsoft/anixartd/ui/activity/UpdateActivity.smali",
|
||||
"./decompiled/smali_classes2/com/swiftsoft/anixartd/ui/fragment/main/preference/MainPreferenceFragment.smali",
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
"""Изменяет формат "поделиться"
|
||||
|
||||
"selectable_text": {
|
||||
"enabled": true,
|
||||
"format": {
|
||||
"share_channel_text": "Канал: «%1$s»\n%2$schannel/%3$d",
|
||||
"share_collection_text": "Коллекция: «%1$s»\n%2$scollection/%3$d",
|
||||
"share_profile_text": "Профиль пользователя «%1$s»\n%2$sprofile/%3$d",
|
||||
"share_release_text": "Релиз: «%1$s»\n%2$srelease/%3$d"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
priority = 0
|
||||
|
||||
# imports
|
||||
from tqdm import tqdm
|
||||
from lxml import etree
|
||||
from typing import Dict, Any
|
||||
from pydantic import Field
|
||||
|
||||
from utils.config import PatchConfig
|
||||
|
||||
#Config
|
||||
DEFAULT_FORMATS = {
|
||||
"share_channel_text": "Канал: «%1$s»\n%2$schannel/%3$d",
|
||||
"share_collection_text": "Коллекция: «%1$s»\n%2$scollection/%3$d",
|
||||
"share_profile_text": "Профиль пользователя «%1$s»\n%2$sprofile/%3$d",
|
||||
"share_release_text": "Релиз: «%1$s»\n%2$srelease/%3$d"
|
||||
}
|
||||
|
||||
class Config(PatchConfig):
|
||||
format: Dict[str, str] = Field(DEFAULT_FORMATS, description="Строки для замены в `strings.xml`")
|
||||
|
||||
# Patch
|
||||
def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
|
||||
file_path = "./decompiled/res/values/strings.xml"
|
||||
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
root = tree.getroot()
|
||||
|
||||
# Обновляем значения
|
||||
for string in root.findall("string"):
|
||||
name = string.get("name")
|
||||
if name in config.format:
|
||||
string.text = config.format[name]
|
||||
|
||||
# Сохраняем обратно
|
||||
tree.write(file_path, encoding="utf-8", xml_declaration=True, pretty_print=True)
|
||||
|
||||
return True
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Добавляет пользовательские скорости воспроизведения видео
|
||||
"""Добавляет пользовательские скорости воспроизведения видео
|
||||
|
||||
"custom_speed": {
|
||||
"enabled": true,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"""
|
||||
Шаблон патча
|
||||
"""Шаблон патча
|
||||
|
||||
Здесь вы можете добавить описание патча, его назначение и другие детали.
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
"""Добавляет всплывающее окно при первом входе
|
||||
|
||||
"welcome": {
|
||||
"enabled": true,
|
||||
"title": "Anixarty",
|
||||
"description": "Описание",
|
||||
"link_text": "МЫ В TELEGRAM",
|
||||
"link_url": "https://t.me/http_teapod",
|
||||
"skip_text": "Пропустить",
|
||||
"title_bg_color": "#FFFFFF"
|
||||
}
|
||||
"""
|
||||
|
||||
priority = 0
|
||||
|
||||
# imports
|
||||
import os
|
||||
import shutil
|
||||
from pydantic import Field
|
||||
from typing import Dict, Any
|
||||
from utils.config import PatchConfig
|
||||
from utils.smali_parser import (
|
||||
find_and_replace_smali_line,
|
||||
get_smali_lines,
|
||||
save_smali_lines
|
||||
)
|
||||
|
||||
#Config
|
||||
class Config(PatchConfig):
|
||||
title: str = Field("Anixarty", description="Заголовок")
|
||||
description: str = Field("Описание", description="Описание")
|
||||
link_text: str = Field("МЫ В TELEGRAM", description="Текст ссылки")
|
||||
link_url: str = Field("https://t.me/http_teapod", description="Ссылка")
|
||||
skip_text: str = Field("Пропустить", description="Текст кнопки пропуска")
|
||||
title_bg_color: str = Field("#FFFFFF", description="Цвет фона заголовка")
|
||||
|
||||
|
||||
# Patch
|
||||
def apply(config: Config, base: Dict[str, Any]) -> bool:
|
||||
# Добавление ресурсов окна первого входа
|
||||
shutil.copy("./resources/avatar.png", "./decompiled/assets/avatar.png")
|
||||
shutil.copy(
|
||||
"./resources/OpenSans-Regular.ttf",
|
||||
"./decompiled/assets/OpenSans-Regular.ttf",
|
||||
)
|
||||
shutil.copytree(
|
||||
"./resources/smali_classes4/", "./decompiled/smali_classes4/"
|
||||
)
|
||||
|
||||
file_path = "./decompiled/smali_classes2/com/swiftsoft/anixartd/ui/activity/MainActivity.smali"
|
||||
method = "invoke-super {p0}, Lmoxy/MvpAppCompatActivity;->onResume()V"
|
||||
lines = get_smali_lines(file_path)
|
||||
lines = find_and_replace_smali_line(lines, method, method+"\ninvoke-static {p0}, Lcom/swiftsoft/about/$2;->oooooo(Landroid/content/Context;)Ljava/lang/Object;")
|
||||
save_smali_lines(file_path, lines)
|
||||
|
||||
return True
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.59 23.26l-0.01 0-0.07 0.03-0.02 0.01-0.01-0.01-0.07-0.03q-0.02-0.01-0.03 0l0 0.01-0.02 0.43 0.01 0.02 0.01 0.02 0.1 0.07 0.02 0 0.01 0 0.1-0.07 0.01-0.02 0.01-0.02-0.02-0.42q0-0.02-0.02-0.02m0.27-0.12l-0.01 0.01-0.19 0.09-0.01 0.01 0 0.01 0.02 0.43 0 0.01 0.01 0.01 0.2 0.09q0.02 0.01 0.03-0.01l0-0.01-0.03-0.61q-0.01-0.02-0.02-0.03m-0.72 0.01a0.02 0.02 0 0 0-0.02 0l-0.01 0.02-0.03 0.61q0 0.02 0.01 0.02l0.02 0 0.2-0.09 0.01-0.01 0-0.01 0.02-0.43 0-0.01-0.01-0.01z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15 16h2.4a4 4 0 0 0 3.94-4.72l-0.91-5A4 4 0 0 0 16.5 3H8v12l1.82 5.79c0.3 0.69 1.06 1.32 2.02 1.13C13.37 21.63 15 20.43 15 18.5z m-9-1a3 3 0 0 1-3-3V6a3 3 0 0 1 3-3z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.59 23.26l-0.01 0-0.07 0.03-0.02 0.01-0.01-0.01-0.07-0.03q-0.02-0.01-0.03 0l0 0.01-0.02 0.43 0.01 0.02 0.01 0.02 0.1 0.07 0.02 0 0.01 0 0.1-0.07 0.01-0.02 0.01-0.02-0.02-0.42q0-0.02-0.02-0.02m0.27-0.12l-0.01 0.01-0.19 0.09-0.01 0.01 0 0.01 0.02 0.43 0 0.01 0.01 0.01 0.2 0.09q0.02 0.01 0.03-0.01l0-0.01-0.03-0.61q-0.01-0.02-0.02-0.03m-0.72 0.01a0.02 0.02 0 0 0-0.02 0l-0.01 0.02-0.03 0.61q0 0.02 0.01 0.02l0.02 0 0.2-0.09 0.01-0.01 0-0.01 0.02-0.43 0-0.01-0.01-0.01z"/>
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M16.5 3a4 4 0 0 1 3.93 3.28l0.91 5a4 4 0 0 1-3.94 4.72H15v2.5c0 1.93-1.63 3.12-3.15 3.42-0.96 0.18-1.73-0.44-2.03-1.13l-2.48-5.79H6a3 3 0 0 1-3-3v-6a3 3 0 0 1 3-3z m0 2H9v8.59a1 1 0 0 0 0.08 0.39l2.54 5.94c0.88-0.22 1.38-0.83 1.38-1.42v-2.5a2 2 0 0 1 2-2h2.4a2 2 0 0 0 1.97-2.36l-0.91-5a2 2 0 0 0-1.96-1.64M7 5H6a1 1 0 0 0-0.99 0.88L5 6v6a1 1 0 0 0 0.88 0.99l0.12 0.01h1z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.59 23.26l-0.01 0-0.07 0.03-0.02 0.01-0.01-0.01-0.07-0.03q-0.02-0.01-0.03 0l0 0.01-0.02 0.43 0.01 0.02 0.01 0.02 0.1 0.07 0.02 0 0.01 0 0.1-0.07 0.01-0.02 0.01-0.02-0.02-0.42q0-0.02-0.02-0.02m0.27-0.12l-0.01 0.01-0.19 0.09-0.01 0.01 0 0.01 0.02 0.43 0 0.01 0.01 0.01 0.2 0.09q0.02 0.01 0.03-0.01l0-0.01-0.03-0.61q-0.01-0.02-0.02-0.03m-0.72 0.01a0.02 0.02 0 0 0-0.02 0l-0.01 0.02-0.03 0.61q0 0.02 0.01 0.02l0.02 0 0.2-0.09 0.01-0.01 0-0.01 0.02-0.43 0-0.01-0.01-0.01z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15 8h2.4a4 4 0 0 1 3.94 4.72l-0.91 5A4 4 0 0 1 16.5 21H8V9l1.82-5.79c0.3-0.69 1.06-1.32 2.02-1.13C13.37 2.38 15 3.57 15 5.5zM6 9a3 3 0 0 0-3 3v6a3 3 0 0 0 3 3z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.59 23.26l-0.01 0-0.07 0.03-0.02 0.01-0.01-0.01-0.07-0.03q-0.02-0.01-0.03 0l0 0.01-0.02 0.43 0.01 0.02 0.01 0.02 0.1 0.07 0.02 0 0.01 0 0.1-0.07 0.01-0.02 0.01-0.02-0.02-0.42q0-0.02-0.02-0.02m0.27-0.12l-0.01 0.01-0.19 0.09-0.01 0.01 0 0.01 0.02 0.43 0 0.01 0.01 0.01 0.2 0.09q0.02 0.01 0.03-0.01l0-0.01-0.03-0.61q-0.01-0.02-0.02-0.03m-0.72 0.01a0.02 0.02 0 0 0-0.02 0l-0.01 0.02-0.03 0.61q0 0.02 0.01 0.02l0.02 0 0.2-0.09 0.01-0.01 0-0.01 0.02-0.43 0-0.01-0.01-0.01z"/>
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9.82 3.21c0.3-0.69 1.06-1.32 2.02-1.13 1.47 0.28 3.04 1.4 3.15 3.22L15 5.5V8h2.4a4 4 0 0 1 3.97 4.52l-0.03 0.2-0.91 5a4 4 0 0 1-3.74 3.28l-0.19 0H6a3 3 0 0 1-3-2.82L3 18v-6a3 3 0 0 1 2.82-3L6 9h1.34zM7 11H6a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h1z m4.63-6.92l-2.55 5.94a1 1 0 0 0-0.07 0.26L9 10.41V19h7.5a2 2 0 0 0 1.93-1.49l0.03-0.15 0.91-5a2 2 0 0 0-1.82-2.35L17.41 10H15a2 2 0 0 1-2-1.85L13 8V5.5c0-0.55-0.43-1.12-1.21-1.37z"/>
|
||||
</vector>
|
||||
@@ -1,6 +0,0 @@
|
||||
import struct
|
||||
|
||||
|
||||
def float_to_hex(f):
|
||||
b = struct.pack(">f", f)
|
||||
return b.hex()
|
||||
+13
-5
@@ -1,8 +1,9 @@
|
||||
from lxml import etree
|
||||
from typing_extensions import Optional
|
||||
from copy import deepcopy
|
||||
from lxml import etree
|
||||
|
||||
|
||||
def insert_after_public(anchor_name: str, elem_name: str):
|
||||
def insert_after_public(anchor_name: str, elem_name: str) -> Optional[int]:
|
||||
file_path = "./decompiled/res/values/public.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
@@ -19,6 +20,8 @@ def insert_after_public(anchor_name: str, elem_name: str):
|
||||
anchor = (elem, attrs)
|
||||
types[attrs["type"]] = types.get(attrs["type"], []) + [int(attrs["id"], 16)]
|
||||
|
||||
assert anchor != None
|
||||
|
||||
free_ids = set()
|
||||
group = types[anchor[1]["type"]]
|
||||
for i in range(min(group), max(group) + 1):
|
||||
@@ -47,7 +50,7 @@ def insert_after_public(anchor_name: str, elem_name: str):
|
||||
return new_id
|
||||
|
||||
|
||||
def insert_after_id(anchor_name: str, elem_name: str):
|
||||
def insert_after_id(anchor_name: str, elem_name: str) -> None:
|
||||
file_path = "./decompiled/res/values/ids.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
@@ -62,13 +65,15 @@ def insert_after_id(anchor_name: str, elem_name: str):
|
||||
assert anchor == None
|
||||
anchor = (elem, attrs)
|
||||
|
||||
assert anchor != None
|
||||
|
||||
new_elem = deepcopy(anchor[0])
|
||||
new_elem.set("name", elem_name)
|
||||
anchor[0].addnext(new_elem)
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
|
||||
def change_color(name: str, value: str):
|
||||
def change_color(name: str, value: str) -> None:
|
||||
file_path = "./decompiled/res/values/colors.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
@@ -86,7 +91,8 @@ def change_color(name: str, value: str):
|
||||
assert replacements >= 1
|
||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||
|
||||
def insert_after_color(anchor_name: str, elem_name: str, elem_value: str):
|
||||
|
||||
def insert_after_color(anchor_name: str, elem_name: str, elem_value: str) -> None:
|
||||
file_path = "./decompiled/res/values/colors.xml"
|
||||
parser = etree.XMLParser(remove_blank_text=True)
|
||||
tree = etree.parse(file_path, parser)
|
||||
@@ -101,6 +107,8 @@ def insert_after_color(anchor_name: str, elem_name: str, elem_value: str):
|
||||
assert anchor == None
|
||||
anchor = (elem, attrs)
|
||||
|
||||
assert anchor != None
|
||||
|
||||
new_elem = deepcopy(anchor[0])
|
||||
new_elem.set("name", elem_name)
|
||||
anchor[0].addnext(new_elem)
|
||||
|
||||
@@ -67,3 +67,11 @@ def find_and_replace_smali_line(
|
||||
def float_to_hex(f):
|
||||
b = struct.pack(">f", f)
|
||||
return b.hex()
|
||||
|
||||
|
||||
def quick_replace(file: str) -> None:
|
||||
content = ""
|
||||
with open(file, "r", encoding="utf-8") as smali:
|
||||
content = smali.read()
|
||||
with open(file, "w", encoding="utf-8") as f:
|
||||
f.writelines(content)
|
||||
|
||||
@@ -19,6 +19,7 @@ def ensure_dirs():
|
||||
for d in [TOOLS, ORIGINAL, MODIFIED, DECOMPILED, PATCHES, CONFIGS]:
|
||||
d.mkdir(exist_ok=True)
|
||||
|
||||
|
||||
def run(console: Console, cmd: List[str], hide_output=True):
|
||||
prog = local[cmd[0]][cmd[1:]]
|
||||
try:
|
||||
@@ -28,6 +29,7 @@ def run(console: Console, cmd: List[str], hide_output=True):
|
||||
console.print(e.stderr)
|
||||
raise typer.Exit(1)
|
||||
|
||||
|
||||
def download(console: Console, url: str, dest: Path):
|
||||
console.print(f"[cyan]Скачивание {url} → {dest.name}")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user