Skip to content

Commit f7a52bc

Browse files
authored
Merge pull request #8 from PixelCode01/feature/data-bundle-tooling
Add package data export and script generation tools
2 parents 02b5159 + dfbeead commit f7a52bc

File tree

5 files changed

+215
-0
lines changed

5 files changed

+215
-0
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,26 @@ Create backup? (y/n): y
144144
Proceed? (yes): yes
145145
```
146146

147+
## Export package data
148+
149+
Generate a consolidated JSON file with all bloatware package information from every supported brand:
150+
151+
```bash
152+
python scripts/generate_data_bundle.py
153+
```
154+
155+
This creates `build/data.json` containing:
156+
- All package names, descriptions, and risk levels
157+
- Brand/platform associations
158+
- Category classifications (adware, telemetry, OEM tools)
159+
- Metadata (generation timestamp, package counts)
160+
161+
Use this data for:
162+
- Custom tooling and automation
163+
- Package analysis and research
164+
- Integration with other debloating workflows
165+
- Creating custom removal scripts
166+
147167
## Important stuff
148168

149169
- **Always backup first** - Things can go wrong

scripts/generate_data_bundle.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
from __future__ import annotations
2+
3+
import argparse
4+
import json
5+
from datetime import datetime, timezone
6+
from importlib import import_module
7+
from pathlib import Path
8+
from typing import Any, Iterable
9+
import sys
10+
11+
ROOT = Path(__file__).resolve().parent.parent
12+
if str(ROOT) not in sys.path:
13+
sys.path.insert(0, str(ROOT))
14+
15+
BRANDS = [
16+
("Samsung", "Samsung.samsung_remover", "SamsungRemover"),
17+
("Xiaomi", "Xiaomi.xiaomi_remover", "XiaomiRemover"),
18+
("Oppo", "Oppo.oppo_remover", "OppoRemover"),
19+
("Vivo", "Vivo.vivo_remover", "VivoRemover"),
20+
("Realme", "Realme.realme_remover", "RealmeRemover"),
21+
("Tecno", "Tecno.tecno_remover", "TecnoRemover"),
22+
("OnePlus", "OnePlus.oneplus_remover", "OnePlusRemover"),
23+
("Huawei", "Huawei.huawei_remover", "HuaweiRemover"),
24+
("Honor", "Honor.honor_remover", "HonorRemover"),
25+
("Motorola", "Motorola.motorola_remover", "MotorolaRemover"),
26+
("Nothing", "Nothing.nothing_remover", "NothingRemover"),
27+
("Asus", "Asus.asus_remover", "AsusRemover"),
28+
("Google", "Google.google_remover", "GoogleRemover"),
29+
("Infinix", "Infinix.infinix_remover", "InfinixRemover"),
30+
("Lenovo", "Lenovo.lenovo_remover", "LenovoRemover"),
31+
]
32+
33+
CATEGORY_OVERRIDES: dict[tuple[str, str] | str, str] = {
34+
("samsung", "carrier_bloat"): "adware",
35+
("samsung", "google_apps"): "telemetry",
36+
"ads": "adware",
37+
"preloads": "oem_tool",
38+
"gaming": "oem_tool",
39+
"services": "telemetry",
40+
"assistant": "telemetry",
41+
"pixel_features": "oem_tool",
42+
"system_tools": "oem_tool",
43+
"media": "adware",
44+
}
45+
46+
RISK_SCORES = {"safe": 1, "caution": 2, "dangerous": 3, "unknown": 0}
47+
48+
49+
def load_packages() -> list[dict[str, Any]]:
50+
entries: list[dict[str, Any]] = []
51+
for brand_title, module_path, class_name in BRANDS:
52+
module = import_module(module_path)
53+
cls = getattr(module, class_name)
54+
remover = cls(test_mode=True)
55+
config = remover._get_default_packages()
56+
categories: dict[str, Iterable[dict[str, Any]]] = config.get("categories", {})
57+
for category_key, packages in categories.items():
58+
for item in packages:
59+
package_name = item.get("name")
60+
if not package_name:
61+
continue
62+
risk = item.get("risk", "unknown").lower()
63+
risk_score = RISK_SCORES.get(risk, 0)
64+
description = item.get("description", "")
65+
normalized_category = category_key.replace("_", " ").title()
66+
group = CATEGORY_OVERRIDES.get((brand_title.lower(), category_key.lower()))
67+
if not group:
68+
group = CATEGORY_OVERRIDES.get(category_key.lower(), "oem_tool")
69+
entries.append(
70+
{
71+
"brand": brand_title,
72+
"platform": brand_title,
73+
"package": package_name,
74+
"description": description,
75+
"risk": risk,
76+
"risk_score": risk_score,
77+
"category": normalized_category,
78+
"category_slug": category_key,
79+
"category_group": group,
80+
}
81+
)
82+
entries.sort(key=lambda row: (row["brand"], row["category"], row["package"]))
83+
return entries
84+
85+
86+
def write_json(payload: dict[str, Any], path: Path) -> None:
87+
path.parent.mkdir(parents=True, exist_ok=True)
88+
path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
89+
90+
91+
def main() -> None:
92+
parser = argparse.ArgumentParser(description="Generate consolidated bloatware dataset")
93+
parser.add_argument("--out", default="build/data.json")
94+
parser.add_argument("--public", default="web/public/data.json")
95+
args = parser.parse_args()
96+
97+
packages = load_packages()
98+
payload = {
99+
"generated_at": datetime.now(timezone.utc).isoformat(),
100+
"package_count": len(packages),
101+
"brands": sorted({entry["brand"] for entry in packages}),
102+
"category_groups": sorted({entry["category_group"] for entry in packages}),
103+
"risks": RISK_SCORES,
104+
"packages": packages,
105+
}
106+
107+
primary_path = Path(args.out)
108+
public_path = Path(args.public)
109+
write_json(payload, primary_path)
110+
write_json(payload, public_path)
111+
112+
113+
if __name__ == "__main__":
114+
main()

scripts/generators/adb.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from __future__ import annotations
2+
3+
from typing import Iterable, Optional
4+
5+
6+
def generate(packages: Iterable[str], *, device_serial: Optional[str] = None) -> str:
7+
pkg_list = [pkg.strip() for pkg in packages if pkg.strip()]
8+
if not pkg_list:
9+
return "# No packages selected"
10+
11+
prefix = f"adb -s {device_serial} shell" if device_serial else "adb shell"
12+
lines = ["# Run these commands in a terminal"]
13+
for pkg in pkg_list:
14+
lines.append(f"{prefix} pm uninstall --user 0 {pkg}")
15+
return "\n".join(lines)

scripts/generators/bash.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from __future__ import annotations
2+
3+
from typing import Iterable, Optional
4+
5+
6+
def generate(packages: Iterable[str], *, device_serial: Optional[str] = None) -> str:
7+
pkg_list = [pkg.strip() for pkg in packages if pkg.strip()]
8+
if not pkg_list:
9+
return "# No packages selected"
10+
11+
prefix = f"adb -s {device_serial} " if device_serial else "adb "
12+
lines: list[str] = []
13+
lines.append("#!/usr/bin/env bash")
14+
lines.append("set -euo pipefail")
15+
lines.append("packages=(")
16+
lines.extend(f' "{pkg}"' for pkg in pkg_list)
17+
lines.append(")")
18+
lines.append("errors=()")
19+
lines.append("for pkg in \"${packages[@]}\"; do")
20+
lines.append(f" if ! {prefix}shell pm uninstall --user 0 \"$pkg\" >/dev/null 2>&1; then")
21+
lines.append(f" if ! {prefix}shell pm disable-user --user 0 \"$pkg\" >/dev/null 2>&1; then")
22+
lines.append(" errors+=(\"$pkg\")")
23+
lines.append(" fi")
24+
lines.append(" fi")
25+
lines.append("done")
26+
lines.append("if [ ${#errors[@]} -gt 0 ]; then")
27+
lines.append(" printf 'Failed to process\\n'")
28+
lines.append(" for pkg in \"${errors[@]}\"; do")
29+
lines.append(" printf ' - %s\\n' \"$pkg\"")
30+
lines.append(" done")
31+
lines.append("else")
32+
lines.append(" echo 'All packages processed successfully.'")
33+
lines.append("fi")
34+
return "\n".join(lines)

scripts/generators/powershell.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from __future__ import annotations
2+
3+
from typing import Iterable, Optional
4+
5+
6+
def generate(packages: Iterable[str], *, device_serial: Optional[str] = None) -> str:
7+
pkg_list = [pkg.strip() for pkg in packages if pkg.strip()]
8+
if not pkg_list:
9+
return "# No packages selected"
10+
11+
serial = f" -s {device_serial}" if device_serial else ""
12+
lines: list[str] = []
13+
lines.append("$packages = @(")
14+
lines.extend(f' "{pkg}"' for pkg in pkg_list)
15+
lines.append(")")
16+
lines.append("$errors = @()")
17+
lines.append("foreach ($pkg in $packages) {")
18+
lines.append(f" $result = adb{serial} shell pm uninstall --user 0 $pkg")
19+
lines.append(" if ($LASTEXITCODE -ne 0 -or -not $result.Contains('Success')) {")
20+
lines.append(f" $fallback = adb{serial} shell pm disable-user --user 0 $pkg")
21+
lines.append(" if ($LASTEXITCODE -ne 0) {")
22+
lines.append(" $errors += $pkg")
23+
lines.append(" }")
24+
lines.append(" }")
25+
lines.append("}")
26+
lines.append("if ($errors.Count -gt 0) {")
27+
lines.append(" Write-Output 'Failed to process:'")
28+
lines.append(" $errors | ForEach-Object { Write-Output (\" - $_\") }")
29+
lines.append("} else {")
30+
lines.append(" Write-Output 'All packages processed successfully.'")
31+
lines.append("}")
32+
return "\n".join(lines)

0 commit comments

Comments
 (0)