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:
commit
b6c058c40f
16 changed files with 400 additions and 0 deletions
0
scripts/__init__.py
Normal file
0
scripts/__init__.py
Normal file
46
scripts/download_tools.py
Normal file
46
scripts/download_tools.py
Normal 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
27
scripts/select_apk.py
Normal 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
87
scripts/select_patches.py
Normal 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
43
scripts/utils.py
Normal 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)
|
Loading…
Add table
Add a link
Reference in a new issue