mirror of
https://github.com/corpnewt/gibMacOS.git
synced 2024-12-04 13:33:26 +01:00
Add files via upload
This commit is contained in:
parent
da6d8aa8d6
commit
a76e237a46
4
Scripts/__init__.py
Normal file
4
Scripts/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from os.path import dirname, basename, isfile
|
||||
import glob
|
||||
modules = glob.glob(dirname(__file__)+"/*.py")
|
||||
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')]
|
79
Scripts/downloader.py
Normal file
79
Scripts/downloader.py
Normal file
@ -0,0 +1,79 @@
|
||||
import sys, os, time
|
||||
# Python-aware urllib stuff
|
||||
if sys.version_info >= (3, 0):
|
||||
from urllib.request import urlopen
|
||||
else:
|
||||
from urllib2 import urlopen
|
||||
|
||||
class Downloader:
|
||||
|
||||
def __init__(self):
|
||||
return
|
||||
|
||||
def _progress_hook(self, response, bytes_so_far, total_size):
|
||||
if total_size > 0:
|
||||
percent = float(bytes_so_far) / total_size
|
||||
percent = round(percent*100, 2)
|
||||
sys.stdout.write("Downloaded {:,} of {:,} bytes ({:.2f}%)\r".format(bytes_so_far, total_size, percent))
|
||||
else:
|
||||
sys.stdout.write("Downloaded {:,} bytes\r".format(bytes_so_far))
|
||||
|
||||
def get_string(self, url, progress = True):
|
||||
response = urlopen(url)
|
||||
CHUNK = 16 * 1024
|
||||
bytes_so_far = 0
|
||||
try:
|
||||
total_size = int(response.headers['Content-Length'])
|
||||
except:
|
||||
total_size = -1
|
||||
chunk_so_far = "".encode("utf-8")
|
||||
while True:
|
||||
chunk = response.read(CHUNK)
|
||||
bytes_so_far += len(chunk)
|
||||
if progress:
|
||||
self._progress_hook(response, bytes_so_far, total_size)
|
||||
if not chunk:
|
||||
break
|
||||
chunk_so_far += chunk
|
||||
return chunk_so_far.decode("utf-8")
|
||||
|
||||
def get_bytes(self, url, progress = True):
|
||||
response = urlopen(url)
|
||||
CHUNK = 16 * 1024
|
||||
bytes_so_far = 0
|
||||
try:
|
||||
total_size = int(response.headers['Content-Length'])
|
||||
except:
|
||||
total_size = -1
|
||||
chunk_so_far = "".encode("utf-8")
|
||||
while True:
|
||||
chunk = response.read(CHUNK)
|
||||
bytes_so_far += len(chunk)
|
||||
if progress:
|
||||
self._progress_hook(response, bytes_so_far, total_size)
|
||||
if not chunk:
|
||||
break
|
||||
chunk_so_far += chunk
|
||||
return chunk_so_far
|
||||
|
||||
def stream_to_file(self, url, file, progress = True):
|
||||
response = urlopen(url)
|
||||
CHUNK = 16 * 1024
|
||||
bytes_so_far = 0
|
||||
try:
|
||||
total_size = int(response.headers['Content-Length'])
|
||||
except:
|
||||
total_size = -1
|
||||
with open(file, 'wb') as f:
|
||||
while True:
|
||||
chunk = response.read(CHUNK)
|
||||
bytes_so_far += len(chunk)
|
||||
if progress:
|
||||
self._progress_hook(response, bytes_so_far, total_size)
|
||||
if not chunk:
|
||||
break
|
||||
f.write(chunk)
|
||||
if os.path.exists(file):
|
||||
return file
|
||||
else:
|
||||
return None
|
182
Scripts/plist.py
Normal file
182
Scripts/plist.py
Normal file
@ -0,0 +1,182 @@
|
||||
### ###
|
||||
# Imports #
|
||||
### ###
|
||||
|
||||
import datetime
|
||||
from io import BytesIO
|
||||
import os
|
||||
import plistlib
|
||||
import struct
|
||||
import sys
|
||||
|
||||
try:
|
||||
FMT_XML = plistlib.FMT_XML
|
||||
except:
|
||||
FMT_XML = None
|
||||
|
||||
### ###
|
||||
# Helper Methods #
|
||||
### ###
|
||||
|
||||
def _check_py3():
|
||||
return True if sys.version_info >= (3, 0) else False
|
||||
|
||||
def _is_binary(fp):
|
||||
header = fp.read(32)
|
||||
fp.seek(0)
|
||||
return header[:8] == b'bplist00'
|
||||
|
||||
def _get_inst():
|
||||
if _check_py3():
|
||||
return (str)
|
||||
else:
|
||||
return (str, unicode)
|
||||
|
||||
### ###
|
||||
# Deprecated Functions - Remapped #
|
||||
### ###
|
||||
|
||||
def readPlist(pathOrFile):
|
||||
if not isinstance(pathOrFile, _get_inst()):
|
||||
return load(pathOrFile)
|
||||
with open(pathOrFile, "rb") as f:
|
||||
return load(f)
|
||||
|
||||
def writePlist(value, pathOrFile):
|
||||
if not isinstance(pathOrFile, _get_inst()):
|
||||
return dump(value, pathOrFile, fmt=FMT_XML, sort_keys=True, skipkeys=False)
|
||||
with open(pathOrFile, "wb") as f:
|
||||
return dump(value, f, fmt=FMT_XML, sort_keys=True, skipkeys=False)
|
||||
|
||||
### ###
|
||||
# Remapped Functions #
|
||||
### ###
|
||||
|
||||
def load(fp, fmt=None, use_builtin_types=True, dict_type=dict):
|
||||
if _check_py3():
|
||||
return plistlib.load(fp, fmt=fmt, use_builtin_types=use_builtin_types, dict_type=dict_type)
|
||||
elif not _is_binary(fp):
|
||||
return plistlib.readPlist(fp)
|
||||
else:
|
||||
return readBinaryPlistFile(fp)
|
||||
|
||||
def loads(value, fmt=None, use_builtin_types=True, dict_type=dict):
|
||||
if isinstance(value, _get_inst()):
|
||||
# We were sent a string - let's encode it to some utf-8 bytes for fun!
|
||||
value = value.encode("utf-8")
|
||||
fp = BytesIO(value)
|
||||
if _check_py3():
|
||||
return plistlib.load(fp, fmt=fmt, use_builtin_types=use_builtin_types, dict_type=dict_type)
|
||||
elif not _is_binary(fp):
|
||||
return plistlib.readPlistFromString(value)
|
||||
else:
|
||||
return readBinaryPlistFile(fp)
|
||||
|
||||
def dump(value, fp, fmt=FMT_XML, sort_keys=True, skipkeys=False):
|
||||
if _check_py3():
|
||||
plistlib.dump(value, fp, fmt=fmt, sort_keys=sort_keys, skipkeys=skipkeys)
|
||||
else:
|
||||
plistlib.writePlist(value, fp)
|
||||
|
||||
def dumps(value, fmt=FMT_XML, skipkeys=False):
|
||||
if _check_py3():
|
||||
return plistlib.dumps(value, fmt=fmt, skipkeys=skipkeys).encode("utf-8")
|
||||
else:
|
||||
return plistlib.writePlistToString(value).encode("utf-8")
|
||||
|
||||
|
||||
### ###
|
||||
# Binary Plist Stuff For Py2 #
|
||||
### ###
|
||||
|
||||
# timestamp 0 of binary plists corresponds to 1/1/2001 (year of Mac OS X 10.0), instead of 1/1/1970.
|
||||
MAC_OS_X_TIME_OFFSET = (31 * 365 + 8) * 86400
|
||||
|
||||
class InvalidFileException(ValueError):
|
||||
def __str__(self):
|
||||
return "Invalid file"
|
||||
def __unicode__(self):
|
||||
return "Invalid file"
|
||||
|
||||
def readBinaryPlistFile(in_file):
|
||||
"""
|
||||
Read a binary plist file, following the description of the binary format: http://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c
|
||||
Raise InvalidFileException in case of error, otherwise return the root object, as usual
|
||||
|
||||
Original patch diffed here: https://bugs.python.org/issue14455
|
||||
"""
|
||||
in_file.seek(-32, os.SEEK_END)
|
||||
trailer = in_file.read(32)
|
||||
if len(trailer) != 32:
|
||||
return InvalidFileException()
|
||||
offset_size, ref_size, num_objects, top_object, offset_table_offset = struct.unpack('>6xBB4xL4xL4xL', trailer)
|
||||
in_file.seek(offset_table_offset)
|
||||
object_offsets = []
|
||||
offset_format = '>' + {1: 'B', 2: 'H', 4: 'L', 8: 'Q', }[offset_size] * num_objects
|
||||
ref_format = {1: 'B', 2: 'H', 4: 'L', 8: 'Q', }[ref_size]
|
||||
int_format = {0: (1, '>B'), 1: (2, '>H'), 2: (4, '>L'), 3: (8, '>Q'), }
|
||||
object_offsets = struct.unpack(offset_format, in_file.read(offset_size * num_objects))
|
||||
def getSize(token_l):
|
||||
""" return the size of the next object."""
|
||||
if token_l == 0xF:
|
||||
m = ord(in_file.read(1)) & 0x3
|
||||
s, f = int_format[m]
|
||||
return struct.unpack(f, in_file.read(s))[0]
|
||||
return token_l
|
||||
def readNextObject(offset):
|
||||
""" read the object at offset. May recursively read sub-objects (content of an array/dict/set) """
|
||||
in_file.seek(offset)
|
||||
token = in_file.read(1)
|
||||
token_h, token_l = ord(token) & 0xF0, ord(token) & 0x0F #high and low parts
|
||||
if token == '\x00':
|
||||
return None
|
||||
elif token == '\x08':
|
||||
return False
|
||||
elif token == '\x09':
|
||||
return True
|
||||
elif token == '\x0f':
|
||||
return ''
|
||||
elif token_h == 0x10: #int
|
||||
result = 0
|
||||
for k in xrange((2 << token_l) - 1):
|
||||
result = (result << 8) + ord(in_file.read(1))
|
||||
return result
|
||||
elif token_h == 0x20: #real
|
||||
if token_l == 2:
|
||||
return struct.unpack('>f', in_file.read(4))[0]
|
||||
elif token_l == 3:
|
||||
return struct.unpack('>d', in_file.read(8))[0]
|
||||
elif token_h == 0x30: #date
|
||||
f = struct.unpack('>d', in_file.read(8))[0]
|
||||
return datetime.datetime.utcfromtimestamp(f + MAC_OS_X_TIME_OFFSET)
|
||||
elif token_h == 0x80: #data
|
||||
s = getSize(token_l)
|
||||
return in_file.read(s)
|
||||
elif token_h == 0x50: #ascii string
|
||||
s = getSize(token_l)
|
||||
return in_file.read(s)
|
||||
elif token_h == 0x60: #unicode string
|
||||
s = getSize(token_l)
|
||||
return in_file.read(s * 2).decode('utf-16be')
|
||||
elif token_h == 0x80: #uid
|
||||
return in_file.read(token_l + 1)
|
||||
elif token_h == 0xA0: #array
|
||||
s = getSize(token_l)
|
||||
obj_refs = struct.unpack('>' + ref_format * s, in_file.read(s * ref_size))
|
||||
return map(lambda x: readNextObject(object_offsets[x]), obj_refs)
|
||||
elif token_h == 0xC0: #set
|
||||
s = getSize(token_l)
|
||||
obj_refs = struct.unpack('>' + ref_format * s, in_file.read(s * ref_size))
|
||||
return set(map(lambda x: readNextObject(object_offsets[x]), obj_refs))
|
||||
elif token_h == 0xD0: #dict
|
||||
result = {}
|
||||
s = getSize(token_l)
|
||||
key_refs = struct.unpack('>' + ref_format * s, in_file.read(s * ref_size))
|
||||
obj_refs = struct.unpack('>' + ref_format * s, in_file.read(s * ref_size))
|
||||
for k, o in zip(key_refs, obj_refs):
|
||||
key = readNextObject(object_offsets[k])
|
||||
obj = readNextObject(object_offsets[o])
|
||||
result[key] = obj
|
||||
return result
|
||||
raise InvalidFileException()
|
||||
return readNextObject(object_offsets[top_object])
|
272
Scripts/utils.py
Normal file
272
Scripts/utils.py
Normal file
@ -0,0 +1,272 @@
|
||||
import sys, os, time, re, json, datetime, ctypes, subprocess
|
||||
|
||||
if os.name == "nt":
|
||||
# Windows
|
||||
import msvcrt
|
||||
else:
|
||||
# Not Windows \o/
|
||||
import select
|
||||
|
||||
class Utils:
|
||||
|
||||
def __init__(self, name = "Python Script"):
|
||||
self.name = name
|
||||
# Init our colors before we need to print anything
|
||||
cwd = os.getcwd()
|
||||
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
||||
if os.path.exists("colors.json"):
|
||||
self.colors_dict = json.load(open("colors.json"))
|
||||
else:
|
||||
self.colors_dict = {}
|
||||
os.chdir(cwd)
|
||||
|
||||
def check_admin(self):
|
||||
# Returns whether or not we're admin
|
||||
try:
|
||||
is_admin = os.getuid() == 0
|
||||
except AttributeError:
|
||||
is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
|
||||
return is_admin
|
||||
|
||||
def elevate(self, file):
|
||||
# Runs the passed file as admin
|
||||
if self.check_admin():
|
||||
return
|
||||
if os.name == "nt":
|
||||
ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, file, None, 1)
|
||||
else:
|
||||
try:
|
||||
p = subprocess.Popen(["which", "sudo"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
c = p.communicate()[0].decode("utf-8", "ignore").replace("\n", "")
|
||||
os.execv(c, [ sys.executable, 'python'] + sys.argv)
|
||||
except:
|
||||
exit(1)
|
||||
|
||||
def compare_versions(self, vers1, vers2, **kwargs):
|
||||
# Helper method to compare ##.## strings
|
||||
#
|
||||
# vers1 < vers2 = True
|
||||
# vers1 = vers2 = None
|
||||
# vers1 > vers2 = False
|
||||
|
||||
# Sanitize the pads
|
||||
pad = str(kwargs.get("pad", ""))
|
||||
sep = str(kwargs.get("separator", "."))
|
||||
|
||||
ignore_case = kwargs.get("ignore_case", True)
|
||||
|
||||
# Cast as strings
|
||||
vers1 = str(vers1)
|
||||
vers2 = str(vers2)
|
||||
|
||||
if ignore_case:
|
||||
vers1 = vers1.lower()
|
||||
vers2 = vers2.lower()
|
||||
|
||||
# Split and pad lists
|
||||
v1_parts, v2_parts = self.pad_length(vers1.split(sep), vers2.split(sep))
|
||||
|
||||
# Iterate and compare
|
||||
for i in range(len(v1_parts)):
|
||||
# Remove non-numeric
|
||||
v1 = ''.join(c.lower() for c in v1_parts[i] if c.isalnum())
|
||||
v2 = ''.join(c.lower() for c in v2_parts[i] if c.isalnum())
|
||||
# Equalize the lengths
|
||||
v1, v2 = self.pad_length(v1, v2)
|
||||
# Compare
|
||||
if str(v1) < str(v2):
|
||||
return True
|
||||
elif str(v1) > str(v2):
|
||||
return False
|
||||
# Never differed - return None, must be equal
|
||||
return None
|
||||
|
||||
def pad_length(self, var1, var2, pad = "0"):
|
||||
# Pads the vars on the left side to make them equal length
|
||||
pad = "0" if len(str(pad)) < 1 else str(pad)[0]
|
||||
if not type(var1) == type(var2):
|
||||
# Type mismatch! Just return what we got
|
||||
return (var1, var2)
|
||||
if len(var1) < len(var2):
|
||||
if type(var1) is list:
|
||||
var1.extend([str(pad) for x in range(len(var2) - len(var1))])
|
||||
else:
|
||||
var1 = "{}{}".format((pad*(len(var2)-len(var1))), var1)
|
||||
elif len(var2) < len(var1):
|
||||
if type(var2) is list:
|
||||
var2.extend([str(pad) for x in range(len(var1) - len(var2))])
|
||||
else:
|
||||
var2 = "{}{}".format((pad*(len(var1)-len(var2))), var2)
|
||||
return (var1, var2)
|
||||
|
||||
def check_path(self, path):
|
||||
# Loop until we either get a working path - or no changes
|
||||
count = 0
|
||||
while count < 100:
|
||||
count += 1
|
||||
if not len(path):
|
||||
# We uh.. stripped out everything - bail
|
||||
return None
|
||||
if os.path.exists(path):
|
||||
# Exists!
|
||||
return os.path.abspath(path)
|
||||
# Check quotes first
|
||||
if (path[0] == '"' and path[-1] == '"') or (path[0] == "'" and path[-1] == "'"):
|
||||
path = path[1:-1]
|
||||
continue
|
||||
# Check for tilde
|
||||
if path[0] == "~":
|
||||
test_path = os.path.expanduser(path)
|
||||
if test_path != path:
|
||||
# We got a change
|
||||
path = test_path
|
||||
continue
|
||||
# If we have no spaces to trim - bail
|
||||
if not (path[0] == " " or path[0] == " ") and not(path[-1] == " " or path[-1] == " "):
|
||||
return None
|
||||
# Here we try stripping spaces/tabs
|
||||
test_path = path
|
||||
t_count = 0
|
||||
while t_count < 100:
|
||||
t_count += 1
|
||||
t_path = test_path
|
||||
while len(t_path):
|
||||
if os.path.exists(t_path):
|
||||
return os.path.abspath(t_path)
|
||||
if t_path[-1] == " " or t_path[-1] == " ":
|
||||
t_path = t_path[:-1]
|
||||
continue
|
||||
break
|
||||
if test_path[0] == " " or test_path[0] == " ":
|
||||
test_path = test_path[1:]
|
||||
continue
|
||||
break
|
||||
# Escapes!
|
||||
test_path = "\\".join([x.replace("\\", "") for x in path.split("\\\\")])
|
||||
if test_path != path and not (path[0] == " " or path[0] == " "):
|
||||
path = test_path
|
||||
continue
|
||||
if path[0] == " " or path[0] == " ":
|
||||
path = path[1:]
|
||||
return None
|
||||
|
||||
def grab(self, prompt, **kwargs):
|
||||
# Takes a prompt, a default, and a timeout and shows it with that timeout
|
||||
# returning the result
|
||||
timeout = kwargs.get("timeout", 0)
|
||||
default = kwargs.get("default", None)
|
||||
# If we don't have a timeout - then skip the timed sections
|
||||
if timeout <= 0:
|
||||
if sys.version_info >= (3, 0):
|
||||
return input(prompt)
|
||||
else:
|
||||
return str(raw_input(prompt))
|
||||
# Write our prompt
|
||||
sys.stdout.write(prompt)
|
||||
sys.stdout.flush()
|
||||
if os.name == "nt":
|
||||
start_time = time.time()
|
||||
i = ''
|
||||
while True:
|
||||
if msvcrt.kbhit():
|
||||
c = msvcrt.getche()
|
||||
if ord(c) == 13: # enter_key
|
||||
break
|
||||
elif ord(c) >= 32: #space_char
|
||||
i += c
|
||||
if len(i) == 0 and (time.time() - start_time) > timeout:
|
||||
break
|
||||
else:
|
||||
i, o, e = select.select( [sys.stdin], [], [], timeout )
|
||||
if i:
|
||||
i = sys.stdin.readline().strip()
|
||||
print('') # needed to move to next line
|
||||
if len(i) > 0:
|
||||
return i
|
||||
else:
|
||||
return default
|
||||
|
||||
def cls(self):
|
||||
os.system('cls' if os.name=='nt' else 'clear')
|
||||
|
||||
def cprint(self, message, **kwargs):
|
||||
strip_colors = kwargs.get("strip_colors", False)
|
||||
if os.name == "nt":
|
||||
strip_colors = True
|
||||
reset = u"\u001b[0m"
|
||||
# Requires sys import
|
||||
for c in self.colors:
|
||||
if strip_colors:
|
||||
message = message.replace(c["find"], "")
|
||||
else:
|
||||
message = message.replace(c["find"], c["replace"])
|
||||
if strip_colors:
|
||||
return message
|
||||
sys.stdout.write(message)
|
||||
print(reset)
|
||||
|
||||
# Needs work to resize the string if color chars exist
|
||||
'''# Header drawing method
|
||||
def head(self, text = None, width = 55):
|
||||
if text == None:
|
||||
text = self.name
|
||||
self.cls()
|
||||
print(" {}".format("#"*width))
|
||||
len_text = self.cprint(text, strip_colors=True)
|
||||
mid_len = int(round(width/2-len(len_text)/2)-2)
|
||||
middle = " #{}{}{}#".format(" "*mid_len, len_text, " "*((width - mid_len - len(len_text))-2))
|
||||
if len(middle) > width+1:
|
||||
# Get the difference
|
||||
di = len(middle) - width
|
||||
# Add the padding for the ...#
|
||||
di += 3
|
||||
# Trim the string
|
||||
middle = middle[:-di]
|
||||
newlen = len(middle)
|
||||
middle += "...#"
|
||||
find_list = [ c["find"] for c in self.colors ]
|
||||
|
||||
# Translate colored string to len
|
||||
middle = middle.replace(len_text, text + self.rt_color) # always reset just in case
|
||||
self.cprint(middle)
|
||||
print("#"*width)'''
|
||||
|
||||
# Header drawing method
|
||||
def head(self, text = None, width = 55):
|
||||
if text == None:
|
||||
text = self.name
|
||||
self.cls()
|
||||
print(" {}".format("#"*width))
|
||||
mid_len = int(round(width/2-len(text)/2)-2)
|
||||
middle = " #{}{}{}#".format(" "*mid_len, text, " "*((width - mid_len - len(text))-2))
|
||||
if len(middle) > width+1:
|
||||
# Get the difference
|
||||
di = len(middle) - width
|
||||
# Add the padding for the ...#
|
||||
di += 3
|
||||
# Trim the string
|
||||
middle = middle[:-di] + "...#"
|
||||
print(middle)
|
||||
print("#"*width)
|
||||
|
||||
def resize(self, width, height):
|
||||
print('\033[8;{};{}t'.format(height, width))
|
||||
|
||||
def custom_quit(self):
|
||||
self.head()
|
||||
print("by CorpNewt\n")
|
||||
print("Thanks for testing it out, for bugs/comments/complaints")
|
||||
print("send me a message on Reddit, or check out my GitHub:\n")
|
||||
print("www.reddit.com/u/corpnewt")
|
||||
print("www.github.com/corpnewt\n")
|
||||
# Get the time and wish them a good morning, afternoon, evening, and night
|
||||
hr = datetime.datetime.now().time().hour
|
||||
if hr > 3 and hr < 12:
|
||||
print("Have a nice morning!\n\n")
|
||||
elif hr >= 12 and hr < 17:
|
||||
print("Have a nice afternoon!\n\n")
|
||||
elif hr >= 17 and hr < 21:
|
||||
print("Have a nice evening!\n\n")
|
||||
else:
|
||||
print("Have a nice night!\n\n")
|
||||
exit(0)
|
34
gibMacOS.bat
Normal file
34
gibMacOS.bat
Normal file
@ -0,0 +1,34 @@
|
||||
@echo off
|
||||
setlocal enableDelayedExpansion
|
||||
|
||||
REM Setup initial vars
|
||||
set "script_name=gibMacOS.command"
|
||||
set "thisDir=%~dp0"
|
||||
|
||||
REM Get python location
|
||||
FOR /F "tokens=* USEBACKQ" %%F IN (`where python 2^> nul`) DO (
|
||||
SET "python=%%F"
|
||||
)
|
||||
|
||||
REM Check for py and give helpful hints!
|
||||
if /i "!python!"=="" (
|
||||
echo Python is not installed or not found in your PATH var.
|
||||
echo Please install it from https://www.python.org/downloads/windows/
|
||||
echo.
|
||||
echo Make sure you check the box labeled:
|
||||
echo.
|
||||
echo "Add Python X.X to PATH"
|
||||
echo.
|
||||
echo Where X.X is the py version you're installing.
|
||||
echo.
|
||||
echo Press [enter] to quit.
|
||||
pause > nul
|
||||
exit /b
|
||||
)
|
||||
|
||||
REM Python found
|
||||
if "%*"=="" (
|
||||
"!python!" "!thisDir!!script_name!"
|
||||
) else (
|
||||
"!python!" "!thisDir!!script_name!" %*
|
||||
)
|
270
gibMacOS.command
Normal file
270
gibMacOS.command
Normal file
@ -0,0 +1,270 @@
|
||||
#!/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):
|
||||
# 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
|
||||
# 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("")
|
||||
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):
|
||||
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])
|
||||
|
||||
def get_latest(self):
|
||||
self.download_prod(self.mac_prods[-1])
|
||||
|
||||
def get_for_product(self, prod):
|
||||
for p in self.mac_prods:
|
||||
if p["product"] == prod:
|
||||
self.download_prod(prod)
|
||||
return
|
||||
print("{} not found".format(prod))
|
||||
|
||||
def get_for_version(self, vers):
|
||||
for p in self.mac_prods:
|
||||
if p["version"] == vers:
|
||||
self.download_prod(prod)
|
||||
return
|
||||
print("{} 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("-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()
|
||||
exit()
|
||||
if args.product:
|
||||
g.get_for_product(args.product)
|
||||
exit()
|
||||
if args.version:
|
||||
g.get_for_version(args.version)
|
||||
exit()
|
||||
|
||||
while True:
|
||||
g.main()
|
Loading…
Reference in New Issue
Block a user