add threading to applying

This commit is contained in:
leminlimez
2025-03-27 12:32:23 -04:00
parent 69ad97e5c4
commit 2010fb216b
5 changed files with 91 additions and 33 deletions

View File

@@ -40,7 +40,7 @@ def get_thumbnail_from_contents(contents: bytes, output_file: str = None):
contents = get_thumbnail_from_mov(inp_file, output_file)
return contents
def create_caml(video_path: str, output_file: str):
def create_caml(video_path: str, output_file: str, update_label=lambda x: None):
cam = cv2.VideoCapture(video_path)
assets_path = os.path.join(output_file, "assets")
try:
@@ -80,7 +80,10 @@ def create_caml(video_path: str, output_file: str):
if ret:
# if video is still left continue creating images
name = 'assets/' + str(currentframe) + '.jpg'
print ('Creating...' + name)
if update_label:
update_label('Creating...' + name)
else:
print ('Creating...' + name)
# writing the extracted images
cv2.imwrite(os.path.join(output_file, name), frame)

View File

@@ -3,7 +3,7 @@ import plistlib
from tempfile import TemporaryDirectory
from PySide6.QtWidgets import QMessageBox
from PySide6.QtCore import QSettings
from PySide6.QtCore import QSettings, QThread
from pymobiledevice3 import usbmux
from pymobiledevice3.lockdown import create_using_usbmux
@@ -12,37 +12,38 @@ from pymobiledevice3.exceptions import MuxException, PasswordRequiredError
from devicemanagement.constants import Device, Version
from devicemanagement.data_singleton import DataSingleton
from gui.apply_worker import ApplyAlertMessage
from tweaks.tweaks import tweaks, FeatureFlagTweak, EligibilityTweak, AITweak, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak, NullifyFileTweak
from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks
from tweaks.posterboard_tweak import PosterboardTweak
from tweaks.basic_plist_locations import FileLocationsList, RiskyFileLocationsList
from Sparserestore.restore import restore_files, FileToRestore
def show_error_msg(txt: str, detailed_txt: str = None):
def show_error_msg(txt: str, title: str = "Error!", icon = QMessageBox.Critical, detailed_txt: str = None):
detailsBox = QMessageBox()
detailsBox.setIcon(QMessageBox.Critical)
detailsBox.setWindowTitle("Error!")
detailsBox.setIcon(icon)
detailsBox.setWindowTitle(title)
detailsBox.setText(txt)
if detailed_txt != None:
detailsBox.setDetailedText(detailed_txt)
detailsBox.exec()
def show_apply_error(e: Exception, update_label=lambda x: None):
if "Find My" in str(e):
show_error_msg("Find My must be disabled in order to use this tool.",
detailed_txt="Disable Find My from Settings (Settings -> [Your Name] -> Find My) and then try again.")
elif "Encrypted Backup MDM" in str(e):
show_error_msg("Nugget cannot be used on this device. Click Show Details for more info.",
detailed_txt="Your device is managed and MDM backup encryption is on. This must be turned off in order for Nugget to work. Please do not use Nugget on your school/work device!")
elif "SessionInactive" in str(e):
show_error_msg("The session was terminated. Refresh the device list and try again.")
elif isinstance(e, PasswordRequiredError):
show_error_msg("Device is password protected! You must trust the computer on your device.",
detailed_txt="Unlock your device. On the popup, click \"Trust\", enter your password, then try again.")
else:
show_error_msg(type(e).__name__ + ": " + repr(e), detailed_txt=str(traceback.format_exc()))
print(traceback.format_exc())
update_label("Failed to restore")
if "Find My" in str(e):
return ApplyAlertMessage("Find My must be disabled in order to use this tool.",
detailed_txt="Disable Find My from Settings (Settings -> [Your Name] -> Find My) and then try again.")
elif "Encrypted Backup MDM" in str(e):
return ApplyAlertMessage("Nugget cannot be used on this device. Click Show Details for more info.",
detailed_txt="Your device is managed and MDM backup encryption is on. This must be turned off in order for Nugget to work. Please do not use Nugget on your school/work device!")
elif "SessionInactive" in str(e):
return ApplyAlertMessage("The session was terminated. Refresh the device list and try again.")
elif "PasswordRequiredError" in str(e):
return ApplyAlertMessage("Device is password protected! You must trust the computer on your device.",
detailed_txt="Unlock your device. On the popup, click \"Trust\", enter your password, then try again.")
else:
return ApplyAlertMessage(type(e).__name__ + ": " + repr(e), detailed_txt=str(traceback.format_exc()))
class DeviceManager:
## Class Functions
@@ -287,7 +288,7 @@ class DeviceManager:
))
## APPLYING OR REMOVING TWEAKS AND RESTORING
def apply_changes(self, resetting: bool = False, update_label=lambda x: None):
def apply_changes(self, resetting: bool = False, update_label=lambda x: None, show_alert=lambda x: None):
try:
# set the tweaks and apply
# first open the file in read mode
@@ -332,7 +333,7 @@ class DeviceManager:
tmp_pb_dir = TemporaryDirectory()
tweak.apply_tweak(
files_to_restore=files_to_restore, output_dir=tmp_pb_dir.name,
windows_path_fix=self.windows_path_fix
windows_path_fix=self.windows_path_fix, update_label=update_label
)
if tweak.enabled:
uses_domains = True
@@ -341,7 +342,7 @@ class DeviceManager:
gestalt_plist = tweak.apply_tweak(gestalt_plist)
elif tweak.enabled:
# no mobilegestalt file provided but applying mga tweaks, give warning
show_error_msg("No mobilegestalt file provided! Please select your file to apply mobilegestalt tweaks.")
show_alert(show_error_msg("No mobilegestalt file provided! Please select your file to apply mobilegestalt tweaks.", exec=False))
update_label("Failed.")
return
# set the custom gestalt keys
@@ -427,12 +428,12 @@ class DeviceManager:
msg = "Your device will now restart."
if not self.auto_reboot:
msg = "Please restart your device to see changes."
QMessageBox.information(None, "Success!", "All done! " + msg)
show_alert(ApplyAlertMessage(txt="All done! " + msg, title="Success!", icon=QMessageBox.Information))
update_label("Success!")
except Exception as e:
if tmp_pb_dir != None:
tmp_pb_dir.cleanup()
show_apply_error(e, update_label)
show_alert(show_apply_error(e, update_label))
## RESETTING MOBILE GESTALT
def reset_mobilegestalt(self, settings: QSettings, update_label=lambda x: None):
@@ -457,4 +458,4 @@ class DeviceManager:
QMessageBox.information(None, "Success!", "All done! " + msg)
update_label("Success!")
except Exception as e:
show_apply_error(e)
show_error_msg(str(e))

