Skip to content

Commit f9aa1b3

Browse files
private plugin installation
1 parent 3a835bd commit f9aa1b3

File tree

6 files changed

+227
-4
lines changed

6 files changed

+227
-4
lines changed

src/mainwindow.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from src.runaethread import RunAEThread
1010
from src.runexethread import RunExeThread
1111
from src.killaethread import KillAEThread
12+
from src.pluginthread import PluginThread
1213
from src.removeaethread import RemoveAEThread
1314
from src.utils import (
1415
check_aegnux_tip_marked, get_default_terminal, get_wine_bin_path_env,
@@ -40,6 +41,11 @@ def __init__(self):
4041
self.remove_ae_thread = RemoveAEThread()
4142
self.remove_ae_thread.finished_signal.connect(self._finished)
4243

44+
self.plugin_thread = PluginThread()
45+
self.plugin_thread.log_signal.connect(self._log)
46+
self.plugin_thread.progress_signal.connect(self.progress_bar.setValue)
47+
self.plugin_thread.finished_signal.connect(self._finished)
48+
4349
self.alt_t_action = QAction(self)
4450
self.alt_t_action.setShortcut(QKeySequence("Alt+T"))
4551
self.alt_t_action.triggered.connect(self.run_command_alt_t)
@@ -56,6 +62,7 @@ def __init__(self):
5662
self.ae_action.triggered.connect(self.run_ae_button_clicked)
5763
self.exe_action.triggered.connect(self.run_exe_button_clicked)
5864
self.reg_action.triggered.connect(self.reg_button_clicked)
65+
self.plugininst_action.triggered.connect(self.install_plugins_button_clicked)
5966
self.kill_action.triggered.connect(self.kill_ae_button_clicked)
6067
self.log_action.triggered.connect(self.toggle_logs)
6168
self.term_action.triggered.connect(self.run_command_alt_t)
@@ -74,6 +81,7 @@ def init_installation(self):
7481
self.runMenu.setEnabled(True)
7582
self.browseMenu.setEnabled(True)
7683
self.kill_action.setEnabled(True)
84+
self.plugininst_action.setEnabled(True)
7785
self.term_action.setEnabled(True)
7886

7987
else:
@@ -85,11 +93,13 @@ def init_installation(self):
8593
self.browseMenu.setEnabled(False)
8694
self.kill_action.setEnabled(False)
8795
self.term_action.setEnabled(False)
96+
self.plugininst_action.setEnabled(False)
8897

8998
def _construct_menubar(self):
9099
self.runMenu = self.menuBar().addMenu(gls('run_menu'))
91100
self.ae_action = self.runMenu.addAction(gls('ae_action'))
92101
self.exe_action = self.runMenu.addAction(gls('exe_action'))
102+
self.plugininst_action = self.runMenu.addAction(gls('plugininst_action'))
93103
self.reg_action = self.runMenu.addAction(gls('reg_action'))
94104

95105
self.browseMenu = self.menuBar().addMenu(gls('browse_menu'))
@@ -108,6 +118,8 @@ def lock_ui(self, lock: bool = True):
108118
self.install_button.setEnabled(not lock)
109119
self.run_button.setEnabled(not lock)
110120
self.remove_aegnux_button.setEnabled(not lock)
121+
122+
self.runMenu.setEnabled(not lock)
111123

112124
@Slot()
113125
def toggle_logs(self):
@@ -172,6 +184,29 @@ def install_button_clicked(self):
172184
self.progress_bar.show()
173185
self.install_thread.start()
174186

187+
@Slot()
188+
def install_plugins_button_clicked(self):
189+
QMessageBox.information(
190+
self,
191+
gls('plugin_note'),
192+
gls('plugin_note_text')
193+
)
194+
195+
filename, _ = QFileDialog.getOpenFileName(
196+
self,
197+
gls('offline_ae_zip_title'),
198+
"",
199+
"Zip Files (*.zip);;All Files (*)"
200+
)
201+
if filename == '':
202+
return
203+
204+
self.plugin_thread.set_plugin_zip_filename(filename)
205+
206+
self.lock_ui()
207+
self.progress_bar.show()
208+
self.plugin_thread.start()
209+
175210
@Slot()
176211
def run_ae_button_clicked(self):
177212
self.lock_ui()

src/pluginthread.py

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import os
2+
import shutil
3+
from src.processthread import ProcessThread
4+
from src.utils import get_private_plugins_unpack_path, get_ae_plugins_dir, get_wineprefix_dir
5+
6+
7+
class PluginThread(ProcessThread):
8+
def __init__(self):
9+
super().__init__()
10+
11+
def set_plugin_zip_filename(self, filename: str):
12+
self.plugin_zip_filename = filename
13+
14+
def run(self):
15+
self.log_signal.emit('[DEBUG] Unpacking plugins from the archive...')
16+
self.progress_signal.emit(5)
17+
self.remove_ppu_dir()
18+
19+
ppu_dir = get_private_plugins_unpack_path()
20+
self.unpack_zip(self.plugin_zip_filename, ppu_dir.as_posix())
21+
self.progress_signal.emit(15)
22+
23+
self.install_aex_plugins()
24+
self.install_cep_extensions()
25+
self.install_presets()
26+
self.run_installers()
27+
28+
self.remove_ppu_dir()
29+
self.progress_signal.emit(95)
30+
self.log_signal.emit('[INFO] The plugins have been installed')
31+
32+
self.finished_signal.emit(True)
33+
self.progress_signal.emit(100)
34+
35+
def install_aex_plugins(self):
36+
self.log_signal.emit('[DEBUG] Installing aex plugins...')
37+
38+
ppu_dir = get_private_plugins_unpack_path()
39+
aex_src = ppu_dir.joinpath('aex')
40+
41+
for item in os.listdir(aex_src.as_posix()):
42+
if self._is_cancelled:
43+
self.cancelled.emit()
44+
return
45+
src_path = aex_src.joinpath(item)
46+
dst_path = get_ae_plugins_dir().joinpath(item)
47+
48+
if os.path.isdir(src_path):
49+
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
50+
else:
51+
shutil.copy2(src_path, dst_path)
52+
53+
self.log_signal.emit('[INFO] AEX plugins installed')
54+
self.progress_signal.emit(30)
55+
56+
def install_presets(self):
57+
self.log_signal.emit('[DEBUG] Installing presets...')
58+
59+
ppu_dir = get_private_plugins_unpack_path()
60+
preset_src = ppu_dir.joinpath('preset-backup')
61+
preset_dest = get_wineprefix_dir().joinpath('drive_c/users/relative/Documents/Adobe/After Effects 2024/User Presets')
62+
63+
os.makedirs(preset_dest, exist_ok=True)
64+
for item in os.listdir(preset_src):
65+
if self._is_cancelled:
66+
self.cancelled.emit()
67+
return
68+
src_path = preset_src.joinpath(item)
69+
dst_path = preset_dest.joinpath(item)
70+
if os.path.isdir(src_path):
71+
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
72+
else:
73+
shutil.copy2(src_path, dst_path)
74+
75+
self.log_signal.emit("[INFO] Presets installed")
76+
self.progress_signal.emit(55)
77+
78+
def run_installers(self):
79+
self.log_signal.emit('[DEBUG] Running installers...')
80+
ppu_dir = get_private_plugins_unpack_path()
81+
install_src = ppu_dir.joinpath('installer')
82+
83+
installers_counter = 0
84+
85+
for exe in os.listdir(install_src.as_posix()):
86+
if exe.endswith('.exe') and exe not in ['E3D.exe', 'saber.exe']:
87+
self.progress_signal.emit(55 + installers_counter * 3)
88+
89+
self.log_signal.emit(f"[INFO] Installing: {exe}")
90+
self.run_command(
91+
['wine', exe, '/verysilent', '/suppressmsgboxes'],
92+
install_src.as_posix(), True
93+
)
94+
95+
self.progress_signal.emit(70)
96+
97+
# Special handling for E3D and saber
98+
for exe in ['E3D.exe', 'saber.exe']:
99+
self.log_signal.emit(f"[INFO] Please manually install: {exe}")
100+
self.run_command(
101+
['wine', exe],
102+
install_src.as_posix(), True
103+
)
104+
105+
self.progress_signal.emit(85)
106+
self.copy_element_files()
107+
108+
def copy_element_files(self):
109+
self.log_signal.emit('[DEBUG] Copying Element files...')
110+
111+
ppu_dir = get_private_plugins_unpack_path()
112+
install_src = ppu_dir.joinpath('installer')
113+
114+
video_copilot_dir = get_ae_plugins_dir().joinpath("VideoCopilot")
115+
element_files = [
116+
("Element.aex", "Element.aex"),
117+
("Element.license", "Element.license")
118+
]
119+
120+
for src_name, dst_name in element_files:
121+
src_path = install_src.joinpath(src_name)
122+
if os.path.exists(src_path):
123+
shutil.copy2(src_path, os.path.join(video_copilot_dir, dst_name))
124+
self.log_signal.emit(f"[INFO] {src_name} copied successfully")
125+
126+
self.log_signal.emit("[INFO] Element installed")
127+
self.progress_signal.emit(90)
128+
129+
def install_cep_extensions(self):
130+
self.log_signal.emit('[DEBUG] Installing CEP extensions...')
131+
132+
ppu_dir = get_private_plugins_unpack_path()
133+
cep_dir = ppu_dir.joinpath('CEP')
134+
135+
cep_reg_file = cep_dir.joinpath("AddKeys.reg")
136+
self.run_command(['wine', "regedit", cep_reg_file.as_posix()], in_prefix=True)
137+
138+
self.install_flow()
139+
140+
self.log_signal.emit("[INFO] CEP extensions installed")
141+
self.progress_signal.emit(45)
142+
143+
def install_flow(self):
144+
ppu_dir = get_private_plugins_unpack_path()
145+
cep_dir = ppu_dir.joinpath('CEP')
146+
147+
self.log_signal.emit('[DEBUG] Installing Flow...')
148+
149+
flow_src = cep_dir.joinpath("flowv1.4.2")
150+
cep_dst = get_wineprefix_dir().joinpath("drive_c/Program Files (x86)/Common Files/Adobe/CEP/extensions")
151+
152+
os.makedirs(cep_dst, exist_ok=True)
153+
shutil.copytree(flow_src, os.path.join(cep_dst, "flowv1.4.2"), dirs_exist_ok=True)
154+
self.log_signal.emit("[INFO] Flow installed")
155+
156+
def remove_ppu_dir(self):
157+
ppu_dir = get_private_plugins_unpack_path()
158+
try:
159+
shutil.rmtree(ppu_dir.as_posix())
160+
self.log_signal.emit('[DEBUG] Temporary folder removed successfully.')
161+
except OSError as e:
162+
self.log_signal.emit(f'[WARNING] Failed to remove temporary folder {ppu_dir}: {e}')

src/utils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,14 @@ def check_aegnux_tip_marked():
204204

205205
def mark_aegnux_tip_as_shown():
206206
with open(get_aegnux_tip_marked_flag_path(), 'w') as f:
207-
f.write('Press ALT+T to open up a terminal')
207+
f.write('Press ALT+T to open up a terminal')
208+
209+
210+
def get_private_plugins_unpack_path():
211+
aegnux_dir = get_aegnux_installation_dir()
212+
ppu_dir = aegnux_dir.joinpath('private-plugins')
213+
214+
if not os.path.exists(ppu_dir):
215+
os.makedirs(ppu_dir)
216+
217+
return ppu_dir

translations/en_US.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,11 @@
3232
'cep_action': 'CEP directory',
3333
'offline_note': 'Offline note',
3434
'offline_note_text': 'Note that the .zip archive should contain After Effects from Program Files (including AfterFX.exe).',
35-
'error': 'Error'
35+
'error': 'Error',
36+
'plugininst_action': 'Install private plugins from ZIP',
37+
'plugin_note': 'Private plugins note',
38+
'plugin_note_text': 'Those plugins are available at https://t.me/Aegnux',
39+
'done_title': 'Done!',
40+
'done_ae': 'AE has been installed.',
41+
'done_plugins': 'The plugins have been installed.'
3642
}

