Skip to content

Commit 8c6ca56

Browse files
committed
Fix indentation, add load_config_from_file; extract downloaded FFmpeg zip into bin/ and auto-update ffmpeg path (Tkinter + PyQt6)
1 parent 36e21f1 commit 8c6ca56

2 files changed

Lines changed: 122 additions & 8 deletions

File tree

GUI_pyqt6_WINFF.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import urllib.request
1111
import webbrowser
1212
from pathlib import Path
13+
import zipfile
14+
import shutil
1315

1416
from PyQt6 import QtWidgets, QtCore
1517
from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QLineEdit, QPushButton, QTextEdit, QComboBox, QFileDialog, QCheckBox, QHBoxLayout, QVBoxLayout
@@ -177,6 +179,44 @@ def select_ffmpeg(self):
177179
if file:
178180
self.ffmpeg_path.setText(file)
179181

182+
def _extract_ffmpeg_zip(self, zip_path, target_bin_dir):
183+
try:
184+
with zipfile.ZipFile(zip_path, 'r') as zf:
185+
temp_dir = target_bin_dir.parent / ('ffmpeg_tmp')
186+
if temp_dir.exists():
187+
shutil.rmtree(temp_dir)
188+
temp_dir.mkdir(parents=True, exist_ok=True)
189+
zf.extractall(path=temp_dir)
190+
191+
exe_name = 'ffmpeg.exe' if os.name == 'nt' else 'ffmpeg'
192+
found = None
193+
for root, dirs, files in os.walk(temp_dir):
194+
if exe_name in files:
195+
found = Path(root) / exe_name
196+
break
197+
if not found:
198+
for root, dirs, files in os.walk(temp_dir):
199+
for d in dirs:
200+
p = Path(root) / d / 'bin' / exe_name
201+
if p.exists():
202+
found = p
203+
break
204+
if found:
205+
break
206+
if found:
207+
target_bin_dir.mkdir(parents=True, exist_ok=True)
208+
target_path = target_bin_dir / exe_name
209+
shutil.copy2(found, target_path)
210+
if os.name != 'nt':
211+
target_path.chmod(0o755)
212+
shutil.rmtree(temp_dir)
213+
return str(target_path)
214+
else:
215+
shutil.rmtree(temp_dir)
216+
return None
217+
except Exception:
218+
return None
219+
180220
def download_ffmpeg_and_maybe_install(self):
181221
def _worker():
182222
try:
@@ -187,9 +227,14 @@ def _worker():
187227
out_path = downloads / url.split('/')[-1]
188228
QtWidgets.QMessageBox.information(self, 'Download', f'Baixando FFmpeg para {out_path} ...')
189229
urllib.request.urlretrieve(url, out_path)
190-
QtWidgets.QMessageBox.information(self, 'Download', f'Arquivo salvo em {out_path}')
230+
target_bin = Path(os.path.dirname(os.path.abspath(__file__))) / 'bin'
231+
extracted = self._extract_ffmpeg_zip(out_path, target_bin)
232+
if extracted:
233+
QtWidgets.QMessageBox.information(self, 'Download', f'FFmpeg extraído para {extracted}. Atualizando caminho...')
234+
self.ffmpeg_path.setText(extracted)
235+
else:
236+
QtWidgets.QMessageBox.warning(self, 'Download', f'Não foi possível extrair o executável FFmpeg automaticamente. O arquivo está em {out_path}')
191237

192-
# Ask user if they want to attempt installation via winget
193238
res = subprocess.run(['winget', '--version'], capture_output=True, text=True)
194239
if res.returncode == 0:
195240
ans = QtWidgets.QMessageBox.question(self, 'Instalar', 'Deseja tentar instalar via winget (Windows)?')

GUI_tkinter_WINFF.py

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import urllib.request
1414
import webbrowser
1515
from pathlib import Path
16+
import zipfile
17+
import shutil
1618

1719
try:
1820
import ffmpeg as ffmpeg_lib # optional: ffmpeg-python
@@ -45,6 +47,18 @@ def load_config(file_name):
4547
config.read(file_name)
4648
apply_saved_config()
4749

50+
def load_config_from_file():
51+
path = filedialog.askopenfilename(title="Carregar Configuração", filetypes=[("Arquivos INI", "*.ini")])
52+
if not path:
53+
return
54+
try:
55+
config.read(path)
56+
apply_saved_config()
57+
messagebox.showinfo('Configuração', f'Configuração carregada de {path}')
58+
except Exception as e:
59+
messagebox.showerror('Erro', f'Falha ao carregar configuração: {e}')
60+
61+
4862
def save_config():
4963
config_file_path = filedialog.asksaveasfilename(initialdir=os.getcwd(), title="Salvar Configuração", defaultextension=".ini",
5064
filetypes=[("Arquivos INI", "*.ini")])
@@ -143,29 +157,84 @@ def select_ffmpeg_executable():
143157
update_command_display()
144158

