61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
import TOML from "toml";
|
|
import { applyConfiguredTransforms, type PatchConfig } from "./extractors";
|
|
|
|
const root = import.meta.dir;
|
|
const inputRoot = path.join(root, "inputs");
|
|
const outputRoot = path.join(root, "outputs");
|
|
const tempRoot = path.join(root, "temp");
|
|
const apktoolJar = path.join(root, "java", "apktool_2.4.1.jar");
|
|
|
|
function run(command: string, args: string[]): void {
|
|
const result = spawnSync(command, args, { cwd: root, stdio: "inherit" });
|
|
if (result.error) throw result.error;
|
|
if (result.status !== 0)
|
|
throw new Error(`${command} exited with status ${result.status}`);
|
|
}
|
|
|
|
function processApp(file: string): void {
|
|
const input = path.join(inputRoot, file);
|
|
const appName = path.basename(file, path.extname(file));
|
|
const workDir = path.join(tempRoot, appName);
|
|
const configPath = path.join(root, "apkpatch", `${appName}.toml`);
|
|
const output = path.join(outputRoot, `${appName}_patched.apk`);
|
|
|
|
console.log(`[+] Processing ${file}`);
|
|
fs.rmSync(workDir, { recursive: true, force: true });
|
|
run("java", ["-jar", apktoolJar, "d", "-f", input, "-o", workDir]);
|
|
if (!fs.existsSync(configPath))
|
|
throw new Error(`Missing patch configuration ${configPath}`);
|
|
const config = TOML.parse(fs.readFileSync(configPath, "utf8")) as PatchConfig;
|
|
applyConfiguredTransforms(workDir, config, root);
|
|
fs.mkdirSync(outputRoot, { recursive: true });
|
|
run("java", ["-jar", apktoolJar, "b", workDir, "-o", output]);
|
|
console.log(`[ok] Rebuilt ${output}`);
|
|
}
|
|
|
|
function main(): void {
|
|
fs.mkdirSync(outputRoot, { recursive: true });
|
|
fs.mkdirSync(tempRoot, { recursive: true });
|
|
const requested = process.argv.slice(2);
|
|
const files = requested.length
|
|
? requested.map((name) => (name.endsWith(".apk") ? name : `${name}.apk`))
|
|
: fs
|
|
.readdirSync(inputRoot)
|
|
.filter((name) => name.endsWith(".apk"))
|
|
.sort();
|
|
let failures = 0;
|
|
for (const file of files) {
|
|
try {
|
|
processApp(file);
|
|
} catch (error) {
|
|
failures++;
|
|
console.error(`[failed] ${file}`, error);
|
|
}
|
|
}
|
|
if (failures) process.exitCode = 1;
|
|
}
|
|
|
|
main();
|