Inicial, descargar y conversion basicas

This commit is contained in:
2026-08-27 14:38:59 +02:00
commit b05ea516ee
11 changed files with 611 additions and 0 deletions

0
gui/__init__.py Normal file
View File

63
gui/main_window.py Normal file
View File

@@ -0,0 +1,63 @@
from PyQt6.QtWidgets import (QMainWindow, QTabWidget, QProgressBar,
QStatusBar, QMessageBox)
from gui.tab_youtube import YoutubeTab
from gui.tab_converter import ConverterTab # <-- Nueva importación
from utils.updater import DependencyChecker
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("seteTools - Media")
self.resize(600, 350)
self.init_menu()
self.init_tabs()
self.init_statusbar()
self.check_dependencies()
def init_menu(self):
menubar = self.menuBar()
menu_actualizaciones = menubar.addMenu("Actualizaciones")
check_action = menu_actualizaciones.addAction("Buscar actualizaciones de binarios")
check_action.triggered.connect(self.force_update_check)
def init_tabs(self):
self.tabs = QTabWidget()
# Pestaña 1: Descarga YouTube
self.youtube_tab = YoutubeTab()
self.tabs.addTab(self.youtube_tab, "Descarga YouTube")
# Pestaña 2: Conversión con FFmpeg
self.converter_tab = ConverterTab()
self.tabs.addTab(self.converter_tab, "Convertidor FFmpeg")
self.setCentralWidget(self.tabs)
def init_statusbar(self):
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
self.progress_bar = QProgressBar()
self.progress_bar.setMaximumWidth(200)
self.progress_bar.hide()
self.statusBar.addPermanentWidget(self.progress_bar)
def check_dependencies(self):
self.thread = DependencyChecker()
self.thread.progress_signal.connect(self.update_progress)
self.thread.finished_signal.connect(self.on_check_finished)
self.progress_bar.show()
self.thread.start()
def update_progress(self, message, percent):
self.statusBar.showMessage(message)
self.progress_bar.setValue(percent)
def on_check_finished(self):
self.progress_bar.hide()
def force_update_check(self):
QMessageBox.information(self, "Actualizaciones", "Verificando componentes...")
self.check_dependencies()

141
gui/tab_converter.py Normal file
View File

@@ -0,0 +1,141 @@
import os
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout,
QLabel, QLineEdit, QPushButton, QComboBox,
QFileDialog, QMessageBox)
from utils.converter import MediaConverter
class ConverterTab(QWidget):
PRESETS = {
"MP4 Estándar (H.264 + AAC)": {"key": "mp4_std", "ext": ".mp4", "tag": "_converted"},
"MP4 Estándar (Máx. 1080p Vertical)": {"key": "mp4_1080p", "ext": ".mp4", "tag": "_1080p"},
"Audio MP3 Estándar (Estéreo 192 kbps)": {"key": "mp3_192k", "ext": ".mp3", "tag": "_audio"},
"Audio MP3 - Solo Canal 1 / Izquierdo (192 kbps)": {"key": "mp3_ch1", "ext": ".mp3", "tag": "_ch1"},
"Audio MP3 - Solo Canal 2 / Derecho (192 kbps)": {"key": "mp3_ch2", "ext": ".mp3", "tag": "_ch2"}
}
def __init__(self):
super().__init__()
self.converter_thread = None
self.initUI()
def initUI(self):
layout = QVBoxLayout()
# Archivo de entrada
layout.addWidget(QLabel("Archivo de entrada (In):"))
in_layout = QHBoxLayout()
self.in_input = QLineEdit()
self.in_input.setPlaceholderText("Selecciona un archivo de vídeo o audio...")
in_layout.addWidget(self.in_input)
self.in_browse_btn = QPushButton("Examinar")
self.in_browse_btn.clicked.connect(self.browse_input_file)
in_layout.addWidget(self.in_browse_btn)
layout.addLayout(in_layout)
# Combo de Presets
layout.addWidget(QLabel("Preset de conversión:"))
self.preset_combo = QComboBox()
for label in self.PRESETS.keys():
self.preset_combo.addItem(label)
self.preset_combo.currentIndexChanged.connect(self.on_preset_changed)
layout.addWidget(self.preset_combo)
# Archivo de salida
layout.addWidget(QLabel("Archivo de salida (Out):"))
out_layout = QHBoxLayout()
self.out_input = QLineEdit()
self.out_input.setPlaceholderText("Ruta del archivo de salida...")
out_layout.addWidget(self.out_input)
self.out_browse_btn = QPushButton("Examinar")
self.out_browse_btn.clicked.connect(self.browse_output_file)
out_layout.addWidget(self.out_browse_btn)
layout.addLayout(out_layout)
# Botón de Conversión
self.convert_btn = QPushButton("Iniciar Conversión")
self.convert_btn.clicked.connect(self.start_conversion)
layout.addWidget(self.convert_btn)
# Label de estado
self.status_label = QLabel("")
layout.addWidget(self.status_label)
layout.addStretch()
self.setLayout(layout)
def browse_input_file(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "Seleccionar archivo de entrada", "", "Archivos Multimedia (*.mkv *.mp4 *.avi *.mov *.m4a *.mp3 *.wav *.flac *.webm);;Todos los archivos (*.*)"
)
if file_path:
self.in_input.setText(file_path)
self.update_output_path_from_input(file_path)
def browse_output_file(self):
selected_preset = self.PRESETS[self.preset_combo.currentText()]
ext = selected_preset["ext"]
file_path, _ = QFileDialog.getSaveFileName(
self, "Guardar archivo como", self.out_input.text(), f"Archivo (*{ext})"
)
if file_path:
self.out_input.setText(file_path)
def update_output_path_from_input(self, input_path):
base_path, _ = os.path.splitext(input_path)
selected_preset = self.PRESETS[self.preset_combo.currentText()]
new_output = f"{base_path}{selected_preset['tag']}{selected_preset['ext']}"
self.out_input.setText(new_output)
def on_preset_changed(self):
input_path = self.in_input.text().strip()
if input_path:
self.update_output_path_from_input(input_path)
else:
current_out = self.out_input.text().strip()
if current_out:
base_path, _ = os.path.splitext(current_out)
selected_preset = self.PRESETS[self.preset_combo.currentText()]
self.out_input.setText(f"{base_path}{selected_preset['ext']}")
def start_conversion(self):
input_file = self.in_input.text().strip()
output_file = self.out_input.text().strip()
selected_preset = self.PRESETS[self.preset_combo.currentText()]
if not input_file or not os.path.exists(input_file):
QMessageBox.warning(self, "Atención", "Por favor, selecciona un archivo de entrada válido.")
return
if not output_file:
QMessageBox.warning(self, "Atención", "Especifica la ruta del archivo de salida.")
return
self.set_inputs_enabled(False)
self.status_label.setText("Iniciando conversión...")
self.converter_thread = MediaConverter(input_file, output_file, selected_preset["key"])
self.converter_thread.progress_signal.connect(self.update_status)
self.converter_thread.finished_signal.connect(self.on_conversion_finished)
self.converter_thread.start()
def update_status(self, message):
self.status_label.setText(message)
def on_conversion_finished(self, success, message):
self.set_inputs_enabled(True)
self.status_label.setText("")
if success:
QMessageBox.information(self, "Éxito", message)
else:
QMessageBox.critical(self, "Error", message)
def set_inputs_enabled(self, enabled: bool):
self.in_input.setEnabled(enabled)
self.in_browse_btn.setEnabled(enabled)
self.out_input.setEnabled(enabled)
self.out_browse_btn.setEnabled(enabled)
self.preset_combo.setEnabled(enabled)
self.convert_btn.setEnabled(enabled)