translations/ru_RU.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,10 @@
3232
'cep_action': 'Папка с CEP',
3333
'offline_note': 'Внимание, оффлайн',
3434
'offline_note_text': 'Учтите, что .zip-архив должен содержать After Effects из Program Files (включая AfterFX.exe).',
35-
'error': 'Ошибка'
35+
'error': 'Ошибка',
36+
'plugininst_action': 'Установить приватные плагины из ZIP',
37+
'plugin_note': 'Замечание к приватным плагинам',
38+
'plugin_note_text': 'Эти плагины доступны здесь: https://t.me/Aegnux',
39+
'done_ae': 'AE был установлен.',
40+
'done_plugins': 'Плагины были установлены.'
3641
}

translations/uk_UA.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,10 @@
3232
"cep_action": "Папка з CEP",
3333
'offline_note': 'Увага, офлайн',
3434
'offline_note_text': 'Зауважте, що .zip-архів повинен містити After Effects з Program Files (включаючи AfterFX.exe).',
35-
'error': 'Помилка'
35+
'error': 'Помилка',
36+
'plugininst_action': 'Встановити приватні плагіни з ZIP',
37+
'plugin_note': 'Примітка до приватних плагінів',
38+
'plugin_note_text': 'Ці плагіни доступні тут: https://t.me/Aegnux',
39+
'done_ae': 'AE було встановлено.',
40+
'done_plugins': 'Плагіни було встановлено.'
3641
}

0 commit comments

Comments
 (0)