29
gui/apply_worker.py Normal file
View File

@@ -0,0 +1,29 @@
from PySide6.QtCore import Signal, QThread
from PySide6.QtWidgets import QMessageBox
class ApplyAlertMessage:
def __init__(self, txt: str, title: str = "Error!", icon = QMessageBox.Critical, detailed_txt: str = None):
self.txt = txt
self.title = title
self.icon = icon
self.detailed_txt = detailed_txt
class ApplyThread(QThread):
progress = Signal(str)
alert = Signal(ApplyAlertMessage)
def update_label(self, txt: str):
self.progress.emit(txt)
def alert_window(self, msg: ApplyAlertMessage):
self.alert.emit(msg)
def __init__(self, manager, resetting: bool = False):
super().__init__()
self.manager = manager
self.resetting = resetting
def do_work(self):
self.manager.apply_changes(self.resetting, self.update_label, self.alert_window)
def run(self):
self.do_work()

View File

@@ -14,6 +14,7 @@ from devicemanagement.constants import Version
from devicemanagement.device_manager import DeviceManager
from gui.dialogs import GestaltDialog, UpdateAppDialog, PBHelpDialog
from gui.apply_worker import ApplyThread, ApplyAlertMessage
from tweaks.tweaks import tweaks
from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks, ValueTypeStrings
@@ -43,6 +44,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.setupUi(self)
self.show_uuid = False
self.pb_mainLayout = None
self.applying_in_progress = False
self.threadpool = QtCore.QThreadPool()
self.loadSettings()
# Check for an update
@@ -1154,12 +1157,31 @@ class MainWindow(QtWidgets.QMainWindow):
def update_bar(self, percent):
self.ui.restoreProgressBar.setValue(int(percent))
def on_removeTweaksBtn_clicked(self):
# TODO: Add threading here
self.device_manager.apply_changes(resetting=True, update_label=self.update_label)
self.apply_changes(resetting=True)
def on_resetGestaltBtn_clicked(self):
self.device_manager.reset_mobilegestalt(self.settings, update_label=self.update_label)
@QtCore.Slot()
def on_applyTweaksBtn_clicked(self):
# TODO: Add threading here
self.device_manager.apply_changes(update_label=self.update_label)
self.apply_changes()
def apply_changes(self, resetting: bool = False):
if not self.applying_in_progress:
self.applying_in_progress = True
self.worker_thread = ApplyThread(manager=self.device_manager, resetting=resetting)
self.worker_thread.progress.connect(self.ui.statusLbl.setText)
self.worker_thread.alert.connect(self.alert_message)
self.worker_thread.finished.connect(self.finish_apply_thread)
self.worker_thread.finished.connect(self.worker_thread.deleteLater)
self.worker_thread.start()
def alert_message(self, alert: ApplyAlertMessage):
print(alert.txt)
detailsBox = QtWidgets.QMessageBox()
detailsBox.setIcon(alert.icon)
detailsBox.setWindowTitle(alert.title)
detailsBox.setText(alert.txt)
if alert.detailed_txt != None:
detailsBox.setDetailedText(alert.detailed_txt)
detailsBox.exec()
def finish_apply_thread(self):
self.applying_in_progress = False