90
gui/tab_youtube.py Normal file
View File

@@ -0,0 +1,90 @@
import os
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout,QLabel, QLineEdit, QPushButton, QFileDialog, QMessageBox)
from utils.downloader import VideoDownloader
class YoutubeTab(QWidget):
def __init__(self):
super().__init__()
self.downloader_thread = None
self.initUI()
def initUI(self):
layout = QVBoxLayout()
# Input URL
layout.addWidget(QLabel("URL del vídeo:"))
self.url_input = QLineEdit()
self.url_input.setPlaceholderText("https://www.youtube.com/watch?v=...")
layout.addWidget(self.url_input)
# Input Ruta de destino
layout.addWidget(QLabel("Ruta de destino:"))
path_layout = QHBoxLayout()
self.path_input = QLineEdit()
# Carpeta por defecto: Descargas del usuario
default_path = os.path.join(os.path.expanduser("~"), "Downloads")
self.path_input.setText(default_path)
path_layout.addWidget(self.path_input)
self.browse_btn = QPushButton("Examinar")
self.browse_btn.clicked.connect(self.browse_folder)
path_layout.addWidget(self.browse_btn)
layout.addLayout(path_layout)
# Botón de Descarga
self.download_btn = QPushButton("Descargar Vídeo MP4")
self.download_btn.clicked.connect(self.start_download)
layout.addWidget(self.download_btn)
# Label de Estado local
self.status_label = QLabel("")
layout.addWidget(self.status_label)
layout.addStretch()
self.setLayout(layout)
def browse_folder(self):
folder = QFileDialog.getExistingDirectory(self, "Seleccionar carpeta de destino")
if folder:
self.path_input.setText(folder)
def start_download(self):
url = self.url_input.text().strip()
save_path = self.path_input.text().strip()
if not url:
QMessageBox.warning(self, "Atención", "Por favor, introduce una URL válida.")
return
if not os.path.exists(save_path):
QMessageBox.warning(self, "Atención", "La ruta de destino seleccionada no existe.")
return
# Bloquear controles para evitar descargas simultáneas
self.set_inputs_enabled(False)
self.status_label.setText("Iniciando proceso...")
# Iniciar hilo en segundo plano
self.downloader_thread = VideoDownloader(url, save_path)
self.downloader_thread.progress_signal.connect(self.update_status)
self.downloader_thread.finished_signal.connect(self.on_download_finished)
self.downloader_thread.start()
def update_status(self, message):
self.status_label.setText(message)
def on_download_finished(self, success, message):
self.set_inputs_enabled(True)
self.status_label.setText("")
if success:
QMessageBox.information(self, "Éxito", message)
self.url_input.clear()
else:
QMessageBox.critical(self, "Error", message)
def set_inputs_enabled(self, enabled: bool):
self.url_input.setEnabled(enabled)
self.path_input.setEnabled(enabled)
self.browse_btn.setEnabled(enabled)
self.download_btn.setEnabled(enabled)