145159

160+
def _extract_ffmpeg_zip(zip_path, target_bin_dir):
161+
"""Extract ffmpeg binary from the downloaded zip into target_bin_dir.
162+
Returns path to extracted ffmpeg executable if found, else None."""
163+
try:
164+
with zipfile.ZipFile(zip_path, 'r') as zf:
165+
# Extract all to a temporary folder and search for ffmpeg/ffmpeg.exe
166+
temp_dir = target_bin_dir.parent / ("ffmpeg_tmp")
167+
if temp_dir.exists():
168+
shutil.rmtree(temp_dir)
169+
temp_dir.mkdir(parents=True, exist_ok=True)
170+
zf.extractall(path=temp_dir)
171+
172+
# Walk extracted tree and find ffmpeg executable
173+
exe_name = 'ffmpeg.exe' if os.name == 'nt' else 'ffmpeg'
174+
found = None
175+
for root, dirs, files in os.walk(temp_dir):
176+
if exe_name in files:
177+
found = Path(root) / exe_name
178+
break
179+
if not found:
180+
# Try common structure 'ffmpeg-*/bin/ffmpeg'
181+
for root, dirs, files in os.walk(temp_dir):
182+
for d in dirs:
183+
p = Path(root) / d / 'bin' / exe_name
184+
if p.exists():
185+
found = p
186+
break
187+
if found:
188+
break
189+
if found:
190+
target_bin_dir.mkdir(parents=True, exist_ok=True)
191+
target_path = target_bin_dir / exe_name
192+
shutil.copy2(found, target_path)
193+
# ensure executable bit on non-Windows
194+
if os.name != 'nt':
195+
target_path.chmod(0o755)
196+
# cleanup temp
197+
shutil.rmtree(temp_dir)
198+
return str(target_path)
199+
else:
200+
shutil.rmtree(temp_dir)
201+
return None
202+
except Exception:
203+
return None
204+
205+
146206
def download_ffmpeg_and_maybe_install():
147207
"""Download a FFmpeg build to the user's Downloads folder.
148-
On Windows offer to try winget install if available and the user agrees.
149-
Runs in a background thread to avoid blocking the UI."""
208+
On Windows: download zip, extract ffmpeg into ./bin and optionally try winget install.
209+
On non-Windows: open releases page in browser. Runs in background thread."""
150210
def _worker():
151211
try:
152212
downloads = Path.home() / 'Downloads'
153213
downloads.mkdir(parents=True, exist_ok=True)
154214
if os.name == 'nt':
155-
# Example Windows build (user-provided example)
215+
# Example Windows build URL (may be updated if releases change)
156216
url = 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n7.1-latest-win64-gpl-7.1.zip'
157217
out_path = downloads / url.split('/')[-1]
158218
messagebox.showinfo('Download', f'Baixando FFmpeg para {out_path} ...')
159219
urllib.request.urlretrieve(url, out_path)
160-
messagebox.showinfo('Download', f'Arquivo salvo em {out_path}')
220+
# Extract into repo's bin/ folder
221+
target_bin = Path(os.path.dirname(os.path.abspath(__file__))) / 'bin'
222+
extracted = _extract_ffmpeg_zip(out_path, target_bin)
223+
if extracted:
224+
messagebox.showinfo('Download', f'FFmpeg extraído para {extracted}. Atualizando caminho...')
225+
ffmpeg_path_entry.delete(0, tk.END)
226+
ffmpeg_path_entry.insert(0, extracted)
227+
config['DEFAULT']['ffmpeg_path'] = extracted
228+
with open(config_file, 'w') as configfile:
229+
config.write(configfile)
230+
else:
231+
messagebox.showwarning('Download', f'Não foi possível extrair o executável FFmpeg automaticamente. O arquivo está em {out_path}')
161232

162233
# Ask user if they want to attempt installation via winget
163234
if messagebox.askyesno('Instalar', 'Deseja tentar instalar via winget (Windows)?'):
164235
try:
165-
# Check winget availability
166236
res = subprocess.run(['winget', '--version'], capture_output=True, text=True)
167237
if res.returncode == 0:
168-
# Try a generic winget install for ffmpeg
169238
install_cmd = ['winget', 'install', 'ffmpeg', '-e']
170239
proc = subprocess.run(install_cmd, capture_output=True, text=True)
171240
if proc.returncode == 0:

0 commit comments

Comments
 (0)