android-unlock-and-more-box/aubox/cli.py

120 lines
3.7 KiB
Python

"""CLI-Einstiegspunkt: `python -m aubox <command>`."""
from __future__ import annotations
import argparse
import sys
import time
from . import p10lite, usb
from .kirin import KirinDload
def cmd_detect(_args: argparse.Namespace) -> int:
devs = usb.scan()
if not devs:
print("Kein bekanntes Hersteller-Gerät angeschlossen.")
print("Probiere `lsusb` für die rohe Liste.")
return 1
for d in devs:
print(d)
if d.mode.notes:
print(f" {d.mode.notes}")
return 0
def cmd_p10lite_frp(args: argparse.Namespace) -> int:
if args.method == "erecovery":
print(p10lite.erecovery_instructions())
return 0
if args.method == "dload-erase":
try:
plan = p10lite.dload_erase_plan()
except FileNotFoundError as e:
print(str(e), file=sys.stderr)
return 2
print("Plan:")
for stage in plan["stages"]:
print(f" - {stage['label']}: {stage['file']} -> 0x{stage['addr']:08x}")
print()
print("Bitte jetzt Testpoint setzen und USB anschließen.")
print("Warte auf Kirin DLOAD (12d1:1100)...")
for _ in range(60):
if usb.find_first("kirin-dload") is not None:
break
time.sleep(0.5)
else:
print("Timeout: kein Kirin DLOAD erschienen.", file=sys.stderr)
return 3
print("Gerät erkannt. Sende Loader-Stages...")
with KirinDload() as k:
for stage in plan["stages"]:
print(f" -> {stage['label']}")
k.send_loader(stage["file"], stage["addr"])
# Zwischen den Stages re-enumeriert das Gerät evtl.
time.sleep(2)
print("Loader-Stages gesendet. Erwarteter Folgemodus:",
plan["post"])
print("Nächster Schritt (manuell, bis Workflow ausgereift):")
print(" fastboot devices")
print(f" fastboot erase {plan['frp_partition']}")
return 0
print(f"Methode {args.method!r} noch nicht implementiert.", file=sys.stderr)
return 2
def cmd_web(args: argparse.Namespace) -> int:
import uvicorn
uvicorn.run(
"aubox.web.app:app",
host=args.host,
port=args.port,
reload=args.reload,
log_level="info",
)
return 0
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(prog="aubox")
sub = p.add_subparsers(dest="cmd", required=True)
sp_detect = sub.add_parser("detect", help="Angeschlossene Geräte erkennen")
sp_detect.set_defaults(func=cmd_detect)
sp_web = sub.add_parser("web", help="Lokale Web-UI starten")
sp_web.add_argument("--host", default="127.0.0.1",
help="Bind-Adresse (Default: 127.0.0.1, im Container 0.0.0.0)")
sp_web.add_argument("--port", type=int, default=8080)
sp_web.add_argument("--reload", action="store_true",
help="Auto-Reload bei Code-Änderungen (Entwicklung)")
sp_web.set_defaults(func=cmd_web)
sp_p10 = sub.add_parser("p10lite", help="Workflows für Huawei P10 Lite")
p10_sub = sp_p10.add_subparsers(dest="p10_cmd", required=True)
sp_frp = p10_sub.add_parser("frp-remove", help="Google-Account-Sperre entfernen")
sp_frp.add_argument(
"--method",
choices=["erecovery", "dload-erase", "dload-flash"],
default="erecovery",
help="Welcher Pfad? Default: erecovery (sicherster, kein Loader nötig)",
)
sp_frp.set_defaults(func=cmd_p10lite_frp)
return p
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
return args.func(args)
if __name__ == "__main__":
raise SystemExit(main())