#!/usr/bin/env -S uv run --script
"""
Dialog-Klassen für den Video Download Helper
"""
import os
import subprocess
from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QFormLayout, QLineEdit, QTextEdit,
QPushButton, QComboBox, QCheckBox, QTabWidget, QWidget,
QHBoxLayout, QGroupBox, QLabel, QDialogButtonBox,
QFileDialog, QMessageBox)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from config import get_base_path, SERIES_TEMPLATE
from utils import set_window_icon
from download_threads import YtDlpDownloadThread
class PresetDialog(QDialog):
def __init__(self, parent=None, preset_data=None):
super().__init__(parent)
self.setWindowTitle("Preset erstellen/bearbeiten")
self.resize(500, 450)
# Entferne den Hilfe-Button (Fragezeichen) in der Titelleiste
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
# Icon für den Dialog setzen
set_window_icon(self)
self.preset_data = preset_data or {
"name": "",
"description": "",
"args": "",
"has_series_template": False,
"series_template": SERIES_TEMPLATE,
"series": "",
"season": "1",
"episode": "1",
"extension": ".mkv",
"custom_path": "",
"is_audio": False,
"custom_output_template": False,
"output_template": "%(title)s.%(ext)s"
}
self.setup_ui()
def setup_ui(self):
layout = QVBoxLayout()
# Tabs hinzufügen
tabs = QTabWidget()
# Tab 1: Grundeinstellungen
basic_tab = QWidget()
form_layout = QFormLayout()
self.name_edit = QLineEdit(self.preset_data["name"])
self.description_edit = QLineEdit(self.preset_data["description"])
self.args_edit = QTextEdit(self.preset_data["args"])
form_layout.addRow("Name:", self.name_edit)
form_layout.addRow("Beschreibung:", self.description_edit)
form_layout.addRow("yt-dlp Argumente:", self.args_edit)
# Eigener Pfad (immer sichtbar, mit Durchsuchen) - hierher verschoben
self.custom_path_edit = QLineEdit(self.preset_data.get("custom_path", ""))
self.custom_path_edit.setPlaceholderText("Optional: Eigener Zielordner für Download")
custom_path_hbox = QHBoxLayout()
custom_path_hbox.addWidget(self.custom_path_edit)
self.custom_path_browse_btn = QPushButton("Durchsuchen...")
self.custom_path_browse_btn.clicked.connect(self.browse_custom_path)
custom_path_hbox.addWidget(self.custom_path_browse_btn)
form_layout.addRow("Eigener Pfad:", custom_path_hbox)
# Audio-Preset Checkbox
self.is_audio_cb = QCheckBox("Ist Audio-Preset (kein Remux nach MKV)")
self.is_audio_cb.setChecked(self.preset_data.get("is_audio", False))
form_layout.addRow(self.is_audio_cb)
# Referer
self.referer_edit = QLineEdit(self.preset_data.get("referer", ""))
self.referer_edit.setPlaceholderText("Optional: Referer-Link für --referer=")
form_layout.addRow("Referer:", self.referer_edit)
# HLS-ffmpeg Checkbox
self.hls_ffmpeg_cb = QCheckBox("HLS-Streams mit ffmpeg herunterladen (--downloader ffmpeg --hls-use-mpegts)")
self.hls_ffmpeg_cb.setChecked(self.preset_data.get("hls_ffmpeg", False))
form_layout.addRow(self.hls_ffmpeg_cb)
basic_tab.setLayout(form_layout)
tabs.addTab(basic_tab, "Grundeinstellungen")
# Tab 2: Untertitel
subtitle_tab = QWidget()
subtitle_layout = QFormLayout()
# Untertitel-Optionen
self.sublang_edit = QLineEdit(self.preset_data.get("sublang", ""))
self.sublang_edit.setPlaceholderText("z.B. de, en, de,en ...")
subtitle_layout.addRow("Untertitelsprache:", self.sublang_edit)
self.embed_subs_cb = QCheckBox("Untertitel einbetten (--embed-subs)")
self.embed_subs_cb.setChecked(self.preset_data.get("embed_subs", False))
subtitle_layout.addRow(self.embed_subs_cb)
# Untertitel-Format Dropdown
self.subformat_combo = QComboBox()
self.subformat_combo.addItem("(keine Konvertierung)", "")
self.subformat_combo.addItem("srt", "srt")
self.subformat_combo.addItem("ass", "ass")
self.subformat_combo.addItem("tx3g", "tx3g")
# Vorbelegen
subformat = self.preset_data.get("subformat", "")
idx = self.subformat_combo.findData(subformat)
if idx >= 0:
self.subformat_combo.setCurrentIndex(idx)
subtitle_layout.addRow("Untertitel-Format:", self.subformat_combo)
subtitle_tab.setLayout(subtitle_layout)
tabs.addTab(subtitle_tab, "Untertitel")
# Tab 3: Output Template
output_tab = QWidget()
output_layout = QFormLayout()
# Custom Output Template Checkbox
self.custom_output_template_cb = QCheckBox("Eigenen Namen verwenden")
self.custom_output_template_cb.setChecked(self.preset_data.get("custom_output_template", False))
output_layout.addRow(self.custom_output_template_cb)
# Output Template Field
self.output_template_edit = QLineEdit(self.preset_data.get("output_template", "%(title)s.%(ext)s"))
self.output_template_edit.setPlaceholderText("z.B. %(title)s.%(ext)s, %(uploader)s/%(title)s.%(ext)s")
output_layout.addRow("Name:", self.output_template_edit)
# Add examples and documentation link
examples_label = QLabel("Beispiele:
" +
"%(title)s-%(id)s.%(ext)s
" +
"%(uploader)s/%(title)s.%(ext)s
" +
"%(playlist)s/%(playlist_index)s-%(title)s.%(ext)s
" +
"Mehr Beispiele in der yt-dlp Dokumentation")
examples_label.setOpenExternalLinks(True)
examples_label.setTextFormat(Qt.RichText)
output_layout.addRow(examples_label)
output_tab.setLayout(output_layout)
tabs.addTab(output_tab, "Name")
# Tab 4: Authentifizierung
auth_tab = QWidget()
auth_layout = QFormLayout()
# Login-Felder
self.username_edit = QLineEdit(self.preset_data.get("username", ""))
self.username_edit.setPlaceholderText("Optional: Benutzername für Login (-u)")
auth_layout.addRow("Benutzername:", self.username_edit)
pw_hbox = QHBoxLayout()
self.password_edit = QLineEdit(self.preset_data.get("password", ""))
self.password_edit.setEchoMode(QLineEdit.Password)
self.password_edit.setPlaceholderText("Optional: Passwort für Login (-p)")
self.show_pw_cb = QCheckBox("Passwort anzeigen")
self.show_pw_cb.toggled.connect(self.toggle_password_visible)
pw_hbox.addWidget(self.password_edit)
pw_hbox.addWidget(self.show_pw_cb)
auth_layout.addRow("Passwort:", pw_hbox)
pw_hint = QLabel("Hinweis: Passwörter werden im Klartext lokal gespeichert!")
pw_hint.setStyleSheet("color: red;")
auth_layout.addRow(pw_hint)
auth_tab.setLayout(auth_layout)
tabs.addTab(auth_tab, "Authentifizierung")
# Tab 4: Pfade & Serien
path_tab = QWidget()
path_layout = QFormLayout()
# Serien-Template
self.series_box = QGroupBox("Serien-Template aktivieren")
self.series_box.setCheckable(True)
self.series_box.setChecked(self.preset_data.get("has_series_template", False))
series_layout = QFormLayout()
self.template_edit = QLineEdit(self.preset_data.get("series_template", SERIES_TEMPLATE))
self.series_edit = QLineEdit(self.preset_data.get("series", ""))
self.season_edit = QLineEdit(self.preset_data.get("season", "1"))
self.episode_edit = QLineEdit(self.preset_data.get("episode", "1"))
series_layout.addRow("Template:", self.template_edit)
series_layout.addRow("Serie:", self.series_edit)
series_layout.addRow("Staffel:", self.season_edit)
series_layout.addRow("Folge:", self.episode_edit)
help_text = QLabel("Verwende {series}, {season}, {episode}, %(ext)s und {path} im Template.")
series_layout.addRow(help_text)
self.series_box.setLayout(series_layout)
path_layout.addWidget(self.series_box)
path_tab.setLayout(path_layout)
tabs.addTab(path_tab, "Serien")
# Tab 5: ADN (vorher Experte)
adn_tab = QWidget()
adn_layout = QVBoxLayout()
# F-Option und Format-ID Checkbox
self.use_format_selection_cb = QCheckBox("Format-Auswahl aktivieren")
self.use_format_selection_cb.setChecked(self.preset_data.get("use_format_selection", False))
self.use_format_selection_cb.toggled.connect(self.toggle_format_selection)
adn_layout.addWidget(self.use_format_selection_cb)
# Beschreibung der Format-Auswahl
format_desc = QLabel(
"Diese Option führt beim Start des Downloads zuerst 'yt-dlp -F' aus,\n"
"um verfügbare Formate anzuzeigen. Anschließend wird nach einer Format-ID gefragt."
)
adn_layout.addWidget(format_desc)
# Dual-Audio (Jap+Ger) und Untertitel Muxing aktivieren
self.use_dual_audio_cb = QCheckBox("Dual-Audio Muxing aktivieren")
self.use_dual_audio_cb.setChecked(self.preset_data.get("use_dual_audio", False))
self.use_dual_audio_cb.toggled.connect(self.toggle_dual_audio)
adn_layout.addWidget(self.use_dual_audio_cb)
# Dual-Audio Gruppe
self.dual_audio_group = QGroupBox("Dual-Audio Einstellungen")
self.dual_audio_group.setEnabled(self.preset_data.get("use_dual_audio", False))
dual_form = QFormLayout()
# Format ID Präfixe
self.jap_prefix_edit = QLineEdit(self.preset_data.get("jap_prefix", "vostde"))
dual_form.addRow("Prefix für japanische Audio:", self.jap_prefix_edit)
self.ger_prefix_edit = QLineEdit(self.preset_data.get("ger_prefix", "vde"))
dual_form.addRow("Prefix für deutsche Audio:", self.ger_prefix_edit)
# Suffix (Standard: -1)
self.format_suffix_edit = QLineEdit(self.preset_data.get("format_suffix", "-1"))
dual_form.addRow("Format-Suffix:", self.format_suffix_edit)
# Dateinamen für temporäre Dateien
self.temp_jp_filename_edit = QLineEdit(self.preset_data.get("temp_jp_filename", "video_jp.mp4"))
dual_form.addRow("Temp. Dateiname JP:", self.temp_jp_filename_edit)
self.temp_de_filename_edit = QLineEdit(self.preset_data.get("temp_de_filename", "video_de.mp4"))
dual_form.addRow("Temp. Dateiname DE:", self.temp_de_filename_edit)
# Untertitel-Dateien
self.de_sub_filename_edit = QLineEdit(self.preset_data.get("de_sub_filename", "subs.de.ass"))
dual_form.addRow("DE Untertitel-Datei:", self.de_sub_filename_edit)
self.de_forced_sub_filename_edit = QLineEdit(self.preset_data.get("de_forced_sub_filename", "subs.de.forced.ass"))
dual_form.addRow("DE forced Untertitel:", self.de_forced_sub_filename_edit)
# Cleanup-Option
self.cleanup_temp_cb = QCheckBox("Temporäre Dateien nach dem Muxing löschen")
self.cleanup_temp_cb.setChecked(self.preset_data.get("cleanup_temp", True))
dual_form.addRow(self.cleanup_temp_cb)
self.dual_audio_group.setLayout(dual_form)
adn_layout.addWidget(self.dual_audio_group)
adn_tab.setLayout(adn_layout)
# ADN Tab nur hinzufügen, wenn aktiviert
self.adn_tab_index = None
if self.parent() and self.parent().config.get("enable_adn_tab", False):
self.adn_tab_index = tabs.addTab(adn_tab, "ADN")
layout.addWidget(tabs)
buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
layout.addWidget(buttons)
self.setLayout(layout)
def toggle_password_visible(self, checked):
self.password_edit.setEchoMode(QLineEdit.Normal if checked else QLineEdit.Password)
def toggle_format_selection(self, checked):
# Diese Methode setzt Flags, wenn die Format-Auswahl aktiviert wird
pass
def toggle_dual_audio(self, checked):
# Aktiviere/Deaktiviere die Dual-Audio-Einstellungen
self.dual_audio_group.setEnabled(checked)
def get_preset_data(self):
return {
"name": self.name_edit.text(),
"description": self.description_edit.text(),
"args": self.args_edit.toPlainText(),
"has_series_template": self.series_box.isChecked(),
"series_template": self.template_edit.text(),
"series": self.series_edit.text(),
"season": self.season_edit.text(),
"episode": self.episode_edit.text(),
"custom_path": self.custom_path_edit.text(),
"is_audio": self.is_audio_cb.isChecked(),
"username": self.username_edit.text(),
"password": self.password_edit.text(),
"referer": self.referer_edit.text(),
"hls_ffmpeg": self.hls_ffmpeg_cb.isChecked(),
"sublang": self.sublang_edit.text(),
"embed_subs": self.embed_subs_cb.isChecked(),
"subformat": self.subformat_combo.currentData(),
"use_format_selection": self.use_format_selection_cb.isChecked(),
"use_dual_audio": self.use_dual_audio_cb.isChecked(),
"jap_prefix": self.jap_prefix_edit.text(),
"ger_prefix": self.ger_prefix_edit.text(),
"format_suffix": self.format_suffix_edit.text(),
"temp_jp_filename": self.temp_jp_filename_edit.text(),
"temp_de_filename": self.temp_de_filename_edit.text(),
"de_sub_filename": self.de_sub_filename_edit.text(),
"de_forced_sub_filename": self.de_forced_sub_filename_edit.text(),
"cleanup_temp": self.cleanup_temp_cb.isChecked(),
"custom_output_template": self.custom_output_template_cb.isChecked(),
"output_template": self.output_template_edit.text()
}
def browse_custom_path(self):
dialog = QFileDialog(self)
dialog.setFileMode(QFileDialog.Directory)
dialog.setWindowTitle("Eigenen Zielordner auswählen")
if self.custom_path_edit.text():
dialog.setDirectory(self.custom_path_edit.text())
# Icon setzen
set_window_icon(dialog)
if dialog.exec_():
directory = dialog.selectedFiles()[0]
self.custom_path_edit.setText(directory)
class OptionenDialog(QDialog):
def __init__(self, output_dir, use_local_ytdlp, parent=None, ytdlp_flags=None):
super().__init__(parent)
self.setWindowTitle("Optionen")
self.resize(420, 300)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
# Icon für den Dialog setzen
set_window_icon(self)
self.selected_output_dir = output_dir
self.selected_use_local_ytdlp = use_local_ytdlp
self.selected_flags = ytdlp_flags or {
"ignore_config": False,
"remux_mkv": False,
"embed_metadata": False,
"use_ffmpeg_location": False
}
self.setup_ui()
def setup_ui(self):
main_layout = QVBoxLayout()
tabs = QTabWidget()
# Tab 1: Allgemein
tab_allgemein = QWidget()
layout = QFormLayout()
self.output_dir_input = QLineEdit(self.selected_output_dir)
browse_btn = QPushButton("Durchsuchen...")
browse_btn.clicked.connect(self.browse_output_dir)
hbox = QHBoxLayout()
hbox.addWidget(self.output_dir_input)
hbox.addWidget(browse_btn)
layout.addRow("Standardpfad:", hbox)
# MKVMerge-Pfad hinzufügen
self.mkvmerge_path_input = QLineEdit(self.parent().config.get("mkvmerge_path", "C:\\Program Files\\MKVToolNix\\mkvmerge.exe") if self.parent() else "C:\\Program Files\\MKVToolNix\\mkvmerge.exe")
mkvmerge_browse_btn = QPushButton("Durchsuchen...")
mkvmerge_browse_btn.clicked.connect(self.browse_mkvmerge_path)
mkvmerge_hbox = QHBoxLayout()
mkvmerge_hbox.addWidget(self.mkvmerge_path_input)
mkvmerge_hbox.addWidget(mkvmerge_browse_btn)
layout.addRow("MKVMerge-Pfad:", mkvmerge_hbox)
# FFmpeg-Pfad hinzufügen
self.ffmpeg_path_input = QLineEdit(self.parent().config.get("ffmpeg_path", "C:\\ffmpeg\\bin\\ffmpeg.exe") if self.parent() else "C:\\ffmpeg\\bin\\ffmpeg.exe")
ffmpeg_browse_btn = QPushButton("Durchsuchen...")
ffmpeg_browse_btn.clicked.connect(self.browse_ffmpeg_path)
ffmpeg_hbox = QHBoxLayout()
ffmpeg_hbox.addWidget(self.ffmpeg_path_input)
ffmpeg_hbox.addWidget(ffmpeg_browse_btn)
layout.addRow("FFmpeg-Pfad:", ffmpeg_hbox)
self.ytdlp_source_combo = QComboBox()
self.ytdlp_source_combo.addItems(["Lokal (bin/yt-dlp.exe)", "System (PATH)"])
self.ytdlp_source_combo.setCurrentIndex(0 if self.selected_use_local_ytdlp else 1)
layout.addRow("yt-dlp-Quelle:", self.ytdlp_source_combo)
# Default-Presets ausblenden
self.hide_defaults_cb = QCheckBox("Default-Presets ausblenden")
self.hide_defaults_cb.setChecked(self.parent().config.get("hide_default_presets", False) if self.parent() else False)
layout.addRow(self.hide_defaults_cb)
# ADN Tab aktivieren
self.enable_adn_tab_cb = QCheckBox("ADN Tab aktivieren")
self.enable_adn_tab_cb.setChecked(self.parent().config.get("enable_adn_tab", False) if self.parent() else False)
layout.addRow(self.enable_adn_tab_cb)
bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
ytdlp_path = os.path.join(bin_dir, "yt-dlp.exe")
# Button 1: Herunterladen
self.download_btn = QPushButton("yt-dlp.exe herunterladen")
self.download_btn.clicked.connect(self.download_ytdlp)
self.download_btn.setEnabled(not os.path.exists(ytdlp_path))
layout.addRow(self.download_btn)
# Button 2: Updaten
self.update_btn = QPushButton("yt-dlp.exe updaten")
self.update_btn.clicked.connect(self.update_ytdlp)
layout.addRow(self.update_btn)
tab_allgemein.setLayout(layout)
tabs.addTab(tab_allgemein, "Allgemein")
# Tab 2: yt-dlp-Flags
tab_flags = QWidget()
flags_layout = QVBoxLayout()
self.cb_ignore_config = QCheckBox("--ignore-config")
self.cb_ignore_config.setChecked(self.selected_flags.get("ignore_config", False))
flags_layout.addWidget(self.cb_ignore_config)
flags_layout.addWidget(QLabel("Ignoriert die systemweite yt-dlp-Konfiguration."))
self.cb_remux_mkv = QCheckBox("--remux-video mkv")
self.cb_remux_mkv.setChecked(self.selected_flags.get("remux_mkv", False))
flags_layout.addWidget(self.cb_remux_mkv)
flags_layout.addWidget(QLabel("Remuxt das Video ins MKV-Format."))
self.cb_embed_metadata = QCheckBox("--embed-metadata")
self.cb_embed_metadata.setChecked(self.selected_flags.get("embed_metadata", False))
flags_layout.addWidget(self.cb_embed_metadata)
flags_layout.addWidget(QLabel("Betten Metadaten in die Ausgabedatei ein."))
self.cb_use_ffmpeg_location = QCheckBox("--ffmpeg-location")
self.cb_use_ffmpeg_location.setChecked(self.selected_flags.get("use_ffmpeg_location", False))
flags_layout.addWidget(self.cb_use_ffmpeg_location)
flags_layout.addWidget(QLabel("Nutzt den konfigurierten FFmpeg-Pfad für yt-dlp."))
tab_flags.setLayout(flags_layout)
tabs.addTab(tab_flags, "yt-dlp-Flags")
# Tab 3: Info
tab_info = QWidget()
info_layout = QVBoxLayout()
info_text = (
"Version: 1.4
"
"© 2025 Akamaru
"
"Sourcecode: https://git.ponywave.de/Akamaru/video-download-helper
"
"Erstellt mit Hilfe von Claude, GPT & Gemini"
)
info_label = QLabel(info_text)
info_label.setOpenExternalLinks(True)
info_label.setTextFormat(Qt.RichText)
info_layout.addWidget(info_label)
info_layout.addStretch(1)
tab_info.setLayout(info_layout)
tabs.addTab(tab_info, "Info")
main_layout.addWidget(tabs)
# Stelle sicher, dass QDialogButtonBox nur einmal erstellt und verbunden wird
if hasattr(self, 'button_box'):
try:
main_layout.removeWidget(self.button_box)
self.button_box.deleteLater()
except Exception:
pass
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
main_layout.addWidget(self.button_box)
self.setLayout(main_layout)
def browse_output_dir(self):
dialog = QFileDialog(self)
dialog.setFileMode(QFileDialog.Directory)
dialog.setWindowTitle("Standardpfad auswählen")
dialog.setDirectory(self.output_dir_input.text() or os.path.expanduser("~"))
# Icon setzen
set_window_icon(dialog)
if dialog.exec_():
directory = dialog.selectedFiles()[0]
self.output_dir_input.setText(directory)
def browse_mkvmerge_path(self):
dialog = QFileDialog(self)
dialog.setFileMode(QFileDialog.ExistingFile)
dialog.setWindowTitle("MKVMerge-Executable auswählen")
dialog.setDirectory(self.mkvmerge_path_input.text() or "C:\\Program Files\\MKVToolNix")
dialog.setNameFilter("Executable (*.exe)")
# Icon setzen
set_window_icon(dialog)
if dialog.exec_():
file_path = dialog.selectedFiles()[0]
self.mkvmerge_path_input.setText(file_path)
def browse_ffmpeg_path(self):
dialog = QFileDialog(self)
dialog.setFileMode(QFileDialog.ExistingFile)
dialog.setWindowTitle("FFmpeg-Executable auswählen")
dialog.setDirectory(self.ffmpeg_path_input.text() or "C:\\ffmpeg\\bin")
dialog.setNameFilter("Executable (*.exe)")
# Icon setzen
set_window_icon(dialog)
if dialog.exec_():
file_path = dialog.selectedFiles()[0]
self.ffmpeg_path_input.setText(file_path)
def get_values(self):
return (
self.output_dir_input.text(),
self.ytdlp_source_combo.currentIndex() == 0,
{
"ignore_config": self.cb_ignore_config.isChecked(),
"remux_mkv": self.cb_remux_mkv.isChecked(),
"embed_metadata": self.cb_embed_metadata.isChecked(),
"use_ffmpeg_location": self.cb_use_ffmpeg_location.isChecked()
},
self.hide_defaults_cb.isChecked(),
self.mkvmerge_path_input.text(),
self.enable_adn_tab_cb.isChecked(),
self.ffmpeg_path_input.text()
)
def download_ytdlp(self):
self.download_btn.setEnabled(False)
self.download_btn.setText("Lade herunter...")
self.thread = YtDlpDownloadThread()
self.thread.finished_signal.connect(self.download_finished)
self.thread.start()
def download_finished(self, success, message):
bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
ytdlp_path = os.path.join(bin_dir, "yt-dlp.exe")
self.download_btn.setEnabled(not os.path.exists(ytdlp_path))
self.download_btn.setText("yt-dlp.exe herunterladen")
if success:
QMessageBox.information(self, "Erfolg", message)
else:
QMessageBox.critical(self, "Fehler", message)
def update_ytdlp(self):
self.update_btn.setEnabled(False)
self.update_btn.setText("Aktualisiere...")
# Bestimme, ob lokal oder systemweit
use_local = self.ytdlp_source_combo.currentIndex() == 0
if use_local:
bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
ytdlp_path = os.path.join(bin_dir, "yt-dlp.exe")
cmd = [ytdlp_path, "-U"]
else:
cmd = ["yt-dlp", "-U"]
try:
creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
result = subprocess.run(cmd, capture_output=True, text=True, creationflags=creationflags)
if result.returncode == 0:
QMessageBox.information(self, "Erfolg", f"yt-dlp wurde aktualisiert.\n\n{result.stdout}")
else:
QMessageBox.warning(self, "Fehler", f"Fehler beim Updaten von yt-dlp:\n{result.stderr or result.stdout}")
except Exception as e:
QMessageBox.critical(self, "Fehler", f"Fehler beim Ausführen von yt-dlp -U: {str(e)}")
self.update_btn.setEnabled(True)
self.update_btn.setText("yt-dlp.exe updaten")