forked from corpnewt/gibMacOS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgibMacOS.command
284 lines (266 loc) · 11.6 KB
/
gibMacOS.command
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
#!/usr/bin/python
from Scripts import *
import os, datetime, shutil, time, sys, argparse
class gibMacOS:
def __init__(self):
self.d = downloader.Downloader()
self.u = utils.Utils("gibMacOS")
self.catalog_suffix = {
"public" : "beta",
"publicrelease" : "",
"customer" : "customerseed",
"developer" : "seed"
}
self.current_macos = 14
self.min_macos = 5
self.mac_os_names_url = {
"8" : "mountainlion",
"7" : "lion",
"6" : "snowleopard",
"5" : "leopard"
}
self.current_catalog = "publicrelease"
self.catalog_data = None
self.scripts = "Scripts"
self.plist = "cat.plist"
self.saves = "macOS Downloads"
self.save_local = False
if not self.get_catalog_data(self.save_local):
self.u.head("Catalog Data Error")
print("")
print("The currently selected catalog ({}) was not reachable".format(self.current_catalog))
if self.save_local:
print("and I was unable to locate a valid {} file in the\n{} directory.".format(self.plist, self.scripts))
print("Please ensure you have a working internet connection.")
print("")
self.u.grab("Press [enter] to exit...")
self.mac_prods = self.get_dict_for_prods(self.get_installers())
def set_catalog(self, catalog):
self.current_catalog = catalog.lower() if catalog.lower() in self.catalog_suffix else "publicrelease"
def build_url(self, **kwargs):
catalog = kwargs.get("catalog", self.current_catalog).lower()
catalog = catalog if catalog.lower() in self.catalog_suffix else "publicrelease"
version = int(kwargs.get("version", self.current_macos))
url = "https://swscan.apple.com/content/catalogs/others/index-"
url += "-".join([self.mac_os_names_url[str(x)] if str(x) in self.mac_os_names_url else "10."+str(x) for x in reversed(range(self.min_macos, version+1))])
url += ".merged-1.sucatalog"
ver_s = self.mac_os_names_url[str(version)] if str(version) in self.mac_os_names_url else "10."+str(version)
url = url.replace(ver_s, ver_s+self.catalog_suffix[catalog])
return url
def get_catalog_data(self, local = False):
# Gets the data based on our current_catalog
url = self.build_url(catalog=self.current_catalog, version=self.current_macos)
self.u.head("Downloading Catalog")
print("")
print("Currently downloading {} catalog from\n\n{}\n".format(self.current_catalog, url))
try:
b = self.d.get_bytes(url)
self.catalog_data = plist.loads(b)
# Assume it's valid data - dump it to a local file
if local:
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(__file__)))
with open(os.path.join(os.getcwd(), self.scripts, self.plist), "wb") as f:
plist.dump(self.catalog_data, f)
os.chdir(cwd)
except:
if local:
# Check if we have one locally in our scripts directory
if not os.path.exists(os.path.join(os.path.dirname(os.path.realpath(__file__)), self.scripts, self.plist)):
return False
# It does - try to load it
try:
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(__file__)))
with open(os.path.join(os.getcwd(), self.scripts, self.plist), "rb") as f:
self.catalog_data = plist.load(f)
os.chdir(cwd)
except:
return False
return True
def get_installers(self, plist_dict = None):
if not plist_dict:
plist_dict = self.catalog_data
if not plist_dict:
return []
mac_prods = []
for p in plist_dict.get("Products", {}):
if plist_dict.get("Products",{}).get(p,{}).get("ExtendedMetaInfo",{}).get("InstallAssistantPackageIdentifiers",{}).get("OSInstall",{}) == "com.apple.mpkg.OSInstall":
mac_prods.append(p)
return mac_prods
def get_dict_for_prods(self, prods, plist_dict = None):
if plist_dict==self.catalog_data==None:
plist_dict = {}
else:
plist_dict = self.catalog_data if plist_dict == None else plist_dict
prod_list = []
for prod in prods:
# Grab the ServerMetadataURL for the passed product key if it exists
prodd = {"product":prod}
try:
b = self.d.get_bytes(plist_dict.get("Products",{}).get(prod,{}).get("ServerMetadataURL",""), False)
smd = plist.loads(b)
except:
smd = {}
# Populate some info!
prodd["date"] = plist_dict.get("Products",{}).get(prod,{}).get("PostDate","")
prodd["time"] = time.mktime(prodd["date"].timetuple()) + prodd["date"].microsecond / 1E6
prodd["title"] = smd.get("localization",{}).get("English",{}).get("title","Unknown")
prodd["version"] = smd.get("CFBundleShortVersionString","Unknown")
# Try to get the description too
try:
desc = smd.get("localization",{}).get("English",{}).get("description","").decode("utf-8")
desctext = desc.split('"p1">')[1].split("</a>")[0]
except:
desctext = None
prodd["description"] = desctext
# Iterate the available packages and save their urls and sizes
prodd["packages"] = plist_dict.get("Products",{}).get(prod,{}).get("Packages",{})
prod_list.append(prodd)
# Sort by newest
prod_list = sorted(prod_list, key=lambda x:x["time"], reverse=True)
return prod_list
def download_prod(self, prod, dmg = False):
# Takes a dictonary of details and downloads it
cwd = os.getcwd()
os.chdir(os.path.dirname(os.path.realpath(__file__)))
name = "{} - {} {}".format(prod["product"], prod["version"], prod["title"])
if os.path.exists(os.path.join(os.getcwd(), self.saves, self.current_catalog, name)):
while True:
self.u.head("Already Exists")
print("")
print("It looks like you've already downloaded {}".format(name))
print("")
menu = self.u.grab("Redownload? (y/n): ")
if not len(menu):
continue
if menu[0].lower() == "n":
return
if menu[0].lower() == "y":
break
# Remove the old copy, then re-download
shutil.rmtree(os.path.join(os.getcwd(), self.saves, self.current_catalog, name))
# Make it new
os.makedirs(os.path.join(os.getcwd(), self.saves, self.current_catalog, name))
dl_list = []
for x in prod["packages"]:
if not x.get("URL",None):
continue
if dmg and not x.get("URL","").lower().endswith(".dmg"):
continue
# add it to the list
dl_list.append(x["URL"])
if not len(dl_list):
self.u.head("Error")
print("")
print("There were no files to download")
print("")
self.u.grab("Press [enter] to return...")
return
c = 0
failed = []
succeeded = []
for x in dl_list:
c += 1
self.u.head("Downloading File {} of {}".format(c, len(dl_list)))
print("")
if dmg:
print("NOTE: Only Downloading DMG Files")
print("")
print("Downloading {} for {}...".format(os.path.basename(x), name))
print("")
try:
self.d.stream_to_file(x, os.path.join(os.getcwd(), self.saves, self.current_catalog, name, os.path.basename(x)))
succeeded.append(os.path.basename(x))
except:
failed.append(os.path.basename(x))
self.u.head("Downloaded {} of {}".format(len(succeeded), len(dl_list)))
print("")
print("Succeeded:")
if len(succeeded):
for x in succeeded:
print(" {}".format(x))
else:
print(" None")
print("")
print("Failed:")
if len(failed):
for x in failed:
print(" {}".format(x))
else:
print(" None")
print("")
self.u.grab("Press [enter] to return...")
def main(self, dmg = False):
self.u.head()
print("")
print("Available Products:")
print("")
num = 0
if not len(self.mac_prods):
print("No installers in catalog!")
print("")
exit()
for p in self.mac_prods:
num += 1
print("{}. {} {}\n - Added {}".format(num, p["version"], p["title"], p["date"]))
print("")
print("Q. Quit")
print("")
menu = self.u.grab("Please select an option: ")
if not len(menu):
return
if menu[0].lower() == "q":
self.u.custom_quit()
# Assume we picked something
try:
menu = int(menu)
except:
return
if menu < 1 or menu > len(self.mac_prods):
return
self.download_prod(self.mac_prods[menu-1], dmg)
def get_latest(self, dmg = False):
self.u.head("Downloading Latest")
print("")
self.download_prod(self.mac_prods[-1], dmg)
def get_for_product(self, prod, dmg = False):
self.u.head("Downloading for {}".format(prod))
print("")
for p in self.mac_prods:
if p["product"] == prod:
self.download_prod(p, dmg)
return
print("{} not found".format(prod))
def get_for_version(self, vers, dmg = False):
self.u.head("Downloading for {}".format(vers))
print("")
for p in self.mac_prods:
if p["version"] == vers:
self.download_prod(p, dmg)
return
print("10.{} not found".format(vers))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-l", "--latest", help="downloads the version avaialble in the current catalog (overrides --version and --product)", action="store_true")
parser.add_argument("-d", "--dmg", help="downloads only the .dmg files", action="store_true")
parser.add_argument("-c", "--catalog", help="sets the CATALOG to use - publicrelease, public, customer, developer")
parser.add_argument("-p", "--product", help="sets the product id to search for (overrides --version)")
parser.add_argument("-v", "--version", help="sets the version of macOS to target - eg 10.14")
args = parser.parse_args()
g = gibMacOS()
if args.catalog:
# Set the catalog
g.set_catalog(args.catalog)
if args.latest:
g.get_latest(args.dmg)
exit()
if args.product:
g.get_for_product(args.product, args.dmg)
exit()
if args.version:
g.get_for_version(args.version, args.dmg)
exit()
print("main")
while True:
g.main(args.dmg)