Исправление патчей, реализация базвого функционала для сборки apk
This commit is contained in:
@@ -9,10 +9,11 @@
|
|||||||
"colors": {
|
"colors": {
|
||||||
"primary": "#ccff00",
|
"primary": "#ccff00",
|
||||||
"secondary": "#ffffd700",
|
"secondary": "#ffffd700",
|
||||||
"background": "#FFFFFF",
|
"background": "#ffffff",
|
||||||
"text": "#000000"
|
"text": "#000000"
|
||||||
},
|
},
|
||||||
"gradient": {
|
"gradient": {
|
||||||
|
"angle": "135.0",
|
||||||
"from": "#ffff6060",
|
"from": "#ffff6060",
|
||||||
"to": "#ffccff00"
|
"to": "#ffccff00"
|
||||||
}
|
}
|
||||||
@@ -51,5 +52,5 @@
|
|||||||
"android": "http://schemas.android.com/apk/res/android",
|
"android": "http://schemas.android.com/apk/res/android",
|
||||||
"app": "http://schemas.android.com/apk/res-auto"
|
"app": "http://schemas.android.com/apk/res-auto"
|
||||||
},
|
},
|
||||||
"speeds": [0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 9.0]
|
"speeds": [9.0]
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import json
|
|||||||
import requests
|
import requests
|
||||||
import colorama
|
import colorama
|
||||||
import importlib
|
import importlib
|
||||||
|
import traceback
|
||||||
import subprocess
|
import subprocess
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ def init() -> dict:
|
|||||||
if not os.path.exists(directory):
|
if not os.path.exists(directory):
|
||||||
os.makedirs(directory)
|
os.makedirs(directory)
|
||||||
|
|
||||||
with open("./patches/config.json", "r") as config_file:
|
with open("./config.json", "r") as config_file:
|
||||||
conf = json.load(config_file)
|
conf = json.load(config_file)
|
||||||
|
|
||||||
if not os.path.exists("./tools/apktool.jar"):
|
if not os.path.exists("./tools/apktool.jar"):
|
||||||
@@ -106,6 +107,23 @@ def decompile_apk(apk: str):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def compile_apk(apk: str):
|
||||||
|
print("Компилируем apk...")
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
"tools/apktool b decompiled -o " + os.path.join("modified", apk),
|
||||||
|
shell=True,
|
||||||
|
check=True,
|
||||||
|
text=True,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print("Ошибка при выполнении команды:")
|
||||||
|
print(e.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
class Patch:
|
class Patch:
|
||||||
def __init__(self, name, pkg):
|
def __init__(self, name, pkg):
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -122,7 +140,8 @@ class Patch:
|
|||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Ошибка при применении патча {self.name}: {e}")
|
print(f"Ошибка при применении патча {self.name}: {e}")
|
||||||
print(e.args)
|
print(type(e), e.args)
|
||||||
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@@ -150,8 +169,14 @@ for patch in patches:
|
|||||||
print(f"{marker}{colorama.Style.RESET_ALL} {patch.name}")
|
print(f"{marker}{colorama.Style.RESET_ALL} {patch.name}")
|
||||||
|
|
||||||
if all(statuses.values()):
|
if all(statuses.values()):
|
||||||
print("Все патчи успешно применены")
|
print(f"{colorama.Fore.GREEN}Все патчи успешно применены{colorama.Style.RESET_ALL}")
|
||||||
|
compile_apk(apk)
|
||||||
elif any(statuses.values()):
|
elif any(statuses.values()):
|
||||||
print("Некоторые патчи не были успешно применены")
|
print(f"{colorama.Fore.YELLOW}⚠{colorama.Style.RESET_ALL} Некоторые патчи не были успешно применены")
|
||||||
|
if input("Продолжить? (y/n): ").lower() == "y":
|
||||||
|
compile_apk(apk)
|
||||||
|
else:
|
||||||
|
print(colorama.Fore.RED + "Операция отменена" + colorama.Style.RESET_ALL)
|
||||||
else:
|
else:
|
||||||
print("Ни один патч не был успешно применен")
|
print(f"{colorama.Fore.RED}Ни один патч не был успешно применен{colorama.Style.RESET_ALL}")
|
||||||
|
sys.exit(1)
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
"""Change api server"""
|
||||||
|
priority = 0
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
import json
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
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}"
|
||||||
|
for item in json.loads(response.text)['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']}")
|
||||||
|
f.write(content.replace(item['src'], item['dst']))
|
||||||
|
return True
|
||||||
@@ -12,9 +12,11 @@ def apply(config: dict) -> bool:
|
|||||||
|
|
||||||
if os.path.isfile(item_path):
|
if os.path.isfile(item_path):
|
||||||
os.remove(item_path)
|
os.remove(item_path)
|
||||||
|
if config.get("verbose", False):
|
||||||
tqdm.write(f'Удалён файл: {item_path}')
|
tqdm.write(f'Удалён файл: {item_path}')
|
||||||
elif os.path.isdir(item_path):
|
elif os.path.isdir(item_path):
|
||||||
if item not in config["cleanup"]["keep_dirs"]:
|
if item not in config["cleanup"]["keep_dirs"]:
|
||||||
shutil.rmtree(item_path)
|
shutil.rmtree(item_path)
|
||||||
|
if config.get("verbose", False):
|
||||||
tqdm.write(f'Удалена папка: {item_path}')
|
tqdm.write(f'Удалена папка: {item_path}')
|
||||||
return True
|
return True
|
||||||
|
|||||||
+56
-1
@@ -3,10 +3,17 @@ priority = 0
|
|||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
|
from utils.public import (
|
||||||
|
insert_after_public,
|
||||||
|
insert_after_color,
|
||||||
|
insert_after_id,
|
||||||
|
change_color,
|
||||||
|
)
|
||||||
|
|
||||||
def apply(config: dict) -> bool:
|
def apply(config: dict) -> bool:
|
||||||
main_color = config["theme"]["colors"]["primary"]
|
main_color = config["theme"]["colors"]["primary"]
|
||||||
splash_color = config["theme"]["colors"]["secondary"]
|
splash_color = config["theme"]["colors"]["secondary"]
|
||||||
|
gradient_angle = config["theme"]["gradient"]["angle"]
|
||||||
gradient_from = config["theme"]["gradient"]["from"]
|
gradient_from = config["theme"]["gradient"]["from"]
|
||||||
gradient_to = config["theme"]["gradient"]["to"]
|
gradient_to = config["theme"]["gradient"]["to"]
|
||||||
|
|
||||||
@@ -31,6 +38,7 @@ def apply(config: dict) -> bool:
|
|||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
|
|
||||||
# Change attributes with namespace
|
# Change attributes with namespace
|
||||||
|
root.set(f"{{{config['xml_ns']['android']}}}angle", gradient_angle)
|
||||||
root.set(f"{{{config['xml_ns']['android']}}}startColor", gradient_from)
|
root.set(f"{{{config['xml_ns']['android']}}}startColor", gradient_from)
|
||||||
root.set(f"{{{config['xml_ns']['android']}}}endColor", gradient_to)
|
root.set(f"{{{config['xml_ns']['android']}}}endColor", gradient_to)
|
||||||
|
|
||||||
@@ -45,7 +53,7 @@ def apply(config: dict) -> bool:
|
|||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
|
|
||||||
# Finding "path"
|
# Finding "path"
|
||||||
for el in root.findall("path", namespaces=config['xml_ns']):
|
for el in root.findall("path", namespaces=config["xml_ns"]):
|
||||||
name = el.get(f"{{{config['xml_ns']['android']}}}name")
|
name = el.get(f"{{{config['xml_ns']['android']}}}name")
|
||||||
if name == "path":
|
if name == "path":
|
||||||
el.set(f"{{{config['xml_ns']['android']}}}fillColor", splash_color)
|
el.set(f"{{{config['xml_ns']['android']}}}fillColor", splash_color)
|
||||||
@@ -53,4 +61,51 @@ def apply(config: dict) -> bool:
|
|||||||
# Save back
|
# Save back
|
||||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||||
|
|
||||||
|
for filename in ["$ic_launcher_foreground__0", "$ic_banner_foreground__0"]:
|
||||||
|
file_path = f"./decompiled/res/drawable-v24/{filename}.xml"
|
||||||
|
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
tree = etree.parse(file_path, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
# Change attributes with namespace
|
||||||
|
root.set(f"{{{config['xml_ns']['android']}}}angle", gradient_angle)
|
||||||
|
items = root.findall("item", namespaces=config['xml_ns'])
|
||||||
|
assert len(items) == 2
|
||||||
|
items[0].set(f"{{{config['xml_ns']['android']}}}color", gradient_from)
|
||||||
|
items[1].set(f"{{{config['xml_ns']['android']}}}color", gradient_to)
|
||||||
|
|
||||||
|
# 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:])
|
||||||
|
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:])
|
||||||
|
change_color("refresh_progress", main_color[0]+'ff'+main_color[1:])
|
||||||
|
|
||||||
|
change_color("ic_launcher_background", "#ff000000")
|
||||||
|
change_color("bottom_nav_indicator_active", "#ffffffff")
|
||||||
|
change_color("bottom_nav_indicator_icon_checked", main_color[0]+'ff'+main_color[1:])
|
||||||
|
change_color("bottom_nav_indicator_label_checked", main_color[0]+'ff'+main_color[1:])
|
||||||
|
|
||||||
|
insert_after_public("warning_error_counter_background", "ic_custom_telegram")
|
||||||
|
insert_after_public("warning_error_counter_background", "ic_custom_crown")
|
||||||
|
|
||||||
|
try:
|
||||||
|
last = "speed75"
|
||||||
|
for speed in config.get("speeds", []):
|
||||||
|
insert_after_public(last, f"speed{int(float(speed)*10)}")
|
||||||
|
insert_after_id(last, f"speed{int(float(speed)*10)}")
|
||||||
|
last = f"speed{int(float(speed)*10)}"
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error occurred while processing speeds: {e}")
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
def compress_pngs(root_dir):
|
def compress_pngs(root_dir: str, verbose: bool = False):
|
||||||
compressed_files = []
|
compressed_files = []
|
||||||
for dirpath, _, filenames in os.walk(root_dir):
|
for dirpath, _, filenames in os.walk(root_dir):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if filename.lower().endswith(".png"):
|
if filename.lower().endswith(".png"):
|
||||||
filepath = os.path.join(dirpath, filename)
|
filepath = os.path.join(dirpath, filename)
|
||||||
tqdm.write(f"Сжимаю: {filepath}")
|
if verbose: tqdm.write(f"Сжимаю: {filepath}")
|
||||||
try:
|
try:
|
||||||
subprocess.run(
|
assert subprocess.run(
|
||||||
[
|
[
|
||||||
"pngquant",
|
"pngquant",
|
||||||
"--force",
|
"--force",
|
||||||
@@ -23,9 +23,8 @@ def compress_pngs(root_dir):
|
|||||||
"--quality=65-90",
|
"--quality=65-90",
|
||||||
filepath,
|
filepath,
|
||||||
],
|
],
|
||||||
check=True,
|
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
)
|
).returncode in [0, 99]
|
||||||
compressed_files.append(filepath)
|
compressed_files.append(filepath)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
tqdm.write(f"Ошибка при сжатии {filepath}: {e}")
|
tqdm.write(f"Ошибка при сжатии {filepath}: {e}")
|
||||||
@@ -33,5 +32,5 @@ def compress_pngs(root_dir):
|
|||||||
|
|
||||||
|
|
||||||
def apply(config: dict) -> bool:
|
def apply(config: dict) -> bool:
|
||||||
files = compress_pngs("./decompiled")
|
files = compress_pngs("./decompiled", config.get("verbose", False))
|
||||||
return len(files) > 0 and any(files)
|
return len(files) > 0 and any(files)
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ from tqdm import tqdm
|
|||||||
import os
|
import os
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from typing import TypedDict
|
|
||||||
|
|
||||||
|
|
||||||
def apply(config) -> bool:
|
def apply(config) -> bool:
|
||||||
attributes = [
|
attributes = [
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ def apply(config: dict) -> bool:
|
|||||||
config["new_package_name"].replace(".", "/"),
|
config["new_package_name"].replace(".", "/"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
os.rmdir("./decompiled/smali_classes2/com/swiftsoft")
|
||||||
if os.path.exists("./decompiled/smali_classes4/com/swiftsoft"):
|
if os.path.exists("./decompiled/smali_classes4/com/swiftsoft"):
|
||||||
rename_dir(
|
rename_dir(
|
||||||
"./decompiled/smali_classes4/com/swiftsoft",
|
"./decompiled/smali_classes4/com/swiftsoft",
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
"""Change api server"""
|
|
||||||
priority = 0
|
|
||||||
from tqdm import tqdm
|
|
||||||
|
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
|
|
||||||
|
|
||||||
def apply(config: dict) -> bool:
|
|
||||||
response = requests.get(config['server'])
|
|
||||||
if response.status_code == 200:
|
|
||||||
for item in json.loads(response.text)["modding"]:
|
|
||||||
tqdm.write(item)
|
|
||||||
return True
|
|
||||||
tqdm.write(f"Failed to fetch data {response.status_code} {response.text}")
|
|
||||||
return False
|
|
||||||
+65
-7
@@ -2,15 +2,15 @@ from lxml import etree
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
def insert_after(anchor_name: str, elem_name: str):
|
def insert_after_public(anchor_name: str, elem_name: str):
|
||||||
file_path = "../decompiled/res/values/public.xml"
|
file_path = "./decompiled/res/values/public.xml"
|
||||||
parser = etree.XMLParser(remove_blank_text=True)
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
tree = etree.parse(file_path, parser)
|
tree = etree.parse(file_path, parser)
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
anchor = None
|
anchor = None
|
||||||
types = {}
|
types = {}
|
||||||
|
|
||||||
for idx, elem in enumerate(root):
|
for elem in root:
|
||||||
assert elem.tag == "public"
|
assert elem.tag == "public"
|
||||||
assert elem.keys() == ["type", "name", "id"]
|
assert elem.keys() == ["type", "name", "id"]
|
||||||
attrs = dict(zip(elem.keys(), elem.values()))
|
attrs = dict(zip(elem.keys(), elem.values()))
|
||||||
@@ -25,7 +25,6 @@ def insert_after(anchor_name: str, elem_name: str):
|
|||||||
if i not in group:
|
if i not in group:
|
||||||
free_ids.add(i)
|
free_ids.add(i)
|
||||||
|
|
||||||
assert len(free_ids) > 0
|
|
||||||
new_id = None
|
new_id = None
|
||||||
for i in free_ids:
|
for i in free_ids:
|
||||||
if i > int(anchor[1]["id"], 16):
|
if i > int(anchor[1]["id"], 16):
|
||||||
@@ -38,12 +37,71 @@ def insert_after(anchor_name: str, elem_name: str):
|
|||||||
if name == anchor[1]["type"]:
|
if name == anchor[1]["type"]:
|
||||||
continue
|
continue
|
||||||
if new_id in group:
|
if new_id in group:
|
||||||
new_id = max(group)
|
assert False, f"ID {new_id} already exists in group {name}"
|
||||||
|
|
||||||
new_elem = deepcopy(anchor[0])
|
new_elem = deepcopy(anchor[0])
|
||||||
new_elem.set("id", new_id)
|
new_elem.set("id", hex(new_id))
|
||||||
new_elem.set("name", elem_name)
|
new_elem.set("name", elem_name)
|
||||||
anchor[0].addnext(new_elem)
|
anchor[0].addnext(new_elem)
|
||||||
|
|
||||||
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
tree.write(file_path, pretty_print=True, xml_declaration=True, encoding="utf-8")
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
|
|
||||||
|
def insert_after_id(anchor_name: str, elem_name: str):
|
||||||
|
file_path = "./decompiled/res/values/ids.xml"
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
tree = etree.parse(file_path, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
anchor = None
|
||||||
|
|
||||||
|
for elem in root:
|
||||||
|
assert elem.tag == "item"
|
||||||
|
assert elem.keys() == ["type", "name"]
|
||||||
|
attrs = dict(zip(elem.keys(), elem.values()))
|
||||||
|
if attrs["name"] == anchor_name:
|
||||||
|
assert anchor == None
|
||||||
|
anchor = (elem, attrs)
|
||||||
|
|
||||||
|
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):
|
||||||
|
file_path = "./decompiled/res/values/colors.xml"
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
tree = etree.parse(file_path, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
replacements = 0
|
||||||
|
|
||||||
|
for elem in root:
|
||||||
|
assert elem.tag == "color"
|
||||||
|
assert elem.keys() == ["name"]
|
||||||
|
attrs = dict(zip(elem.keys(), elem.values()))
|
||||||
|
if attrs["name"] == name:
|
||||||
|
elem.set("name", name)
|
||||||
|
elem.text = value
|
||||||
|
replacements += 1
|
||||||
|
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):
|
||||||
|
file_path = "./decompiled/res/values/colors.xml"
|
||||||
|
parser = etree.XMLParser(remove_blank_text=True)
|
||||||
|
tree = etree.parse(file_path, parser)
|
||||||
|
root = tree.getroot()
|
||||||
|
anchor = None
|
||||||
|
|
||||||
|
for elem in root:
|
||||||
|
assert elem.tag == "color"
|
||||||
|
assert elem.keys() == ["name"]
|
||||||
|
attrs = dict(zip(elem.keys(), elem.values()))
|
||||||
|
if attrs["name"] == anchor_name:
|
||||||
|
assert anchor == None
|
||||||
|
anchor = (elem, attrs)
|
||||||
|
|
||||||
|
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")
|
||||||
|
|||||||
Reference in New Issue
Block a user