-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathgenerate_readme.py
More file actions
303 lines (265 loc) · 13.4 KB
/
Copy pathgenerate_readme.py
File metadata and controls
303 lines (265 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
import json
from pathlib import Path
from datetime import datetime, timezone
from typing import Dict, List, Optional
from config import DEVICE_ORDER, DEVICE_METADATA, REGION_MAPPING, OOS_MAPPING
import re
from hardcode_rules import is_hardcode_protected, version_sort_key
def load_history(file_path: Path) -> Dict:
"""Load history from a JSON file."""
try:
with open(file_path, 'r', encoding='utf-8') as f:
return json.load(f)
except FileNotFoundError:
return {}
def get_region_name(variant: str) -> str:
"""Map compact region codes to human-readable labels."""
return REGION_MAPPING.get(variant, variant)
def generate_device_section(device_id: str, device_name: str, history_data: Dict) -> List[str]:
"""Generate Markdown section for a specific device."""
lines = []
# Convert device_id to snake_case format for hardcode checking
device_id_mapped = OOS_MAPPING.get(device_id, device_id)
# Get available variants
variants = set()
if device_id in DEVICE_METADATA:
variants.update(DEVICE_METADATA[device_id]['models'].keys())
for key in history_data:
if key.startswith(f"{device_id}_"):
variants.add(key.replace(f"{device_id}_", ""))
# Determine region order based on device type
if device_name.startswith("Oppo"):
# Oppo devices use different regional codes
preferred_order = ['EU', 'SG', 'TW', 'MY', 'ID', 'TH', 'VN', 'APC', 'OCA', 'EG', 'SA', 'MX', 'CN']
else:
# OnePlus devices use standard regions
preferred_order = ['GLO', 'EU', 'IN', 'NA', 'VISIBLE', 'CN']
def sort_key(v):
try:
return preferred_order.index(v)
except ValueError:
return len(preferred_order)
sorted_variants = sorted(list(variants), key=sort_key)
has_data = False
rows = []
for variant in sorted_variants:
key = f"{device_id}_{variant}"
if key not in history_data:
continue
data = history_data[key]
current_entry = None
for entry in data.get('history', []):
if entry.get('status') == 'current':
current_entry = entry
break
if not current_entry and data.get('history'):
current_entry = data['history'][0]
if current_entry:
has_data = True
version = current_entry.get('version', 'Unknown')
arb = current_entry.get('arb', -1)
is_hardcoded = is_hardcode_protected(device_id_mapped, version)
# For hardcoded entries, show ? for ARB value (matching website)
display_arb = '?' if is_hardcoded else (arb if arb is not None and arb >= 0 else '?')
date = current_entry.get('last_checked', 'Unknown')
major = current_entry.get('major', '?')
minor = current_entry.get('minor', '?')
region_name = get_region_name(variant)
model = data.get('model', 'Unknown')
# Status icon and text (matching website badges)
if is_hardcoded:
safe_icon = "⚠️ Undetectable ARB"
elif arb == 0:
safe_icon = "✅ Safe"
elif isinstance(arb, int) and arb > 0:
safe_icon = "❌ Protected"
else:
safe_icon = "❓ Unknown"
# MD5 formating
md5 = current_entry.get('md5')
md5_str = ""
if md5:
md5_str = f"<br><details><summary>MD5</summary><code>{md5}</code></details>"
rows.append(f"| {region_name} | {model} | {version}{md5_str} | **{display_arb}** | Major: {major}, Minor: {minor} | {date} | {safe_icon} |")
if has_data:
lines.append(f"### {device_name}")
lines.append("")
lines.append("| Region | Model | Firmware Version | ARB Index | OEM Version | Last Checked | Safe |")
lines.append("|:---|:---|:---|:---|:---|:---|:---|")
lines.extend(rows)
lines.append("")
# Add History Section
history_lines = []
for variant in sorted_variants:
key = f"{device_id}_{variant}"
if key not in history_data:
continue
data = history_data[key]
# Filter out 'current' version from history to avoid redundancy
history_entries = [e for e in data.get('history', []) if e.get('status') != 'current']
# Sort history by firmware version descending (parse numeric parts for correct ordering)
history_entries.sort(key=lambda x: version_sort_key(x.get('version', '')), reverse=True)
if history_entries: # Only show history if there's actual old versions
region_name = get_region_name(variant)
history_lines.append(f"<details>")
history_lines.append(f"<summary>📜 <b>{region_name} History</b> (click to expand)</summary>")
history_lines.append("")
history_lines.append("| Firmware Version | ARB | OEM Version | Last Seen | Safe |")
history_lines.append("|:---|:---|:---|:---|:---|")
for entry in history_entries:
v = entry.get('version', 'Unknown')
a = entry.get('arb', -1)
hist_is_hardcoded = is_hardcode_protected(device_id_mapped, v)
# For hardcoded entries, show ? for ARB value (matching website)
display_a = '?' if hist_is_hardcoded else (a if a is not None and a >= 0 else '?')
maj = entry.get('major', '?')
min_ = entry.get('minor', '?')
ls = entry.get('last_checked', 'Unknown')
if hist_is_hardcoded:
s_icon = "⚠️ Undetectable ARB"
elif a == 0:
s_icon = "✅ Safe"
elif isinstance(a, int) and a > 0:
s_icon = "❌ Protected"
else:
s_icon = "❓ Unknown"
md5_hist = entry.get('md5')
md5_hist_str = ""
if md5_hist:
md5_hist_str = f"<br><details><summary>MD5</summary><code>{md5_hist}</code></details>"
history_lines.append(f"| {v}{md5_hist_str} | {display_a} | Major: {maj}, Minor: {min_} | {ls} | {s_icon} |")
history_lines.append("")
history_lines.append("</details>")
history_lines.append("")
if history_lines:
lines.extend(history_lines)
lines.append("")
return lines
def generate_readme(history_data: Dict) -> str:
"""Generate complete README content."""
lines = [
'# OnePlus Anti-Rollback (ARB) Checker',
'',
'<!-- Badges -->',
'',
'',
'',
'',
'',
'',
'---',
'',
'### 🎉 Thank You for 100 Stars! 🎉',
'A huge thank you to everyone who starred this repository! Your support, feedback, and contributions keep this project alive and growing. Stay awesome! 🚀',
'',
'---',
'',
'Automated ARB (Anti-Rollback) index tracker for OnePlus devices. This repository monitors firmware updates and tracks ARB changes over time.',
'',
'**🌐 ARB Info Website:** [https://oparb.pages.dev/](https://oparb.pages.dev/)',
'',
'## 🤖 OnePlus ARB Checker Bot',
'',
'Our Telegram bot allows you to check the Anti-Rollback (ARB) index of any OnePlus firmware instantly.',
'',
'- **Bot Username:** [@oparbcheckerbot](https://t.me/oparbcheckerbot)',
'- **Group:** [@oneplusarbchecker](https://t.me/oneplusarbchecker)',
'- **Supported Commands:**',
' - `/check <url>` - Analyze a firmware file (Direct Download Link required)',
' - `/download <device> [region]` - Fetch latest firmware & auto-check ARB',
' - `/devicestatus <device>` - Show current firmware & ARB info',
' - `/latest` - Show the 5 most recently discovered firmwares',
' - `/help` - Show usage instructions',
' - `/about` - Bot version and stats',
'',
'> **Note:** The bot **only** works within the [@oneplusarbchecker](https://t.me/oneplusarbchecker) group. DM checks are disabled. Checks are powered by GitHub Actions and may take a minute to process.',
'',
'### 🍻 Support the Project',
'If you find this tool helpful, consider buying me a beer! Your support keeps the updates coming.',
'',
'[](https://www.buymeacoffee.com/bartixxx32)',
'',
'## 📊 Current Status',
''
]
for device_id in DEVICE_ORDER:
if device_id not in DEVICE_METADATA:
continue
meta = DEVICE_METADATA[device_id]
device_name = meta['name']
device_lines = generate_device_section(device_id, device_name, history_data)
if device_lines:
lines.extend(device_lines)
lines.append('---')
lines.append('')
lines.extend([
'## 🤖 On-Demand ARB Checker',
'',
'You can check the ARB index of any OnePlus Ozip/Zip URL manually using our automated workflow.',
'',
'### How to use:',
'1. Go to the [Issues Tab](https://github.com/Bartixxx32/OnePlus-antirollchecker/issues).',
'2. Click **"New Issue"**.',
'3. Set the **Title** to start with `[CHECK]` (e.g., `[CHECK] OnePlus 12 Update`).',
'4. Paste the **Firmware Download URL** (direct link ending in `.zip`) in the description.',
'5. Click **"Submit New Issue"**.',
'',
'The bot will automatically pick up the request, analyze the firmware, and post the results as a comment on your issue.',
'',
'---',
'',
])
lines.extend([
'## 🌐 OOS Downloader API',
'',
'Need direct download URLs for OnePlus firmware? Use our **OOS Downloader API**!',
'',
'🌐 **API Endpoint**: [https://oosdownloader-gui.fly.dev/](https://oosdownloader-gui.fly.dev/)',
'',
'Our OOS Downloader API provides direct, signed download URLs for OnePlus OTA firmware files by leveraging the [OS Updater API](https://play.google.com/store/apps/details?id=com.arjanvlek.oxygenupdater).',
'',
'---',
''
])
lines.extend([
'## Credits',
'',
'- **Payload Extraction**: [otaripper](https://github.com/syedinsaf/otaripper) by syedinsaf',
'- **Payload Extraction (Fallback)**: [payload-dumper-go](https://github.com/ssut/payload-dumper-go) by ssut',
'- **ARB Extraction**: [arbextract](https://github.com/koaaN/arbextract) by koaaN',
'- **API for CN variants**: [roms.danielspringer.at](https://roms.danielspringer.at/) by Daniel Springer',
'- **Firmware API**: [OS Updater](https://play.google.com/store/apps/details?id=com.arjanvlek.oxygenupdater)',
'',
'---',
'',
])
lines.extend([
'## 📱 Android App',
'',
'Prefer a native mobile experience? We have an official Android app on F-Droid! Check firmware statuses, view ARB indices, and stay protected directly from your phone.',
'',
'[<img src="https://f-droid.org/badge/get-it-on.png"',
' alt="Get it on F-Droid"',
' height="80">](https://f-droid.org/packages/com.bartixxx.oneplusarbchecker/)',
'',
'## 💬 Community & Support',
'',
'- **Telegram Group:** [@oneplusarbchecker](https://t.me/oneplusarbchecker)',
'',
'> **Important:** The bot **only** works within this group to prevent spam and ensure availability. DM checks are disabled.',
'',
'---',
f'*Last updated: {datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")}*'
])
return "\n".join(lines)
if __name__ == "__main__":
history_dir = Path("data/history")
if not history_dir.exists():
exit(0)
all_history = {}
for f in history_dir.glob("*.json"):
all_history[f.stem] = load_history(f)
content = generate_readme(all_history)
with open("README.md", "w", encoding="utf-8") as f:
f.write(content)
print("README.md generated successfully")