Enhance user prompts, add temporary dir handling

This commit is contained in:
Hoang Hong Quan
2025-10-22 00:59:12 +07:00
parent c4ed8bb4fe
commit 542ad9623c
8 changed files with 197 additions and 168 deletions
+69 -64
View File
@@ -29,33 +29,32 @@ class OCPE:
self.s = smbios.SMBIOS() self.s = smbios.SMBIOS()
self.r = run.Run() self.r = run.Run()
self.u = utils.Utils() self.u = utils.Utils()
self.result_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "Results") self.result_dir = self.u.get_temporary_dir()
def select_hardware_report(self): def select_hardware_report(self):
self.hardware_sniffer = self.o.gather_hardware_sniffer()
self.ac.dsdt = self.ac.acpi.acpi_tables = None self.ac.dsdt = self.ac.acpi.acpi_tables = None
while True: while True:
self.u.head("Select hardware report") self.u.head("Select hardware report")
print("") print("")
if os.name == "nt": if os.name == "nt":
print("\033[93mNote:\033[0m") print("\033[1;93mNote:\033[0m")
print("- Ensure you are using the latest version of Hardware Sniffer before generating the hardware report.") print("- Ensure you are using the latest version of Hardware Sniffer before generating the hardware report.")
print("- Hardware Sniffer will not collect information related to Resizable BAR option of GPU (disabled by default) and monitor connections in Windows PE.") print("- Hardware Sniffer will not collect information related to Resizable BAR option of GPU (disabled by default) and monitor connections in Windows PE.")
print("")
if self.hardware_sniffer:
print("") print("")
print("E. Export hardware report (Recommended)") print("E. Export hardware report (Recommended)")
print("") print("")
print("Q. Quit") print("Q. Quit")
print("") print("")
user_input = self.u.request_input("Drag and drop your hardware report here (.JSON){}: ".format(" or type \"E\" to export" if self.hardware_sniffer else "")) user_input = self.u.request_input("Drag and drop your hardware report here (.JSON) or type \"E\" to export: ")
if user_input.lower() == "q": if user_input.lower() == "q":
self.u.exit_program() self.u.exit_program()
if self.hardware_sniffer and user_input.lower() == "e": if user_input.lower() == "e":
hardware_sniffer = self.o.gather_hardware_sniffer()
output = self.r.run({ output = self.r.run({
"args":[self.hardware_sniffer, "-e"] "args":[hardware_sniffer, "-e"]
}) })
if output[-1] != 0: if output[-1] != 0:
@@ -101,7 +100,7 @@ class OCPE:
print("\033[91mImportant:\033[0m") print("\033[91mImportant:\033[0m")
print("Please consider these risks carefully before proceeding.") print("Please consider these risks carefully before proceeding.")
print("") print("")
print("\033[93mNote:\033[0m") print("\033[1;93mNote:\033[0m")
print("If you experience black screen after login with OpenCore Legacy Patcher v2.2.0 or newer") print("If you experience black screen after login with OpenCore Legacy Patcher v2.2.0 or newer")
print("after applying root patches, please revert to version v2.1.2.") print("after applying root patches, please revert to version v2.1.2.")
print("") print("")
@@ -157,7 +156,7 @@ class OCPE:
print(" {}. {}{}".format(darwin_version, name, label)) print(" {}. {}{}".format(darwin_version, name, label))
print("") print("")
print("\033[93mNote:\033[0m") print("\033[1;93mNote:\033[0m")
print("- To select a major version, enter the number (e.g., 19).") print("- To select a major version, enter the number (e.g., 19).")
print("- To specify a full version, use the Darwin version format (e.g., 22.4.6).") print("- To specify a full version, use the Darwin version format (e.g., 22.4.6).")
print("") print("")
@@ -177,9 +176,17 @@ class OCPE:
return target_version return target_version
def build_opencore_efi(self, hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp): def build_opencore_efi(self, hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp):
self.u.head("Building OpenCore EFI") steps = [
print("") "Copying EFI base to results folder",
print("1. Copy EFI base to results folder...", end=" ") "Applying ACPI patches",
"Copying kexts and snapshotting to config.plist",
"Generating config.plist",
"Cleaning up unused drivers, resources, and tools"
]
title = "Building OpenCore EFI"
self.u.progress_bar(title, steps, 0)
self.u.create_folder(self.result_dir, remove_content=True) self.u.create_folder(self.result_dir, remove_content=True)
if not os.path.exists(self.k.ock_files_dir): if not os.path.exists(self.k.ock_files_dir):
@@ -193,8 +200,8 @@ class OCPE:
if not config_data: if not config_data:
raise Exception("Error: The file {} does not exist.".format(config_file)) raise Exception("Error: The file {} does not exist.".format(config_file))
print("Done")
print("2. Apply ACPI patches...", end=" ") self.u.progress_bar(title, steps, 1)
config_data["ACPI"]["Add"] = [] config_data["ACPI"]["Add"] = []
config_data["ACPI"]["Delete"] = [] config_data["ACPI"]["Delete"] = []
config_data["ACPI"]["Patch"] = [] config_data["ACPI"]["Patch"] = []
@@ -223,17 +230,17 @@ class OCPE:
config_data["ACPI"]["Patch"].extend(self.ac.dsdt_patches) config_data["ACPI"]["Patch"].extend(self.ac.dsdt_patches)
config_data["ACPI"]["Patch"] = self.ac.apply_acpi_patches(config_data["ACPI"]["Patch"]) config_data["ACPI"]["Patch"] = self.ac.apply_acpi_patches(config_data["ACPI"]["Patch"])
print("Done")
print("3. Copy kexts and snapshot to config.plist...", end=" ") self.u.progress_bar(title, steps, 2)
kexts_directory = os.path.join(self.result_dir, "EFI", "OC", "Kexts") kexts_directory = os.path.join(self.result_dir, "EFI", "OC", "Kexts")
self.k.install_kexts_to_efi(macos_version, kexts_directory) self.k.install_kexts_to_efi(macos_version, kexts_directory)
config_data["Kernel"]["Add"] = self.k.load_kexts(hardware_report, macos_version, kexts_directory) config_data["Kernel"]["Add"] = self.k.load_kexts(hardware_report, macos_version, kexts_directory)
print("Done")
print("4. Generate config.plist...", end=" ") self.u.progress_bar(title, steps, 3)
self.co.genarate(hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp, self.k.kexts, config_data) self.co.genarate(hardware_report, disabled_devices, smbios_model, macos_version, needs_oclp, self.k.kexts, config_data)
self.u.write_file(config_file, config_data) self.u.write_file(config_file, config_data)
print("Done")
print("5. Clean up unused drivers, resources, and tools...", end=" ") self.u.progress_bar(title, steps, 4)
files_to_remove = [] files_to_remove = []
drivers_directory = os.path.join(self.result_dir, "EFI", "OC", "Drivers") drivers_directory = os.path.join(self.result_dir, "EFI", "OC", "Drivers")
@@ -269,7 +276,6 @@ class OCPE:
if not tool_path in tool_loaded: if not tool_path in tool_loaded:
files_to_remove.append(os.path.join(tools_directory, tool_path)) files_to_remove.append(os.path.join(tools_directory, tool_path))
removal_error = None
for file_path in files_to_remove: for file_path in files_to_remove:
try: try:
if os.path.isdir(file_path): if os.path.isdir(file_path):
@@ -277,14 +283,10 @@ class OCPE:
else: else:
os.remove(file_path) os.remove(file_path)
except Exception as e: except Exception as e:
removal_error = True
print("Failed to remove file: {}".format(e)) print("Failed to remove file: {}".format(e))
if removal_error: self.u.progress_bar(title, steps, len(steps), done=True)
print("")
print("Done")
print("")
print("OpenCore EFI build complete.") print("OpenCore EFI build complete.")
time.sleep(2) time.sleep(2)
@@ -308,18 +310,14 @@ class OCPE:
return requirements return requirements
def results(self, org_hardware_report, hardware_report): def before_using_efi(self, org_hardware_report, hardware_report):
self.u.head("Results") while True:
self.u.head("Before Using EFI")
print("")
print("\033[93mPlease complete the following steps:\033[0m")
print("") print("")
print("Your OpenCore EFI for {} has been built at:".format(hardware_report.get("Motherboard").get("Name")))
print("\t{}".format(self.result_dir))
bios_requirements = self.check_bios_requirements(org_hardware_report, hardware_report) bios_requirements = self.check_bios_requirements(org_hardware_report, hardware_report)
print("")
print("\033[93mBefore using EFI, please complete the following steps:\033[0m")
print("")
if bios_requirements: if bios_requirements:
print("* BIOS/UEFI Settings Required:") print("* BIOS/UEFI Settings Required:")
for requirement in bios_requirements: for requirement in bios_requirements:
@@ -336,8 +334,13 @@ class OCPE:
print(" - If you have more than 15 ports on a single controller, enable the XhciPortLimit patch.") print(" - If you have more than 15 ports on a single controller, enable the XhciPortLimit patch.")
print(" - Save the file when finished.") print(" - Save the file when finished.")
print("") print("")
print("Type \"AGREE\" to open the built EFI for you\n")
response = self.u.request_input("")
if response.lower() == "agree":
self.u.open_folder(self.result_dir) self.u.open_folder(self.result_dir)
self.u.request_input() break
else:
print("\033[91mInvalid input. Please try again.\033[0m")
def main(self): def main(self):
hardware_report_path = None hardware_report_path = None
@@ -351,20 +354,17 @@ class OCPE:
while True: while True:
self.u.head() self.u.head()
print("") print("")
print("Hardware Report: {}".format("No report selected" if not hardware_report_path else hardware_report_path)) print(" Hardware Report: {}".format(hardware_report_path or 'Not selected'))
print("") print("")
if hardware_report_path: if hardware_report_path:
print("* Hardware Compatibility:") print(" macOS Version: {}".format(os_data.get_macos_name_by_darwin(macos_version) if macos_version else 'Not selected') + (' (' + macos_version + ')' if macos_version else '') + ('. \033[1;93mRequires OpenCore Legacy Patcher\033[0m' if needs_oclp else ''))
if native_macos_version: print(" SMBIOS: {}".format(smbios_model or 'Not selected'))
print(" - Native macOS Version: {}".format(self.c.show_macos_compatibility((native_macos_version[-1], native_macos_version[0]))))
if disabled_devices: if disabled_devices:
print(" - Disabled Devices:") print(" Disabled Devices:")
for index, device_name in enumerate(disabled_devices, start=1): for device, _ in disabled_devices.items():
print("{}{}. {}".format(" "*6, index, device_name)) print(" - {}".format(device))
print("* EFI Options:")
print(" - macOS Version: {}{}{}".format("Unknown" if not macos_version else os_data.get_macos_name_by_darwin(macos_version), "" if not macos_version else " ({})".format(macos_version), ". \033[1;93mRequires OpenCore Legacy Patcher\033[0m" if needs_oclp else ""))
print(" - SMBIOS: {}".format("Unknown" if not smbios_model else smbios_model))
print("") print("")
print("1. Select Hardware Report") print("1. Select Hardware Report")
print("2. Select macOS Version") print("2. Select macOS Version")
print("3. Customize ACPI Patch") print("3. Customize ACPI Patch")
@@ -374,16 +374,12 @@ class OCPE:
print("") print("")
print("Q. Quit") print("Q. Quit")
print("") print("")
option = self.u.request_input("Select an option: ") option = self.u.request_input("Select an option: ")
if option.lower() == "q": if option.lower() == "q":
self.u.exit_program() self.u.exit_program()
try: if option == "1":
option = int(option)
except:
continue
if option == 1:
hardware_report_path, hardware_report = self.select_hardware_report() hardware_report_path, hardware_report = self.select_hardware_report()
hardware_report, native_macos_version, ocl_patched_macos_version = self.c.check_compatibility(hardware_report) hardware_report, native_macos_version, ocl_patched_macos_version = self.c.check_compatibility(hardware_report)
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version) macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
@@ -394,27 +390,29 @@ class OCPE:
self.ac.select_acpi_patches(customized_hardware, disabled_devices) self.ac.select_acpi_patches(customized_hardware, disabled_devices)
needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches) needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k) self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
elif option < 7:
try: if not hardware_report_path:
customized_hardware self.u.head()
except: print("\n\n")
self.u.request_input("\nPlease select a hardware report to proceed") print("\033[1;93mPlease select a hardware report first.\033[0m")
print("\n\n")
self.u.request_input("Press Enter to go back...")
continue continue
if option == 2: if option == "2":
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version) macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version) customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version)
smbios_model = self.s.select_smbios_model(customized_hardware, macos_version) smbios_model = self.s.select_smbios_model(customized_hardware, macos_version)
needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches) needs_oclp = self.k.select_required_kexts(customized_hardware, macos_version, needs_oclp, self.ac.patches)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k) self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
elif option == 3: elif option == "3":
self.ac.customize_patch_selection() self.ac.customize_patch_selection()
elif option == 4: elif option == "4":
self.k.kext_configuration_menu(macos_version) self.k.kext_configuration_menu(macos_version)
elif option == 5: elif option == "5":
smbios_model = self.s.customize_smbios_model(customized_hardware, smbios_model, macos_version) smbios_model = self.s.customize_smbios_model(customized_hardware, smbios_model, macos_version)
self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k) self.s.smbios_specific_options(customized_hardware, smbios_model, macos_version, self.ac.patches, self.k)
elif option == 6: elif option == "6":
if needs_oclp and not self.show_oclp_warning(): if needs_oclp and not self.show_oclp_warning():
macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version) macos_version = self.select_macos_version(hardware_report, native_macos_version, ocl_patched_macos_version)
customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version) customized_hardware, disabled_devices, needs_oclp = self.h.hardware_customization(hardware_report, macos_version)
@@ -427,7 +425,14 @@ class OCPE:
continue continue
self.build_opencore_efi(customized_hardware, disabled_devices, smbios_model, macos_version, needs_oclp) self.build_opencore_efi(customized_hardware, disabled_devices, smbios_model, macos_version, needs_oclp)
self.results(hardware_report, customized_hardware) self.before_using_efi(hardware_report, customized_hardware)
self.u.head("Result")
print("")
print("Your OpenCore EFI for {} has been built at:".format(customized_hardware.get("Motherboard").get("Name")))
print("\t{}".format(self.result_dir))
print("")
self.u.request_input("Press Enter to main menu...")
if __name__ == '__main__': if __name__ == '__main__':
update_flag = updater.Updater().run_update() update_flag = updater.Updater().run_update()
+1 -3
View File
@@ -3331,9 +3331,7 @@ DefinitionBlock ("", "SSDT", 2, "ZPSS", "WMIS", 0x00000000)
if kext.checked: if kext.checked:
line = "\033[1;32m{}\033[0m".format(line) line = "\033[1;32m{}\033[0m".format(line)
contents.append(line) contents.append(line)
contents.append("\033[1;36m") contents.append("\033[1;93mNote:\033[0m You can select multiple kexts by entering their indices separated by commas (e.g., '1, 2, 3').")
contents.append("Note: You can select multiple kexts by entering their indices separated by commas (e.g., '1, 2, 3').")
contents.append("\033[0m")
contents.append("B. Back") contents.append("B. Back")
contents.append("Q. Quit") contents.append("Q. Quit")
contents.append("") contents.append("")
+3 -3
View File
@@ -221,7 +221,7 @@ class CompatibilityChecker:
print("{}- Audio Endpoint{}: {}".format(" "*6, "s" if len(audio_endpoints) > 1 else "", ", ".join(audio_endpoints))) print("{}- Audio Endpoint{}: {}".format(" "*6, "s" if len(audio_endpoints) > 1 else "", ", ".join(audio_endpoints)))
def check_biometric_compatibility(self): def check_biometric_compatibility(self):
print(" \033[93mNote:\033[0m Biometric authentication in macOS requires Apple T2 Chip,") print(" \033[1;93mNote:\033[0m Biometric authentication in macOS requires Apple T2 Chip,")
print(" which is not available for Hackintosh systems.") print(" which is not available for Hackintosh systems.")
print("") print("")
for biometric_device, biometric_props in self.hardware_report.get("Biometric", {}).items(): for biometric_device, biometric_props in self.hardware_report.get("Biometric", {}).items():
@@ -273,10 +273,10 @@ class CompatibilityChecker:
print("{}- Continuity Support: \033[1;32mFull\033[0m (AirDrop, Handoff, Universal Clipboard, Instant Hotspot,...)".format(" "*6)) print("{}- Continuity Support: \033[1;32mFull\033[0m (AirDrop, Handoff, Universal Clipboard, Instant Hotspot,...)".format(" "*6))
elif device_id in pci_data.IntelWiFiIDs: elif device_id in pci_data.IntelWiFiIDs:
print("{}- Continuity Support: \033[1;33mPartial\033[0m (Handoff and Universal Clipboard with AirportItlwm)".format(" "*6)) print("{}- Continuity Support: \033[1;33mPartial\033[0m (Handoff and Universal Clipboard with AirportItlwm)".format(" "*6))
print("{}\033[93mNote:\033[0m AirDrop, Universal Clipboard, Instant Hotspot,... not available".format(" "*6)) print("{}\033[1;93mNote:\033[0m AirDrop, Universal Clipboard, Instant Hotspot,... not available".format(" "*6))
elif device_id in pci_data.AtherosWiFiIDs: elif device_id in pci_data.AtherosWiFiIDs:
print("{}- Continuity Support: \033[1;31mLimited\033[0m (No Continuity features available)".format(" "*6)) print("{}- Continuity Support: \033[1;31mLimited\033[0m (No Continuity features available)".format(" "*6))
print("{}\033[93mNote:\033[0m Atheros cards are not recommended for macOS".format(" "*6)) print("{}\033[1;93mNote:\033[0m Atheros cards are not recommended for macOS".format(" "*6))
if "OCLP Compatibility" in device_props: if "OCLP Compatibility" in device_props:
print("{}- OCLP Compatibility: {}".format(" "*6, self.show_macos_compatibility(device_props.get("OCLP Compatibility")))) print("{}- OCLP Compatibility: {}".format(" "*6, self.show_macos_compatibility(device_props.get("OCLP Compatibility"))))
+1 -1
View File
@@ -286,7 +286,7 @@ class ConfigProdigy:
else: else:
contents.append(line) contents.append(line)
contents.append("") contents.append("")
contents.append("\033[93mNote:\033[0m") contents.append("\033[1;93mNote:\033[0m")
contents.append("- The default layout may not be optimal.") contents.append("- The default layout may not be optimal.")
contents.append("- Test different layouts to find what works best for your system.") contents.append("- Test different layouts to find what works best for your system.")
contents.append("") contents.append("")
+1 -2
View File
@@ -3,7 +3,6 @@ from Scripts import kext_maestro
from Scripts import resource_fetcher from Scripts import resource_fetcher
from Scripts import utils from Scripts import utils
import os import os
import tempfile
import shutil import shutil
import subprocess import subprocess
import platform import platform
@@ -21,7 +20,7 @@ class gatheringFiles:
self.amd_vanilla_patches_url = "https://raw.githubusercontent.com/AMD-OSX/AMD_Vanilla/beta/patches.plist" self.amd_vanilla_patches_url = "https://raw.githubusercontent.com/AMD-OSX/AMD_Vanilla/beta/patches.plist"
self.aquantia_macos_patches_url = "https://raw.githubusercontent.com/CaseySJ/Aquantia-macOS-Patches/refs/heads/main/CaseySJ-Aquantia-Patch-Sets-1-and-2.plist" self.aquantia_macos_patches_url = "https://raw.githubusercontent.com/CaseySJ/Aquantia-macOS-Patches/refs/heads/main/CaseySJ-Aquantia-Patch-Sets-1-and-2.plist"
self.hyper_threading_patches_url = "https://github.com/b00t0x/CpuTopologyRebuild/raw/refs/heads/master/patches_ht.plist" self.hyper_threading_patches_url = "https://github.com/b00t0x/CpuTopologyRebuild/raw/refs/heads/master/patches_ht.plist"
self.temporary_dir = tempfile.mkdtemp() self.temporary_dir = self.utils.get_temporary_dir()
self.ock_files_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "OCK_Files") self.ock_files_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "OCK_Files")
self.bootloader_kexts_data_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "bootloader_kexts_data.json") self.bootloader_kexts_data_path = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "bootloader_kexts_data.json")
self.download_history_file = os.path.join(self.ock_files_dir, "history.json") self.download_history_file = os.path.join(self.ock_files_dir, "history.json")
+17 -17
View File
@@ -122,7 +122,7 @@ class KextMaestro:
for codec_properties in hardware_report.get("Sound", {}).values(): for codec_properties in hardware_report.get("Sound", {}).values():
if codec_properties.get("Device ID") in codec_layouts.data: if codec_properties.get("Device ID") in codec_layouts.data:
if self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("25.0.0"): if self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("25.0.0"):
print("\n\033[93mNote:\033[0m Since macOS Tahoe 26 DP2, Apple has removed AppleHDA kext and uses the Apple T2 chip for audio management.") print("\n\033[1;93mNote:\033[0m Since macOS Tahoe 26 DP2, Apple has removed AppleHDA kext and uses the Apple T2 chip for audio management.")
print("To use AppleALC, you must rollback AppleHDA. Alternatively, you can use VoodooHDA.") print("To use AppleALC, you must rollback AppleHDA. Alternatively, you can use VoodooHDA.")
print("") print("")
print("1. \033[1mAppleALC\033[0m - Requires AppleHDA rollback with \033[1;93mOpenCore Legacy Patcher\033[0m") print("1. \033[1mAppleALC\033[0m - Requires AppleHDA rollback with \033[1;93mOpenCore Legacy Patcher\033[0m")
@@ -179,8 +179,8 @@ class KextMaestro:
recommended_option = 1 recommended_option = 1
recommended_name = "NootRX" recommended_name = "NootRX"
max_option = 3 max_option = 3
print("\033[93mNote:\033[0m - Since macOS Tahoe 26, WhateverGreen has known connector patching issues for AMD {} GPUs.".format(gpu_props.get("Codename"))) print("\033[1;93mNote:\033[0m Since macOS Tahoe 26, WhateverGreen has known connector patching issues for AMD {} GPUs.".format(gpu_props.get("Codename")))
print(" - To avoid this, you can use NootRX or choose not to install a GPU kext.") print("To avoid this, you can use NootRX or choose not to install a GPU kext.")
print("") print("")
print("1. \033[1mNootRX\033[0m - Uses latest GPU firmware") print("1. \033[1mNootRX\033[0m - Uses latest GPU firmware")
print("2. \033[1mWhateverGreen\033[0m - Uses original Apple firmware") print("2. \033[1mWhateverGreen\033[0m - Uses original Apple firmware")
@@ -189,7 +189,8 @@ class KextMaestro:
recommended_option = 2 recommended_option = 2
recommended_name = "WhateverGreen" recommended_name = "WhateverGreen"
max_option = 2 max_option = 2
print("\033[93mNote:\033[0m - AMD {} GPUs have two available kext options:".format(gpu_props.get("Codename"))) print("\033[1;93mNote:\033[0m")
print("- AMD {} GPUs have two available kext options:".format(gpu_props.get("Codename")))
print("- You can try different kexts after installation to find the best one for your system") print("- You can try different kexts after installation to find the best one for your system")
print("") print("")
print("1. \033[1mNootRX\033[0m - Uses latest GPU firmware") print("1. \033[1mNootRX\033[0m - Uses latest GPU firmware")
@@ -197,8 +198,8 @@ class KextMaestro:
print("") print("")
if any(other_gpu_props.get("Manufacturer") == "Intel" for other_gpu_props in hardware_report.get("GPU", {}).values()): if any(other_gpu_props.get("Manufacturer") == "Intel" for other_gpu_props in hardware_report.get("GPU", {}).values()):
print("\033[91mImportant:\033[0m - NootRX kext is not compatible with Intel GPUs") print("\033[91mImportant:\033[0m NootRX kext is not compatible with Intel GPUs")
print(" - Automatically selecting WhateverGreen kext due to Intel GPU compatibility") print("Automatically selecting WhateverGreen kext due to Intel GPU compatibility")
print("") print("")
self.utils.request_input("Press Enter to continue...") self.utils.request_input("Press Enter to continue...")
continue continue
@@ -221,9 +222,9 @@ class KextMaestro:
if self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("25.0.0"): if self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("25.0.0"):
print("\n*** Found {} is AMD {} GPU.".format(gpu_name, gpu_props.get("Codename"))) print("\n*** Found {} is AMD {} GPU.".format(gpu_name, gpu_props.get("Codename")))
print("") print("")
print("\033[93mNote:\033[0m - Since macOS Tahoe 26, WhateverGreen has known connector patching issues for AMD GPUs.") print("\033[1;93mNote:\033[0m Since macOS Tahoe 26, WhateverGreen has known connector patching issues for AMD GPUs.")
print(" - The current recommendation is to not use WhateverGreen.") print("The current recommendation is to not use WhateverGreen.")
print(" - However, you can still try adding it to see if it works on your system.") print("However, you can still try adding it to see if it works on your system.")
print("") print("")
self.utils.request_input("Press Enter to continue...") self.utils.request_input("Press Enter to continue...")
break break
@@ -254,7 +255,7 @@ class KextMaestro:
elif device_id in pci_data.IntelWiFiIDs: elif device_id in pci_data.IntelWiFiIDs:
print("\n*** Found {} is Intel WiFi device.".format(network_name)) print("\n*** Found {} is Intel WiFi device.".format(network_name))
print("") print("")
print("\033[93mNote:\033[0m Intel WiFi devices have two available kext options:") print("\033[1;93mNote:\033[0m Intel WiFi devices have two available kext options:")
print("") print("")
print("1. \033[1mAirportItlwm\033[0m - Uses native WiFi settings menu") print("1. \033[1mAirportItlwm\033[0m - Uses native WiFi settings menu")
print(" • Provides Handoff, Universal Clipboard, Location Services, Instant Hotspot support") print(" • Provides Handoff, Universal Clipboard, Location Services, Instant Hotspot support")
@@ -303,7 +304,7 @@ class KextMaestro:
selected_kexts.append("IOSkywalkFamily") selected_kexts.append("IOSkywalkFamily")
elif self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("23.0.0"): elif self.utils.parse_darwin_version(macos_version) >= self.utils.parse_darwin_version("23.0.0"):
print("") print("")
print("\033[93mNote:\033[0m Since macOS Sonoma 14, iServices won't work with AirportItlwm without patches") print("\033[1;93mNote:\033[0m Since macOS Sonoma 14, iServices won't work with AirportItlwm without patches")
print("") print("")
while True: while True:
option = self.utils.request_input("Apply OCLP root patch to fix iServices? (yes/No): ").strip().lower() option = self.utils.request_input("Apply OCLP root patch to fix iServices? (yes/No): ").strip().lower()
@@ -651,11 +652,10 @@ class KextMaestro:
for index, (kext_name, is_lilu_dependent) in enumerate(incompatible_kexts, start=1): for index, (kext_name, is_lilu_dependent) in enumerate(incompatible_kexts, start=1):
print("{:2}. {:25}{}".format(index, kext_name, " - Lilu Plugin" if is_lilu_dependent else "")) print("{:2}. {:25}{}".format(index, kext_name, " - Lilu Plugin" if is_lilu_dependent else ""))
print("\n\033[1;36m") print("\n\033[1;93mNote:\033[0m")
print("Note:")
print("- With Lilu plugins, using the \"-lilubetaall\" boot argument will force them to load.") print("- With Lilu plugins, using the \"-lilubetaall\" boot argument will force them to load.")
print("- Forcing unsupported kexts can cause system instability. \033[0;31mProceed with caution.\033[0m") print("- Forcing unsupported kexts can cause system instability. \033[0;31mProceed with caution.\033[0m")
print("\033[0m") print("")
option = self.utils.request_input("Do you want to force load {} on the unsupported macOS version? (yes/No): ".format("these kexts" if len(incompatible_kexts) > 1 else "this kext")) option = self.utils.request_input("Do you want to force load {} on the unsupported macOS version? (yes/No): ".format("these kexts" if len(incompatible_kexts) > 1 else "this kext"))
@@ -684,12 +684,12 @@ class KextMaestro:
elif not self.utils.parse_darwin_version(kext.min_darwin_version) <= self.utils.parse_darwin_version(macos_version) <= self.utils.parse_darwin_version(kext.max_darwin_version): elif not self.utils.parse_darwin_version(kext.min_darwin_version) <= self.utils.parse_darwin_version(macos_version) <= self.utils.parse_darwin_version(kext.max_darwin_version):
line = "\033[90m{}\033[0m".format(line) line = "\033[90m{}\033[0m".format(line)
contents.append(line) contents.append(line)
contents.append("\033[1;36m") contents.append("")
contents.append("Note:") contents.append("\033[1;93mNote:\033[0m")
contents.append("- Lines in gray indicate kexts that are not supported by the current macOS version ({}).".format(macos_version)) contents.append("- Lines in gray indicate kexts that are not supported by the current macOS version ({}).".format(macos_version))
contents.append("- When a plugin of a kext is selected, the entire kext will be automatically selected.") contents.append("- When a plugin of a kext is selected, the entire kext will be automatically selected.")
contents.append("- You can select multiple kexts by entering their indices separated by commas (e.g., '1, 2, 3').") contents.append("- You can select multiple kexts by entering their indices separated by commas (e.g., '1, 2, 3').")
contents.append("\033[0m") contents.append("")
contents.append("B. Back") contents.append("B. Back")
contents.append("Q. Quit") contents.append("Q. Quit")
contents.append("") contents.append("")
+63 -36
View File
@@ -8,10 +8,29 @@ import binascii
import subprocess import subprocess
import pathlib import pathlib
import zipfile import zipfile
import tempfile
class Utils: class Utils:
def __init__(self, script_name = "OpCore Simplify"): def __init__(self, script_name = "OpCore Simplify"):
self.script_name = script_name self.script_name = script_name
self.clean_temporary_dir()
def clean_temporary_dir(self):
temporary_dir = tempfile.gettempdir()
for file in os.listdir(temporary_dir):
if file.startswith("ocs_"):
if not os.path.isdir(os.path.join(temporary_dir, file)):
continue
try:
shutil.rmtree(os.path.join(temporary_dir, file))
except Exception as e:
pass
def get_temporary_dir(self):
return tempfile.mkdtemp(prefix="ocs_")
def write_file(self, file_path, data): def write_file(self, file_path, data):
file_extension = os.path.splitext(file_path)[1] file_extension = os.path.splitext(file_path)[1]
@@ -78,18 +97,13 @@ class Utils:
def hex_to_bytes(self, string): def hex_to_bytes(self, string):
try: try:
# Remove non-hex characters (e.g., hyphens)
hex_string = re.sub(r'[^0-9a-fA-F]', '', string) hex_string = re.sub(r'[^0-9a-fA-F]', '', string)
if len(re.sub(r"\s+", "", string)) != len(hex_string): if len(re.sub(r"\s+", "", string)) != len(hex_string):
return string return string
# Convert hex string to bytes return binascii.unhexlify(hex_string)
bytes_data = binascii.unhexlify(hex_string)
return bytes_data
except binascii.Error: except binascii.Error:
# Handle invalid hex string
return string return string
def int_to_hex(self, number): def int_to_hex(self, number):
@@ -98,9 +112,7 @@ class Utils:
def to_little_endian_hex(self, hex_string): def to_little_endian_hex(self, hex_string):
hex_string = hex_string.lower().lstrip("0x") hex_string = hex_string.lower().lstrip("0x")
little_endian_hex = ''.join(reversed([hex_string[i:i+2] for i in range(0, len(hex_string), 2)])) return ''.join(reversed([hex_string[i:i+2] for i in range(0, len(hex_string), 2)])).upper()
return little_endian_hex.upper()
def string_to_hex(self, string): def string_to_hex(self, string):
return ''.join(format(ord(char), '02X') for char in string) return ''.join(format(ord(char), '02X') for char in string)
@@ -118,29 +130,20 @@ class Utils:
return next((item for item in data[start:end] if item.lower() in search_item.lower()), None) return next((item for item in data[start:end] if item.lower() in search_item.lower()), None)
def normalize_path(self, path): def normalize_path(self, path):
# Remove all surrounding quotes if present
path = re.sub(r'^[\'"]+|[\'"]+$', '', path) path = re.sub(r'^[\'"]+|[\'"]+$', '', path)
# Remove trailing spaces
path = path.strip() path = path.strip()
# Expand ~ to the user's home directory
path = os.path.expanduser(path) path = os.path.expanduser(path)
# Normalize path separators for the target operating system if os.name == 'nt':
if os.name == 'nt': # Windows
# Replace single backslashes with forward slashes
path = path.replace('\\', '/') path = path.replace('\\', '/')
# Remove redundant slashes
path = re.sub(r'/+', '/', path) path = re.sub(r'/+', '/', path)
else: else:
# Remove backslashes
path = path.replace('\\', '') path = path.replace('\\', '')
# Normalize the path
path = os.path.normpath(path) path = os.path.normpath(path)
# Convert the path to an absolute path and normalize it according to the OS
return str(pathlib.Path(path).resolve()) return str(pathlib.Path(path).resolve())
def parse_darwin_version(self, darwin_version): def parse_darwin_version(self, darwin_version):
@@ -155,36 +158,47 @@ class Utils:
subprocess.run(['xdg-open', folder_path]) subprocess.run(['xdg-open', folder_path])
elif os.name == 'nt': elif os.name == 'nt':
os.startfile(folder_path) os.startfile(folder_path)
else:
raise NotImplementedError("This function is only supported on macOS, Windows, and Linux.")
def request_input(self, prompt="Press Enter to continue..."): def request_input(self, prompt="Press Enter to continue..."):
try: if sys.version_info[0] < 3:
user_response = input(prompt)
except NameError:
user_response = raw_input(prompt) user_response = raw_input(prompt)
else:
user_response = input(prompt)
if not isinstance(user_response, str): if not isinstance(user_response, str):
user_response = str(user_response) user_response = str(user_response)
return user_response return user_response
def clear_screen(self): def progress_bar(self, title, steps, current_step_index, done=False):
os.system('cls' if os.name=='nt' else 'clear') self.head(title)
print("")
if done:
for step in steps:
print(" [\033[92m✓\033[0m] {}".format(step))
else:
for i, step in enumerate(steps):
if i < current_step_index:
print(" [\033[92m✓\033[0m] {}".format(step))
elif i == current_step_index:
print(" [\033[1;93m>\033[0m] {}...".format(step))
else:
print(" [ ] {}".format(step))
print("")
def head(self, text = None, width = 68, resize=True): def head(self, text = None, width = 68, resize=True):
if resize: if resize:
self.adjust_window_size() self.adjust_window_size()
self.clear_screen() os.system('cls' if os.name=='nt' else 'clear')
if text == None: if text == None:
text = self.script_name text = self.script_name
separator = "#" * width separator = "" * (width - 2)
title = " {} ".format(text) title = " {} ".format(text)
if len(title) > width - 2: if len(title) > width - 2:
title = title[:width-4] + "..." title = title[:width-4] + "..."
title = title.center(width - 2) # Center the title within the width minus 2 for the '#' characters title = title.center(width - 2)
print("{}\n#{}#\n{}".format(separator, title, separator)) print("{}\n{}\n{}".format(separator, title, separator))
def adjust_window_size(self, content=""): def adjust_window_size(self, content=""):
lines = content.splitlines() lines = content.splitlines()
@@ -194,14 +208,27 @@ class Utils:
def exit_program(self): def exit_program(self):
self.head() self.head()
width = 68
print("") print("")
print("For more information, to report errors, or to contribute to the product:") print("For more information, to report errors, or to contribute to the product:".center(width))
print("* Facebook: https://www.facebook.com/macforce2601")
print("* Telegram: https://t.me/lzhoang2601")
print("* GitHub: https://github.com/lzhoang2801/OpCore-Simplify")
print("") print("")
print("Thank you for using our program!") separator = "" * (width - 4)
print(f"{separator}")
contacts = {
"Facebook": "https://www.facebook.com/macforce2601",
"Telegram": "https://t.me/lzhoang2601",
"GitHub": "https://github.com/lzhoang2801/OpCore-Simplify"
}
for platform, link in contacts.items():
line = f" * {platform}: {link}"
print(f"{line.ljust(width - 4)}")
print(f"{separator}")
print("") print("")
self.request_input("Press Enter to exit.") print("Thank you for using our program!".center(width))
print("")
self.request_input("Press Enter to exit.".center(width))
sys.exit(0) sys.exit(0)
+1 -1
View File
@@ -226,7 +226,7 @@ class WifiProfileExtractor:
self.utils.head("WiFi Profile Extractor") self.utils.head("WiFi Profile Extractor")
print("") print("")
print("\033[93mNote:\033[0m") print("\033[1;93mNote:\033[0m")
print("- When using itlwm kext, WiFi appears as Ethernet in macOS") print("- When using itlwm kext, WiFi appears as Ethernet in macOS")
print("- You'll need Heliport app to manage WiFi connections in macOS") print("- You'll need Heliport app to manage WiFi connections in macOS")
print("- This step will enable auto WiFi connections at boot time") print("- This step will enable auto WiFi connections at boot time")