private plugin installation

This commit is contained in:
Andrew
2025-11-05 04:55:38 +03:00
parent 3a835bdb63
commit f9aa1b3878
6 changed files with 227 additions and 4 deletions

View File

@@ -9,6 +9,7 @@ from src.installationthread import InstallationThread
from src.runaethread import RunAEThread
from src.runexethread import RunExeThread
from src.killaethread import KillAEThread
from src.pluginthread import PluginThread
from src.removeaethread import RemoveAEThread
from src.utils import (
check_aegnux_tip_marked, get_default_terminal, get_wine_bin_path_env,
@@ -40,6 +41,11 @@ class MainWindow(MainWindowUI):
self.remove_ae_thread = RemoveAEThread()
self.remove_ae_thread.finished_signal.connect(self._finished)
self.plugin_thread = PluginThread()
self.plugin_thread.log_signal.connect(self._log)
self.plugin_thread.progress_signal.connect(self.progress_bar.setValue)
self.plugin_thread.finished_signal.connect(self._finished)
self.alt_t_action = QAction(self)
self.alt_t_action.setShortcut(QKeySequence("Alt+T"))
self.alt_t_action.triggered.connect(self.run_command_alt_t)
@@ -56,6 +62,7 @@ class MainWindow(MainWindowUI):
self.ae_action.triggered.connect(self.run_ae_button_clicked)
self.exe_action.triggered.connect(self.run_exe_button_clicked)
self.reg_action.triggered.connect(self.reg_button_clicked)
self.plugininst_action.triggered.connect(self.install_plugins_button_clicked)
self.kill_action.triggered.connect(self.kill_ae_button_clicked)
self.log_action.triggered.connect(self.toggle_logs)
self.term_action.triggered.connect(self.run_command_alt_t)
@@ -74,6 +81,7 @@ class MainWindow(MainWindowUI):
self.runMenu.setEnabled(True)
self.browseMenu.setEnabled(True)
self.kill_action.setEnabled(True)
self.plugininst_action.setEnabled(True)
self.term_action.setEnabled(True)
else:
@@ -85,11 +93,13 @@ class MainWindow(MainWindowUI):
self.browseMenu.setEnabled(False)
self.kill_action.setEnabled(False)
self.term_action.setEnabled(False)
self.plugininst_action.setEnabled(False)
def _construct_menubar(self):
self.runMenu = self.menuBar().addMenu(gls('run_menu'))
self.ae_action = self.runMenu.addAction(gls('ae_action'))
self.exe_action = self.runMenu.addAction(gls('exe_action'))
self.plugininst_action = self.runMenu.addAction(gls('plugininst_action'))
self.reg_action = self.runMenu.addAction(gls('reg_action'))
self.browseMenu = self.menuBar().addMenu(gls('browse_menu'))
@@ -108,6 +118,8 @@ class MainWindow(MainWindowUI):
self.install_button.setEnabled(not lock)
self.run_button.setEnabled(not lock)
self.remove_aegnux_button.setEnabled(not lock)
self.runMenu.setEnabled(not lock)
@Slot()
def toggle_logs(self):
@@ -172,6 +184,29 @@ class MainWindow(MainWindowUI):
self.progress_bar.show()
self.install_thread.start()
@Slot()
def install_plugins_button_clicked(self):
QMessageBox.information(
self,
gls('plugin_note'),
gls('plugin_note_text')
)
filename, _ = QFileDialog.getOpenFileName(
self,
gls('offline_ae_zip_title'),
"",
"Zip Files (*.zip);;All Files (*)"
)
if filename == '':
return
self.plugin_thread.set_plugin_zip_filename(filename)
self.lock_ui()
self.progress_bar.show()
self.plugin_thread.start()
@Slot()
def run_ae_button_clicked(self):
self.lock_ui()

162
src/pluginthread.py Normal file
View File

@@ -0,0 +1,162 @@
import os
import shutil
from src.processthread import ProcessThread
from src.utils import get_private_plugins_unpack_path, get_ae_plugins_dir, get_wineprefix_dir
class PluginThread(ProcessThread):
def __init__(self):
super().__init__()
def set_plugin_zip_filename(self, filename: str):
self.plugin_zip_filename = filename
def run(self):
self.log_signal.emit('[DEBUG] Unpacking plugins from the archive...')
self.progress_signal.emit(5)
self.remove_ppu_dir()
ppu_dir = get_private_plugins_unpack_path()
self.unpack_zip(self.plugin_zip_filename, ppu_dir.as_posix())
self.progress_signal.emit(15)
self.install_aex_plugins()
self.install_cep_extensions()
self.install_presets()
self.run_installers()
self.remove_ppu_dir()
self.progress_signal.emit(95)
self.log_signal.emit('[INFO] The plugins have been installed')
self.finished_signal.emit(True)
self.progress_signal.emit(100)
def install_aex_plugins(self):
self.log_signal.emit('[DEBUG] Installing aex plugins...')
ppu_dir = get_private_plugins_unpack_path()
aex_src = ppu_dir.joinpath('aex')
for item in os.listdir(aex_src.as_posix()):
if self._is_cancelled:
self.cancelled.emit()
return
src_path = aex_src.joinpath(item)
dst_path = get_ae_plugins_dir().joinpath(item)
if os.path.isdir(src_path):
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
else:
shutil.copy2(src_path, dst_path)
self.log_signal.emit('[INFO] AEX plugins installed')
self.progress_signal.emit(30)
def install_presets(self):
self.log_signal.emit('[DEBUG] Installing presets...')
ppu_dir = get_private_plugins_unpack_path()
preset_src = ppu_dir.joinpath('preset-backup')
preset_dest = get_wineprefix_dir().joinpath('drive_c/users/relative/Documents/Adobe/After Effects 2024/User Presets')
os.makedirs(preset_dest, exist_ok=True)
for item in os.listdir(preset_src):
if self._is_cancelled:
self.cancelled.emit()
return
src_path = preset_src.joinpath(item)
dst_path = preset_dest.joinpath(item)
if os.path.isdir(src_path):
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
else:
shutil.copy2(src_path, dst_path)
self.log_signal.emit("[INFO] Presets installed")
self.progress_signal.emit(55)
def run_installers(self):
self.log_signal.emit('[DEBUG] Running installers...')
ppu_dir = get_private_plugins_unpack_path()
install_src = ppu_dir.joinpath('installer')
installers_counter = 0
for exe in os.listdir(install_src.as_posix()):
if exe.endswith('.exe') and exe not in ['E3D.exe', 'saber.exe']:
self.progress_signal.emit(55 + installers_counter * 3)
self.log_signal.emit(f"[INFO] Installing: {exe}")
self.run_command(
['wine', exe, '/verysilent', '/suppressmsgboxes'],
install_src.as_posix(), True
)
self.progress_signal.emit(70)
# Special handling for E3D and saber
for exe in ['E3D.exe', 'saber.exe']:
self.log_signal.emit(f"[INFO] Please manually install: {exe}")
self.run_command(
['wine', exe],
install_src.as_posix(), True
)
self.progress_signal.emit(85)
self.copy_element_files()
def copy_element_files(self):
self.log_signal.emit('[DEBUG] Copying Element files...')
ppu_dir = get_private_plugins_unpack_path()
install_src = ppu_dir.joinpath('installer')
video_copilot_dir = get_ae_plugins_dir().joinpath("VideoCopilot")
element_files = [
("Element.aex", "Element.aex"),
("Element.license", "Element.license")
]
for src_name, dst_name in element_files:
src_path = install_src.joinpath(src_name)
if os.path.exists(src_path):
shutil.copy2(src_path, os.path.join(video_copilot_dir, dst_name))
self.log_signal.emit(f"[INFO] {src_name} copied successfully")
self.log_signal.emit("[INFO] Element installed")
self.progress_signal.emit(90)
def install_cep_extensions(self):
self.log_signal.emit('[DEBUG] Installing CEP extensions...')
ppu_dir = get_private_plugins_unpack_path()
cep_dir = ppu_dir.joinpath('CEP')
cep_reg_file = cep_dir.joinpath("AddKeys.reg")
self.run_command(['wine', "regedit", cep_reg_file.as_posix()], in_prefix=True)
self.install_flow()
self.log_signal.emit("[INFO] CEP extensions installed")
self.progress_signal.emit(45)
def install_flow(self):
ppu_dir = get_private_plugins_unpack_path()
cep_dir = ppu_dir.joinpath('CEP')
self.log_signal.emit('[DEBUG] Installing Flow...')
flow_src = cep_dir.joinpath("flowv1.4.2")
cep_dst = get_wineprefix_dir().joinpath("drive_c/Program Files (x86)/Common Files/Adobe/CEP/extensions")
os.makedirs(cep_dst, exist_ok=True)
shutil.copytree(flow_src, os.path.join(cep_dst, "flowv1.4.2"), dirs_exist_ok=True)
self.log_signal.emit("[INFO] Flow installed")
def remove_ppu_dir(self):
ppu_dir = get_private_plugins_unpack_path()
try:
shutil.rmtree(ppu_dir.as_posix())
self.log_signal.emit('[DEBUG] Temporary folder removed successfully.')
except OSError as e:
self.log_signal.emit(f'[WARNING] Failed to remove temporary folder {ppu_dir}: {e}')

View File

@@ -204,4 +204,14 @@ def check_aegnux_tip_marked():
def mark_aegnux_tip_as_shown():
with open(get_aegnux_tip_marked_flag_path(), 'w') as f:
f.write('Press ALT+T to open up a terminal')
f.write('Press ALT+T to open up a terminal')
def get_private_plugins_unpack_path():
aegnux_dir = get_aegnux_installation_dir()
ppu_dir = aegnux_dir.joinpath('private-plugins')
if not os.path.exists(ppu_dir):
os.makedirs(ppu_dir)
return ppu_dir

View File

@@ -32,5 +32,11 @@ STRINGS = {
'cep_action': 'CEP directory',
'offline_note': 'Offline note',
'offline_note_text': 'Note that the .zip archive should contain After Effects from Program Files (including AfterFX.exe).',
'error': 'Error'
'error': 'Error',
'plugininst_action': 'Install private plugins from ZIP',
'plugin_note': 'Private plugins note',
'plugin_note_text': 'Those plugins are available at https://t.me/Aegnux',
'done_title': 'Done!',
'done_ae': 'AE has been installed.',
'done_plugins': 'The plugins have been installed.'
}

View File

@@ -32,5 +32,10 @@ STRINGS = {
'cep_action': 'Папка с CEP',
'offline_note': 'Внимание, оффлайн',
'offline_note_text': 'Учтите, что .zip-архив должен содержать After Effects из Program Files (включая AfterFX.exe).',
'error': 'Ошибка'
'error': 'Ошибка',
'plugininst_action': 'Установить приватные плагины из ZIP',
'plugin_note': 'Замечание к приватным плагинам',
'plugin_note_text': 'Эти плагины доступны здесь: https://t.me/Aegnux',
'done_ae': 'AE был установлен.',
'done_plugins': 'Плагины были установлены.'
}

View File

@@ -32,5 +32,10 @@ STRINGS = {
"cep_action": "Папка з CEP",
'offline_note': 'Увага, офлайн',
'offline_note_text': 'Зауважте, що .zip-архів повинен містити After Effects з Program Files (включаючи AfterFX.exe).',
'error': 'Помилка'
'error': 'Помилка',
'plugininst_action': 'Встановити приватні плагіни з ZIP',
'plugin_note': 'Примітка до приватних плагінів',
'plugin_note_text': 'Ці плагіни доступні тут: https://t.me/Aegnux',
'done_ae': 'AE було встановлено.',
'done_plugins': 'Плагіни було встановлено.'
}