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

View File

@@ -3,7 +3,7 @@ import plistlib
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
from PySide6.QtWidgets import QMessageBox from PySide6.QtWidgets import QMessageBox
from PySide6.QtCore import QSettings from PySide6.QtCore import QSettings, QThread
from pymobiledevice3 import usbmux from pymobiledevice3 import usbmux
from pymobiledevice3.lockdown import create_using_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.constants import Device, Version
from devicemanagement.data_singleton import DataSingleton 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.tweaks import tweaks, FeatureFlagTweak, EligibilityTweak, AITweak, BasicPlistTweak, AdvancedPlistTweak, RdarFixTweak, NullifyFileTweak
from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks
from tweaks.posterboard_tweak import PosterboardTweak from tweaks.posterboard_tweak import PosterboardTweak
from tweaks.basic_plist_locations import FileLocationsList, RiskyFileLocationsList from tweaks.basic_plist_locations import FileLocationsList, RiskyFileLocationsList
from Sparserestore.restore import restore_files, FileToRestore 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 = QMessageBox()
detailsBox.setIcon(QMessageBox.Critical) detailsBox.setIcon(icon)
detailsBox.setWindowTitle("Error!") detailsBox.setWindowTitle(title)
detailsBox.setText(txt) detailsBox.setText(txt)
if detailed_txt != None: if detailed_txt != None:
detailsBox.setDetailedText(detailed_txt) detailsBox.setDetailedText(detailed_txt)
detailsBox.exec() detailsBox.exec()
def show_apply_error(e: Exception, update_label=lambda x: None): 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()) print(traceback.format_exc())
update_label("Failed to restore") 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 DeviceManager:
## Class Functions ## Class Functions
@@ -287,7 +288,7 @@ class DeviceManager:
)) ))
## APPLYING OR REMOVING TWEAKS AND RESTORING ## 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: try:
# set the tweaks and apply # set the tweaks and apply
# first open the file in read mode # first open the file in read mode
@@ -332,7 +333,7 @@ class DeviceManager:
tmp_pb_dir = TemporaryDirectory() tmp_pb_dir = TemporaryDirectory()
tweak.apply_tweak( tweak.apply_tweak(
files_to_restore=files_to_restore, output_dir=tmp_pb_dir.name, 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: if tweak.enabled:
uses_domains = True uses_domains = True
@@ -341,7 +342,7 @@ class DeviceManager:
gestalt_plist = tweak.apply_tweak(gestalt_plist) gestalt_plist = tweak.apply_tweak(gestalt_plist)
elif tweak.enabled: elif tweak.enabled:
# no mobilegestalt file provided but applying mga tweaks, give warning # 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.") update_label("Failed.")
return return
# set the custom gestalt keys # set the custom gestalt keys
@@ -427,12 +428,12 @@ class DeviceManager:
msg = "Your device will now restart." msg = "Your device will now restart."
if not self.auto_reboot: if not self.auto_reboot:
msg = "Please restart your device to see changes." 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!") update_label("Success!")
except Exception as e: except Exception as e:
if tmp_pb_dir != None: if tmp_pb_dir != None:
tmp_pb_dir.cleanup() tmp_pb_dir.cleanup()
show_apply_error(e, update_label) show_alert(show_apply_error(e, update_label))
## RESETTING MOBILE GESTALT ## RESETTING MOBILE GESTALT
def reset_mobilegestalt(self, settings: QSettings, update_label=lambda x: None): def reset_mobilegestalt(self, settings: QSettings, update_label=lambda x: None):
@@ -457,4 +458,4 @@ class DeviceManager:
QMessageBox.information(None, "Success!", "All done! " + msg) QMessageBox.information(None, "Success!", "All done! " + msg)
update_label("Success!") update_label("Success!")
except Exception as e: 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 devicemanagement.device_manager import DeviceManager
from gui.dialogs import GestaltDialog, UpdateAppDialog, PBHelpDialog from gui.dialogs import GestaltDialog, UpdateAppDialog, PBHelpDialog
from gui.apply_worker import ApplyThread, ApplyAlertMessage
from tweaks.tweaks import tweaks from tweaks.tweaks import tweaks
from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks, ValueTypeStrings from tweaks.custom_gestalt_tweaks import CustomGestaltTweaks, ValueTypeStrings
@@ -43,6 +44,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.ui.setupUi(self) self.ui.setupUi(self)
self.show_uuid = False self.show_uuid = False
self.pb_mainLayout = None self.pb_mainLayout = None
self.applying_in_progress = False
self.threadpool = QtCore.QThreadPool()
self.loadSettings() self.loadSettings()
# Check for an update # Check for an update
@@ -1154,12 +1157,31 @@ class MainWindow(QtWidgets.QMainWindow):
def update_bar(self, percent): def update_bar(self, percent):
self.ui.restoreProgressBar.setValue(int(percent)) self.ui.restoreProgressBar.setValue(int(percent))
def on_removeTweaksBtn_clicked(self): def on_removeTweaksBtn_clicked(self):
# TODO: Add threading here self.apply_changes(resetting=True)
self.device_manager.apply_changes(resetting=True, update_label=self.update_label)
def on_resetGestaltBtn_clicked(self): def on_resetGestaltBtn_clicked(self):
self.device_manager.reset_mobilegestalt(self.settings, update_label=self.update_label) self.device_manager.reset_mobilegestalt(self.settings, update_label=self.update_label)
@QtCore.Slot() @QtCore.Slot()
def on_applyTweaksBtn_clicked(self): def on_applyTweaksBtn_clicked(self):
# TODO: Add threading here self.apply_changes()
self.device_manager.apply_changes(update_label=self.update_label)
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) overriding.write(thumb_contents)
del 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}") print(f"file: {self.videoFile}, looping: {self.loop_video}")
if self.videoFile and self.loop_video: if self.videoFile and self.loop_video:
source_dir = get_bundle_files("files/posterboard/VideoCAML") 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) 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") 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") 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 # unzip the file
if not self.enabled: if not self.enabled:
return return
@@ -243,8 +243,10 @@ class PosterboardTweak(Tweak):
if os.name == "nt" and windows_path_fix: if os.name == "nt" and windows_path_fix:
# try to get past directory name limit on windows # try to get past directory name limit on windows
output_dir = "\\\\?\\" + output_dir output_dir = "\\\\?\\" + output_dir
update_label("Generating PosterBoard Video...")
self.create_live_photo_files(output_dir) 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: for tendie in self.tendies:
zip_output = os.path.join(output_dir, str(uuid.uuid4())) zip_output = os.path.join(output_dir, str(uuid.uuid4()))
os.makedirs(zip_output) os.makedirs(zip_output)
@@ -252,3 +254,4 @@ class PosterboardTweak(Tweak):
zip_ref.extractall(zip_output) zip_ref.extractall(zip_output)
# add the files # add the files
self.recursive_add(files_to_restore, curr_path=output_dir) self.recursive_add(files_to_restore, curr_path=output_dir)
update_label("Adding other tweaks...")