Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 63 additions & 1 deletion Scripts/downloader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import sys, os, time, ssl, gzip, multiprocessing
import sys, os, time, ssl, gzip, multiprocessing, subprocess, shutil
from io import BytesIO
# Python-aware urllib stuff
try:
Expand Down Expand Up @@ -145,6 +145,7 @@ class Downloader:
def __init__(self,**kwargs):
self.ua = kwargs.get("useragent",{"User-Agent":"Mozilla"})
self.chunk = 1048576 # 1024 x 1024 i.e. 1MiB
self.use_aria2c = kwargs.get("use_aria2c", self.check_aria2c())
if os.name=="nt": os.system("color") # Initialize cmd for ANSI escapes
# Provide reasonable default logic to workaround macOS CA file handling
cafile = ssl.get_default_verify_paths().openssl_cafile
Expand All @@ -158,6 +159,15 @@ def __init__(self,**kwargs):
# None of the above worked, disable certificate verification for now
self.ssl_context = ssl._create_unverified_context()
return

def check_aria2c(self):
# Check if aria2c is available in the system PATH
return shutil.which('aria2c') is not None

def set_use_aria2c(self, use_aria2c):
# Allow toggling between aria2c and default downloader
self.use_aria2c = use_aria2c if use_aria2c and self.check_aria2c() else False
return self.use_aria2c

def _decode(self, value, encoding="utf-8", errors="ignore"):
# Helper method to only decode if bytes type
Expand Down Expand Up @@ -264,7 +274,59 @@ def get_bytes(self, url, progress = True, headers = None, expand_gzip = True):
process.join()
return chunk_so_far

def stream_to_file_aria2c(self, url, file_path, progress = True, headers = None, ensure_size_if_present = True, allow_resume = False):
# Download using aria2c if available
try:
# Build aria2c command
cmd = ['aria2c', url, '-o', os.path.basename(file_path), '-d', os.path.dirname(file_path)]

# Add user agent header if provided
if headers:
for key, value in headers.items():
if key.lower() == 'user-agent':
cmd.extend(['--user-agent', value])
else:
cmd.extend(['--header', '{}:{}'.format(key, value)])
elif self.ua:
ua_value = self.ua.get('User-Agent', 'Mozilla')
cmd.extend(['--user-agent', ua_value])

# Add resume support
if allow_resume:
cmd.append('-c')

# Add connection options for better performance
cmd.extend(['-x', '16', '-s', '16', '-k', '1M'])

# Disable certificate verification if using unverified context
if hasattr(self, 'ssl_context') and isinstance(self.ssl_context, ssl.SSLContext):
if not self.ssl_context.check_hostname:
cmd.append('--check-certificate=false')

# Show progress
if not progress:
cmd.append('-q')

# Run aria2c
result = subprocess.run(cmd, capture_output=False)

if result.returncode == 0 and os.path.exists(file_path):
return file_path
else:
return None
except Exception as e:
# Fall back to default downloader
return self.stream_to_file_default(url, file_path, progress, headers, ensure_size_if_present, allow_resume)

def stream_to_file(self, url, file_path, progress = True, headers = None, ensure_size_if_present = True, allow_resume = False):
if self.use_aria2c:
result = self.stream_to_file_aria2c(url, file_path, progress, headers, ensure_size_if_present, allow_resume)
if result:
return result
# Fall back to default implementation
return self.stream_to_file_default(url, file_path, progress, headers, ensure_size_if_present, allow_resume)

def stream_to_file_default(self, url, file_path, progress = True, headers = None, ensure_size_if_present = True, allow_resume = False):
response = self.open_url(url, headers)
if response is None: return None
bytes_so_far = 0
Expand Down
11 changes: 10 additions & 1 deletion gibMacOS.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,16 @@ def __init__(self, interactive = True, download_dir = None):
"RecoveryHDUpdate.pkg",
"RecoveryHDMetaDmg.pkg"
)
self.use_aria2c = self.settings.get("use_aria2c", self.d.check_aria2c())
self.d.set_use_aria2c(self.use_aria2c)
self.settings_to_save = (
"current_macos",
"current_catalog",
"print_urls",
"find_recovery",
"hide_pid",
"caffeinate_downloads"
"caffeinate_downloads",
"use_aria2c"
)
self.mac_prods = []

Expand Down Expand Up @@ -659,6 +662,8 @@ def main(self, dmg = False):
lines.append("L. Clear SoftwareUpdate Catalog")
lines.append("F. Caffeinate Downloads to Prevent Sleep (Currently {})".format("On" if self.caffeinate_downloads else "Off"))
lines.append("R. Toggle Recovery-Only (Currently {})".format("On" if self.find_recovery else "Off"))
if self.d.check_aria2c():
lines.append("A. Toggle aria2c Downloader (Currently {})".format("On" if self.use_aria2c else "Off"))
lines.append("U. Show Catalog URL")
lines.append("Q. Quit")
lines.append(" ")
Expand Down Expand Up @@ -707,6 +712,10 @@ def main(self, dmg = False):
elif menu[0].lower() == "r":
self.find_recovery ^= True
self.save_settings()
elif menu[0].lower() == "a" and self.d.check_aria2c():
self.use_aria2c ^= True
self.d.set_use_aria2c(self.use_aria2c)
self.save_settings()
if menu[0].lower() in ["m","c","r"]:
self.resize()
self.u.head("Parsing Data")
Expand Down