View File

@@ -203,7 +203,7 @@ class PosterboardTweak(Tweak):
overriding.write(thumb_contents)
del thumb_contents
def create_video_loop_files(self, output_dir: str):
def create_video_loop_files(self, output_dir: str, update_label=lambda x: None):
print(f"file: {self.videoFile}, looping: {self.loop_video}")
if self.videoFile and self.loop_video:
source_dir = get_bundle_files("files/posterboard/VideoCAML")
@@ -211,11 +211,11 @@ class PosterboardTweak(Tweak):
copytree(source_dir, video_output_dir, dirs_exist_ok=True)
contents_path = os.path.join(video_output_dir, "versions/1/contents/9183.Custom-810w-1080h@2x~ipad.wallpaper/9183.Custom_Floating-810w-1080h@2x~ipad.ca")
print(f"path at {contents_path}, creating caml")
video_handler.create_caml(video_path=self.videoFile, output_file=contents_path)
video_handler.create_caml(video_path=self.videoFile, output_file=contents_path, update_label=update_label)
def apply_tweak(self, files_to_restore: list[FileToRestore], output_dir: str, windows_path_fix: bool):
def apply_tweak(self, files_to_restore: list[FileToRestore], output_dir: str, windows_path_fix: bool, update_label=lambda x: None):
# unzip the file
if not self.enabled:
return
@@ -243,8 +243,10 @@ class PosterboardTweak(Tweak):
if os.name == "nt" and windows_path_fix:
# try to get past directory name limit on windows
output_dir = "\\\\?\\" + output_dir
update_label("Generating PosterBoard Video...")
self.create_live_photo_files(output_dir)
self.create_video_loop_files(output_dir)
self.create_video_loop_files(output_dir, update_label=update_label)
update_label("Adding tendies...")
for tendie in self.tendies:
zip_output = os.path.join(output_dir, str(uuid.uuid4()))
os.makedirs(zip_output)
@@ -252,3 +254,4 @@ class PosterboardTweak(Tweak):
zip_ref.extractall(zip_output)
# add the files
self.recursive_add(files_to_restore, curr_path=output_dir)
update_label("Adding other tweaks...")