-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAirFirmwareDownloader.py
207 lines (175 loc) · 9.23 KB
/
AirFirmwareDownloader.py
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
import hashlib
import requests
import os
import json
from tqdm import tqdm
from colorama import Fore, Style, init
init(autoreset=True)
ASCII_ART = r"""
_ _ _____ _ ____ _
/ \ (_)_ __| ___(_)_ __ _ __ _____ ____ _ _ __ ___| _ \| |
/ _ \ | | '__| |_ | | '__| '_ ` _ \ \ /\ / / _` | '__/ _ \ | | | |
/ ___ \| | | | _| | | | | | | | | \ V V / (_| | | | __/ |_| | |___
/_/ \_\_|_| |_| |_|_| |_| |_| |_|\_/\_/ \__,_|_| \___|____/|_____|
"""
EARPHONE_MODELS = {
"1": {
"name": "V5.2 TB",
"base_url": "http://twsfota.198509.xyz/tws_fota_bin/S505/AB1562AE/S505_cc%20ultra_AB1562AE_V310.6.505.",
"versions": {
'153': 'Version 153 is available.',
'152': 'Version 152 is available.',
'135': 'Version 135 is available.',
'133': 'Version 133 is available.'
},
"url_format": lambda version: f"http://twsfota.198509.xyz/tws_fota_bin/S505/AB1562AE/S505_cc%20ultra_AB1562AE_V310.6.505.{version}_fota/S505_cc%20ultra_AB1562AE_V310.6.505.{version}_{{side}}_FotaPackage.bin"
},
"2": {
"name": "V4.9 TB",
"base_url": "http://twsfota.198509.xyz/tws_fota_bin/S305/AB1562AE/",
"versions": {
'162': 'Version 162 is available.'
},
"url_format": lambda version: f"http://twsfota.198509.xyz/tws_fota_bin/S305/AB1562AE/S305_cc%20ultra_AB1562AE_V31.6.305.{version}_fota/S305_cc%20ultra_AB1562AE_V31.6.305.{version}_{{side}}_FotaPackage.bin"
},
"3": {
"name": "V1E",
"base_url": "http://twsfota.198509.xyz/tws_fota_bin/S45/AB1562E/",
"versions": {
'144': 'Version 144 is available.'
},
"url_format": lambda version: f"http://twsfota.198509.xyz/tws_fota_bin/S45/AB1562E/S45_cc%20ultra_AB1562E_ENC_V31.6.45.{version}_fota/S45_cc%20ultra_AB1562E_ENC_V31.6.45.{version}_{{side}}_FotaPackage.bin"
}
}
def print_ascii_welcome():
"""Print ASCII art and a welcome message."""
print(Fore.CYAN + ASCII_ART)
print(Fore.BLUE + Style.BRIGHT + "=" * 50)
def calculate_sha256(file_path):
"""Calculate SHA-256 checksum of a file."""
sha256 = hashlib.sha256()
with open(file_path, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
sha256.update(chunk)
return sha256.hexdigest()
def download_file(url, file_path, version):
"""Download a file from a URL with a progress bar."""
try:
response = requests.get(url, stream=True)
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
if total_size == 0:
print(Fore.RED + Style.BRIGHT + f"Cannot determine size of the file from URL: {url}")
return False
short_name = f"V{version}"
with tqdm(total=total_size, unit='B', unit_scale=True, unit_divisor=1024,
desc=short_name, bar_format='{l_bar}{bar} | {n_fmt}/{total_fmt}',
colour='cyan') as bar:
with open(file_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
file.write(chunk)
bar.update(len(chunk))
return True
except requests.exceptions.HTTPError as e:
print(Fore.RED + Style.BRIGHT + f"Error downloading file from {url}: {e}")
except Exception as e:
print(Fore.RED + Style.BRIGHT + f"An unexpected error occurred: {e}")
return False
def load_checksums(json_file):
"""Load checksums from a JSON file."""
with open(json_file, 'r') as f:
return json.load(f)
def compare_checksums(model_name, version, left_sha256, right_sha256, checksums):
"""Compare calculated checksums with expected checksums."""
expected = checksums.get(model_name, {}).get(str(version), {"left": None, "right": None})
return {
"left_file_checksum": left_sha256,
"right_file_checksum": right_sha256,
"left_match": left_sha256.lower() == expected.get("left", "").lower() if expected.get("left") else None,
"right_match": right_sha256.lower() == expected.get("right", "").lower() if expected.get("right") else None
}
def print_comparison_results(results):
"""Print comparison results in a formatted manner."""
print(Fore.GREEN + Style.BRIGHT + "\nChecksum Comparison Results:")
print(Fore.GREEN + Style.BRIGHT + "=" * 50)
print(Fore.GREEN + Style.BRIGHT + f"Left file checksum: {results['left_file_checksum']}")
print(Fore.GREEN + Style.BRIGHT + f"Right file checksum: {results['right_file_checksum']}")
print(Fore.GREEN + Style.BRIGHT + f"Left file match: {get_match_result(results['left_match'])}")
print(Fore.GREEN + Style.BRIGHT + f"Right file match: {get_match_result(results['right_match'])}")
print(Fore.GREEN + Style.BRIGHT + "=" * 50)
def get_match_result(match):
if match is True:
return 'Match'
elif match is False:
return 'No match'
else:
return 'Not available in checksums.json'
def construct_file_path(model, version, file_type):
"""Construct the file path for the given model, version and file type."""
return os.path.join(
os.getcwd(),
f"{model['name']}_{version}",
os.path.basename(model['url_format'](version).format(side=file_type))
)
def main():
"""Main function to run the program."""
print_ascii_welcome()
checksums = load_checksums('checksums.json')
while True:
try:
print(Fore.YELLOW + Style.BRIGHT + "Available Earphone Models:")
for number, model in EARPHONE_MODELS.items():
print(Fore.GREEN + Style.BRIGHT + f"{number}. {model['name']}")
model_input = input(Fore.YELLOW + Style.BRIGHT + "\nEnter the number of the earphone model: ").strip()
if model_input not in EARPHONE_MODELS:
print(Fore.RED + Style.BRIGHT + "Invalid model number provided. Please try again.")
continue
model = EARPHONE_MODELS[model_input]
available_versions = model['versions']
version_input = input(Fore.YELLOW + Style.BRIGHT + f"Enter the firmware version for {model['name']} (e.g., {next(iter(available_versions))}), or press Enter to display available versions: ").strip()
if not version_input:
print(Fore.YELLOW + Style.BRIGHT + f"\nAvailable Versions for {model['name']}:")
for v in sorted(available_versions.keys(), reverse=True):
print(Fore.GREEN + Style.BRIGHT + f"{available_versions[v]}")
version_input = input(Fore.YELLOW + Style.BRIGHT + f"\nPlease enter the firmware version you want to download for {model['name']}: ").strip()
if not version_input or version_input not in available_versions:
print(Fore.RED + Style.BRIGHT + "Invalid version provided. Exiting...")
return
version = version_input
version_folder = os.path.join(os.getcwd(), f"{model['name']}_{version}")
left_file_path = construct_file_path(model, version, "left")
right_file_path = construct_file_path(model, version, "right")
if os.path.exists(version_folder) and os.path.isfile(left_file_path) and os.path.isfile(right_file_path):
print(Fore.GREEN + Style.BRIGHT + f"Version {version} for {model['name']} is already downloaded.")
left_sha256 = calculate_sha256(left_file_path)
right_sha256 = calculate_sha256(right_file_path)
results = compare_checksums(model['name'], version, left_sha256, right_sha256, checksums)
print_comparison_results(results)
break
os.makedirs(version_folder, exist_ok=True)
left_file_url = model['url_format'](version).format(side="left")
right_file_url = model['url_format'](version).format(side="right")
print(Fore.CYAN + Style.BRIGHT + f"Downloading files for {model['name']} version {version}...")
left_downloaded = download_file(left_file_url, left_file_path, version)
right_downloaded = download_file(right_file_url, right_file_path, version)
if left_downloaded and right_downloaded:
print(Fore.GREEN + Style.BRIGHT + "\nFiles downloaded successfully!")
left_sha256 = calculate_sha256(left_file_path)
right_sha256 = calculate_sha256(right_file_path)
results = compare_checksums(model['name'], version, left_sha256, right_sha256, checksums)
print_comparison_results(results)
else:
print(Fore.RED + Style.BRIGHT + "Failed to download one or both files.")
break
except KeyboardInterrupt:
print(Fore.RED + Style.BRIGHT + "\nProcess interrupted by user.")
return
except Exception as e:
print(Fore.RED + Style.BRIGHT + f"An unexpected error occurred: {str(e)}")
import traceback
print(Fore.RED + Style.BRIGHT + "Error traceback:")
print(traceback.format_exc())
return
if __name__ == "__main__":
main()