1
0
Fork 0
mirror of https://github.com/Radiquum/anixart-patcher.git synced 2025-09-06 03:03:50 +05:00

feat: initial commit

This commit is contained in:
Kentai Radiquum 2025-08-31 19:51:58 +05:00
commit b6c058c40f
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
16 changed files with 400 additions and 0 deletions

0
scripts/__init__.py Normal file
View file

46
scripts/download_tools.py Normal file
View file

@ -0,0 +1,46 @@
import requests
import os
from tqdm import tqdm
from config import config, log
def check_if_tool_exists(tool: str) -> bool:
if not os.path.exists(config["folders"]["tools"]):
log.info(f"creating `tools` folder: {config['folders']['tools']}")
os.mkdir(config["folders"]["tools"])
if not os.path.exists(f"{config['folders']['tools']}/{tool}"):
return False
elif os.path.exists(f"{config['folders']['tools']}/{tool}") and os.path.isdir(
f"{config['folders']['tools']}/{tool}"
):
log.warning(f"`{config['folders']['tools']}/{tool}` is a folder")
return True
else:
return True
def download_tool(url: str, tool: str):
if not check_if_tool_exists(tool):
log.info(f"downloading a tool: `{tool}`")
try:
response = requests.get(url, stream=True)
total = int(response.headers.get("content-length", 0))
with open(f"{config['folders']['tools']}/{tool}", "wb") as file, tqdm(
desc=tool,
total=total,
unit="iB",
unit_scale=True,
unit_divisor=1024,
) as bar:
for bytes in response.iter_content(chunk_size=8192):
size = file.write(bytes)
bar.update(size)
log.info(f"`{tool}` downloaded")
except Exception as e:
log.error(f"error while downloading `{tool}`: {e}")
def check_and_download_all_tools():
for tool in config["tools"]:
download_tool(tool["url"], tool["tool"])

27
scripts/select_apk.py Normal file
View file

@ -0,0 +1,27 @@
import os
from beaupy import select
from config import config, log, console
def get_apks() -> list[str]:
apks = []
if not os.path.exists(config["folders"]["apks"]):
log.info(f"creating `apks` folder: {config['folders']['apks']}")
os.mkdir(config["folders"]["apks"])
return apks
for file in os.listdir(config["folders"]["apks"]):
if file.endswith(".apk") and os.path.isfile(f"{config['folders']['apks']}/{file}"):
apks.append(file)
return apks
def select_apk(apks: list[str]) -> str:
console.print("select apk file to patch")
apks.append("cancel")
apk = select(apks, cursor="->", cursor_style="cyan")
if apk == "cancel":
log.info("patching cancelled")
exit(0)
return apk

87
scripts/select_patches.py Normal file
View file

@ -0,0 +1,87 @@
import os, json
import importlib
from typing import TypedDict
from beaupy import select_multiple
from tqdm import tqdm
from config import config, log, console
class Patch:
def __init__(self, name, pkg):
self.name = name
self.package = pkg
self.applied = False
try:
self.priority = pkg.priority
except AttributeError:
self.priority = 0
def apply(self, conf: dict) -> bool:
try:
self.applied = self.package.apply(conf)
return True
except Exception as e:
log.error(
f"error while applying a patch {self.name}: %s, with args: %s",
e,
e.args,
exc_info=True,
)
return False
def get_patches() -> list[str]:
patches = []
if not os.path.exists(config["folders"]["patches"]):
log.info(f"creating `patches` folder: {config['folders']['patches']}")
os.mkdir(config["folders"]["patches"])
return patches
for file in os.listdir(config["folders"]["patches"]):
if (
file.endswith(".py")
and os.path.isfile(f"{config['folders']['patches']}/{file}")
and file != "__init__.py"
):
patches.append(file[:-3])
return patches
def select_patches(patches: list[str]) -> list[str]:
console.print("select patches to apply")
applied = select_multiple(patches, tick_character="X")
return applied
class PatchStatus(TypedDict):
name: str
status: bool
def apply_patches(patches: list[str]) -> list[PatchStatus]:
modules = []
statuses = []
for name in patches:
module = importlib.import_module(
f"{config['folders']['patches'].removeprefix("./")}.{name}"
)
modules.append(Patch(name, module))
modules.sort(key=lambda x: x.package.priority, reverse=True)
for patch in tqdm(modules, colour="green", desc="patching apk"):
tqdm.write(f"patch apply: {patch.name}")
conf = {}
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 conf:
conf = json.loads(conf.read())
conf["src"] = config["folders"]["decompiled"]
status = patch.apply(conf)
statuses.append({"name": patch.name, "status": status})
return statuses

43
scripts/utils.py Normal file
View file

@ -0,0 +1,43 @@
import os
import shutil
import subprocess
from config import log, config
def check_java_version():
try:
result = subprocess.run(
["java", "-version"], capture_output=True, text=True, check=True
)
version_line = result.stderr.splitlines()[0]
if not any(f"{i}." in version_line for i in range(9, 100)):
log.error(f"java 8+ is not installed")
exit(1)
except subprocess.CalledProcessError:
log.error(f"java 8+ is not found")
exit(1)
log.info(f"found java: {version_line}")
def decompile_apk(apk: str):
if not os.path.exists(config["folders"]["decompiled"]):
log.info(f"creating `decompiled` folder: {config['folders']['decompiled']}")
os.mkdir(config["folders"]["decompiled"])
else:
log.info(f"resetting `decompiled` folder: {config['folders']['decompiled']}")
shutil.rmtree(config["folders"]["decompiled"])
os.mkdir(config["folders"]["decompiled"])
log.info(f"decompile apk: `{apk}`")
try:
result = subprocess.run(
f"java -jar {config['folders']['tools']}/apktool.jar d -f -o {config['folders']['decompiled']} {config['folders']['apks']}/{apk}",
shell=True,
check=True,
text=True,
# stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE,
)
except subprocess.CalledProcessError as e:
log.fatal(f"error of running a command: %s", e.stderr, exc_info=True)
exit(1)