Implementiere eine Download-Queue mit Funktionen zum Hinzufügen, Starten, Leeren und Verwalten von Queue-Elementen. Speichere und lade die Queue aus einer Datei.
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -5,3 +5,4 @@ bin/yt-dlp.exe
 | 
			
		||||
config.json
 | 
			
		||||
main.spec
 | 
			
		||||
*.7z
 | 
			
		||||
queue.json
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										431
									
								
								main.py
									
									
									
									
									
								
							
							
						
						
									
										431
									
								
								main.py
									
									
									
									
									
								
							@@ -13,10 +13,12 @@ import json
 | 
			
		||||
import subprocess
 | 
			
		||||
import re
 | 
			
		||||
import urllib.request
 | 
			
		||||
import uuid
 | 
			
		||||
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
 | 
			
		||||
                            QLabel, QLineEdit, QPushButton, QComboBox, QTextEdit, 
 | 
			
		||||
                            QFileDialog, QMessageBox, QListWidget, QDialog, QFormLayout,
 | 
			
		||||
                            QDialogButtonBox, QInputDialog, QGroupBox, QCheckBox, QTabWidget)
 | 
			
		||||
                            QDialogButtonBox, QInputDialog, QGroupBox, QCheckBox, QTabWidget,
 | 
			
		||||
                            QListWidgetItem, QMenu, QAction)
 | 
			
		||||
from PyQt5.QtCore import QThread, pyqtSignal, Qt
 | 
			
		||||
 | 
			
		||||
# Hilfsfunktionen für den Ressourcenpfad
 | 
			
		||||
@@ -517,6 +519,62 @@ class OptionenDialog(QDialog):
 | 
			
		||||
        self.update_btn.setText("yt-dlp.exe updaten")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QueueItem:
 | 
			
		||||
    """Repräsentiert einen Eintrag in der Download-Queue."""
 | 
			
		||||
    def __init__(self, url, preset_data, output_dir=None, output_filename=None, 
 | 
			
		||||
                 series_info=None, use_local_ytdlp=True, extra_args=None):
 | 
			
		||||
        self.id = str(uuid.uuid4())  # Eindeutige ID für diesen Queue-Eintrag
 | 
			
		||||
        self.url = url
 | 
			
		||||
        self.preset_data = preset_data.copy() if preset_data else {}
 | 
			
		||||
        self.output_dir = output_dir
 | 
			
		||||
        self.output_filename = output_filename
 | 
			
		||||
        self.series_info = series_info.copy() if series_info else {}
 | 
			
		||||
        self.use_local_ytdlp = use_local_ytdlp
 | 
			
		||||
        self.extra_args = extra_args or ""
 | 
			
		||||
        self.status = "Wartend"
 | 
			
		||||
        
 | 
			
		||||
    def get_display_name(self):
 | 
			
		||||
        """Gibt einen lesbaren Namen für die Queue-Anzeige zurück."""
 | 
			
		||||
        preset_name = self.preset_data.get("name", "Unbekannt")
 | 
			
		||||
        if self.series_info:
 | 
			
		||||
            series = self.series_info.get("series", "")
 | 
			
		||||
            season = self.series_info.get("season", "")
 | 
			
		||||
            episode = self.series_info.get("episode", "")
 | 
			
		||||
            if series and season and episode:
 | 
			
		||||
                return f"{self.url} - {series} S{season}E{episode} ({preset_name})"
 | 
			
		||||
        return f"{self.url} ({preset_name})"
 | 
			
		||||
        
 | 
			
		||||
    def to_dict(self):
 | 
			
		||||
        """Konvertiert das QueueItem in ein JSON-serialisierbares Dictionary."""
 | 
			
		||||
        return {
 | 
			
		||||
            "id": self.id,
 | 
			
		||||
            "url": self.url,
 | 
			
		||||
            "preset_data": self.preset_data,
 | 
			
		||||
            "output_dir": self.output_dir,
 | 
			
		||||
            "output_filename": self.output_filename,
 | 
			
		||||
            "series_info": self.series_info,
 | 
			
		||||
            "use_local_ytdlp": self.use_local_ytdlp,
 | 
			
		||||
            "extra_args": self.extra_args,
 | 
			
		||||
            "status": self.status
 | 
			
		||||
        }
 | 
			
		||||
    
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def from_dict(cls, data):
 | 
			
		||||
        """Erstellt ein QueueItem aus einem Dictionary."""
 | 
			
		||||
        item = cls(
 | 
			
		||||
            url=data["url"],
 | 
			
		||||
            preset_data=data["preset_data"],
 | 
			
		||||
            output_dir=data["output_dir"],
 | 
			
		||||
            output_filename=data["output_filename"],
 | 
			
		||||
            series_info=data["series_info"],
 | 
			
		||||
            use_local_ytdlp=data["use_local_ytdlp"],
 | 
			
		||||
            extra_args=data["extra_args"]
 | 
			
		||||
        )
 | 
			
		||||
        item.id = data["id"]
 | 
			
		||||
        item.status = data["status"]
 | 
			
		||||
        return item
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MainWindow(QMainWindow):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
@@ -534,9 +592,15 @@ class MainWindow(QMainWindow):
 | 
			
		||||
        self.presets = self.load_presets()
 | 
			
		||||
        
 | 
			
		||||
        self.download_thread = None
 | 
			
		||||
        self.download_queue = []  # Liste für die Download-Queue
 | 
			
		||||
        self.current_queue_item = None  # Aktuell laufender Download aus der Queue
 | 
			
		||||
        
 | 
			
		||||
        # UI initialisieren
 | 
			
		||||
        self.setup_ui()
 | 
			
		||||
        
 | 
			
		||||
        # Queue aus gespeicherter Datei laden (nach UI-Setup)
 | 
			
		||||
        self.load_queue()
 | 
			
		||||
        
 | 
			
		||||
    def ensure_directories(self):
 | 
			
		||||
        """Stellt sicher, dass alle benötigten Verzeichnisse existieren."""
 | 
			
		||||
        # Stelle sicher, dass der Presets-Ordner existiert
 | 
			
		||||
@@ -601,11 +665,11 @@ class MainWindow(QMainWindow):
 | 
			
		||||
        main_layout.addWidget(self.series_group)
 | 
			
		||||
        
 | 
			
		||||
        # Options-Button statt Felder für Standardpfad und yt-dlp-Quelle
 | 
			
		||||
        optionen_layout = QHBoxLayout()
 | 
			
		||||
        options_layout = QHBoxLayout()
 | 
			
		||||
        self.optionen_btn = QPushButton("Optionen...")
 | 
			
		||||
        self.optionen_btn.clicked.connect(self.open_optionen_dialog)
 | 
			
		||||
        optionen_layout.addWidget(self.optionen_btn)
 | 
			
		||||
        main_layout.addLayout(optionen_layout)
 | 
			
		||||
        options_layout.addWidget(self.optionen_btn)
 | 
			
		||||
        main_layout.addLayout(options_layout)
 | 
			
		||||
        
 | 
			
		||||
        # Command Preview
 | 
			
		||||
        main_layout.addWidget(QLabel("Befehlsvorschau:"))
 | 
			
		||||
@@ -614,21 +678,60 @@ class MainWindow(QMainWindow):
 | 
			
		||||
        self.cmd_preview.setMaximumHeight(60)
 | 
			
		||||
        main_layout.addWidget(self.cmd_preview)
 | 
			
		||||
        
 | 
			
		||||
        # Download Button
 | 
			
		||||
        # Download Buttons
 | 
			
		||||
        download_buttons_layout = QHBoxLayout()
 | 
			
		||||
        self.download_btn = QPushButton("Download starten")
 | 
			
		||||
        self.download_btn.clicked.connect(self.start_download)
 | 
			
		||||
        main_layout.addWidget(self.download_btn)
 | 
			
		||||
        download_buttons_layout.addWidget(self.download_btn)
 | 
			
		||||
        
 | 
			
		||||
        # Log Output
 | 
			
		||||
        main_layout.addWidget(QLabel("Ausgabe:"))
 | 
			
		||||
        # Neu: Queue-Button
 | 
			
		||||
        self.queue_btn = QPushButton("Zur Queue hinzufügen")
 | 
			
		||||
        self.queue_btn.clicked.connect(self.add_to_queue)
 | 
			
		||||
        download_buttons_layout.addWidget(self.queue_btn)
 | 
			
		||||
        
 | 
			
		||||
        main_layout.addLayout(download_buttons_layout)
 | 
			
		||||
        
 | 
			
		||||
        # Neu: Tabbed Layout für Ausgabe und Queue
 | 
			
		||||
        self.tabs = QTabWidget()
 | 
			
		||||
        
 | 
			
		||||
        # Log Output Tab
 | 
			
		||||
        log_tab = QWidget()
 | 
			
		||||
        log_layout = QVBoxLayout()
 | 
			
		||||
        log_layout.addWidget(QLabel("Ausgabe:"))
 | 
			
		||||
        self.log_output = QTextEdit()
 | 
			
		||||
        self.log_output.setReadOnly(True)
 | 
			
		||||
        main_layout.addWidget(self.log_output)
 | 
			
		||||
        log_layout.addWidget(self.log_output)
 | 
			
		||||
        log_tab.setLayout(log_layout)
 | 
			
		||||
        self.tabs.addTab(log_tab, "Ausgabe")
 | 
			
		||||
        
 | 
			
		||||
        # Queue Tab
 | 
			
		||||
        queue_tab = QWidget()
 | 
			
		||||
        queue_layout = QVBoxLayout()
 | 
			
		||||
        queue_layout.addWidget(QLabel("Download-Queue:"))
 | 
			
		||||
        
 | 
			
		||||
        self.queue_list = QListWidget()
 | 
			
		||||
        self.queue_list.setContextMenuPolicy(Qt.CustomContextMenu)
 | 
			
		||||
        self.queue_list.customContextMenuRequested.connect(self.show_queue_context_menu)
 | 
			
		||||
        queue_layout.addWidget(self.queue_list)
 | 
			
		||||
        
 | 
			
		||||
        queue_buttons = QHBoxLayout()
 | 
			
		||||
        self.start_queue_btn = QPushButton("Queue starten")
 | 
			
		||||
        self.start_queue_btn.clicked.connect(self.start_queue)
 | 
			
		||||
        queue_buttons.addWidget(self.start_queue_btn)
 | 
			
		||||
        
 | 
			
		||||
        self.clear_queue_btn = QPushButton("Queue leeren")
 | 
			
		||||
        self.clear_queue_btn.clicked.connect(self.clear_queue)
 | 
			
		||||
        queue_buttons.addWidget(self.clear_queue_btn)
 | 
			
		||||
        
 | 
			
		||||
        queue_layout.addLayout(queue_buttons)
 | 
			
		||||
        queue_tab.setLayout(queue_layout)
 | 
			
		||||
        self.tabs.addTab(queue_tab, "Queue")
 | 
			
		||||
        
 | 
			
		||||
        main_layout.addWidget(self.tabs)
 | 
			
		||||
        
 | 
			
		||||
        # Connect signals
 | 
			
		||||
        self.url_input.textChanged.connect(self.update_cmd_preview)
 | 
			
		||||
        self.preset_combo.currentIndexChanged.connect(self.preset_changed)
 | 
			
		||||
        # self.optionen_btn.clicked.connect(self.open_optionen_dialog)  # Entfernt, um doppeltes Öffnen zu verhindern
 | 
			
		||||
        
 | 
			
		||||
        # Serie, Staffel, Folge Signals
 | 
			
		||||
        self.series_input.textChanged.connect(self.update_cmd_preview)
 | 
			
		||||
@@ -642,6 +745,7 @@ class MainWindow(QMainWindow):
 | 
			
		||||
        # Initial update
 | 
			
		||||
        self.preset_changed()
 | 
			
		||||
        self.update_cmd_preview()
 | 
			
		||||
        self.update_queue_buttons()
 | 
			
		||||
        
 | 
			
		||||
    def load_config(self):
 | 
			
		||||
        if os.path.exists(CONFIG_FILE):
 | 
			
		||||
@@ -1115,10 +1219,317 @@ class MainWindow(QMainWindow):
 | 
			
		||||
            self.log_output.append(f"Fehler: {message}")
 | 
			
		||||
            QMessageBox.warning(self, "Fehler", message)
 | 
			
		||||
            
 | 
			
		||||
        # Queue-Buttons nach Download aktualisieren
 | 
			
		||||
        self.update_queue_buttons()
 | 
			
		||||
    
 | 
			
		||||
    def closeEvent(self, event):
 | 
			
		||||
        self.save_config()
 | 
			
		||||
        self.save_queue()  # Queue beim Beenden speichern
 | 
			
		||||
        event.accept()
 | 
			
		||||
 | 
			
		||||
    def load_queue(self):
 | 
			
		||||
        """Lädt die gespeicherte Download-Queue aus einer Datei."""
 | 
			
		||||
        queue_file = os.path.join(get_user_data_dir(), "queue.json")
 | 
			
		||||
        if os.path.exists(queue_file):
 | 
			
		||||
            try:
 | 
			
		||||
                with open(queue_file, 'r', encoding='utf-8') as f:
 | 
			
		||||
                    queue_data = json.load(f)
 | 
			
		||||
                    self.download_queue = [QueueItem.from_dict(item) for item in queue_data]
 | 
			
		||||
                    # Sicherer Log-Aufruf
 | 
			
		||||
                    if hasattr(self, 'log_output'):
 | 
			
		||||
                        self.log_output.append(f"Download-Queue mit {len(self.download_queue)} Elementen geladen.")
 | 
			
		||||
                    # Queue-Liste aktualisieren
 | 
			
		||||
                    if hasattr(self, 'queue_list'):
 | 
			
		||||
                        self.update_queue_list()
 | 
			
		||||
            except Exception as e:
 | 
			
		||||
                if hasattr(self, 'log_output'):
 | 
			
		||||
                    self.log_output.append(f"Fehler beim Laden der Download-Queue: {str(e)}")
 | 
			
		||||
                print(f"Fehler beim Laden der Download-Queue: {str(e)}")
 | 
			
		||||
                self.download_queue = []
 | 
			
		||||
                
 | 
			
		||||
        # Aktualisiere Queue-Buttons nach dem Laden
 | 
			
		||||
        if hasattr(self, 'start_queue_btn') and hasattr(self, 'clear_queue_btn'):
 | 
			
		||||
            self.update_queue_buttons()
 | 
			
		||||
    
 | 
			
		||||
    def save_queue(self):
 | 
			
		||||
        """Speichert die Download-Queue in eine Datei."""
 | 
			
		||||
        queue_file = os.path.join(get_user_data_dir(), "queue.json")
 | 
			
		||||
        try:
 | 
			
		||||
            queue_data = [item.to_dict() for item in self.download_queue]
 | 
			
		||||
            with open(queue_file, 'w', encoding='utf-8') as f:
 | 
			
		||||
                json.dump(queue_data, f, indent=4, ensure_ascii=False)
 | 
			
		||||
        except Exception as e:
 | 
			
		||||
            if hasattr(self, 'log_output'):
 | 
			
		||||
                self.log_output.append(f"Fehler beim Speichern der Download-Queue: {str(e)}")
 | 
			
		||||
            print(f"Fehler beim Speichern der Download-Queue: {str(e)}")
 | 
			
		||||
    
 | 
			
		||||
    def add_to_queue(self):
 | 
			
		||||
        """Fügt den aktuellen Download zur Queue hinzu."""
 | 
			
		||||
        url = self.url_input.text()
 | 
			
		||||
        if not url:
 | 
			
		||||
            QMessageBox.warning(self, "Fehler", "Bitte geben Sie eine URL ein.")
 | 
			
		||||
            return
 | 
			
		||||
        preset = self.get_current_preset()
 | 
			
		||||
        if not preset:
 | 
			
		||||
            QMessageBox.warning(self, "Fehler", "Bitte wählen Sie ein Preset aus.")
 | 
			
		||||
            return
 | 
			
		||||
        
 | 
			
		||||
        # Wenn im Preset ein eigener Pfad definiert ist, diesen bevorzugen
 | 
			
		||||
        custom_path = self.custom_path_input.text() or preset.get("custom_path", "")
 | 
			
		||||
        # Wenn custom_path gesetzt ist, verwenden wir diesen anstelle des standard output_dir
 | 
			
		||||
        output_dir = custom_path if custom_path else self.config["output_dir"]
 | 
			
		||||
        
 | 
			
		||||
        series_info = None
 | 
			
		||||
        output_filename = None
 | 
			
		||||
        
 | 
			
		||||
        # Wenn es ein Serien-Preset ist, die Serien-Infos separat speichern
 | 
			
		||||
        if preset.get("has_series_template", False):
 | 
			
		||||
            series_info = {
 | 
			
		||||
                "series": self.series_input.text() or preset.get("series", ""),
 | 
			
		||||
                "season": self.season_input.text() or preset.get("season", "1"),
 | 
			
		||||
                "episode": self.episode_input.text() or preset.get("episode", "1"),
 | 
			
		||||
                "template": preset.get("series_template", SERIES_TEMPLATE)
 | 
			
		||||
            }
 | 
			
		||||
            output_filename = self.get_output_filename(preset)
 | 
			
		||||
        
 | 
			
		||||
        # Flags und Extra-Argumente vorbereiten
 | 
			
		||||
        flags = self.config.get("ytdlp_flags", {})
 | 
			
		||||
        is_audio = preset.get("is_audio", False)
 | 
			
		||||
        extra_args = []
 | 
			
		||||
        
 | 
			
		||||
        if preset.get("username"):
 | 
			
		||||
            extra_args.extend(["-u", preset["username"]])
 | 
			
		||||
        if preset.get("password"):
 | 
			
		||||
            extra_args.extend(["-p", preset["password"]])
 | 
			
		||||
        if preset.get("referer"):
 | 
			
		||||
            extra_args.append(f"--referer={preset['referer']}")
 | 
			
		||||
        if preset.get("hls_ffmpeg"):
 | 
			
		||||
            extra_args.extend(["--downloader", "ffmpeg", "--hls-use-mpegts"])
 | 
			
		||||
        if preset.get("sublang"):
 | 
			
		||||
            extra_args.extend(["--sub-lang", preset["sublang"]])
 | 
			
		||||
        if preset.get("embed_subs"):
 | 
			
		||||
            extra_args.append("--embed-subs")
 | 
			
		||||
        if preset.get("subformat"):
 | 
			
		||||
            extra_args.extend(["--convert-subs", preset["subformat"]])
 | 
			
		||||
        if flags.get("ignore_config"):
 | 
			
		||||
            extra_args.append("--ignore-config")
 | 
			
		||||
        if flags.get("remux_mkv") and not is_audio:
 | 
			
		||||
            extra_args.extend(["--remux-video", "mkv"])
 | 
			
		||||
        if flags.get("embed_metadata"):
 | 
			
		||||
            extra_args.append("--embed-metadata")
 | 
			
		||||
        
 | 
			
		||||
        full_args = (" ".join(extra_args) + " " + preset["args"]).strip() if extra_args else preset["args"]
 | 
			
		||||
        
 | 
			
		||||
        # Erstelle ein Queue-Element
 | 
			
		||||
        queue_item = QueueItem(
 | 
			
		||||
            url=url,
 | 
			
		||||
            preset_data=preset,
 | 
			
		||||
            output_dir=output_dir,
 | 
			
		||||
            output_filename=output_filename,
 | 
			
		||||
            series_info=series_info,
 | 
			
		||||
            use_local_ytdlp=self.config["use_local_ytdlp"],
 | 
			
		||||
            extra_args=full_args
 | 
			
		||||
        )
 | 
			
		||||
        
 | 
			
		||||
        # Füge das Element zur Queue hinzu
 | 
			
		||||
        self.download_queue.append(queue_item)
 | 
			
		||||
        
 | 
			
		||||
        # Aktualisiere die Queue-Liste
 | 
			
		||||
        self.update_queue_list()
 | 
			
		||||
        self.tabs.setCurrentIndex(1)  # Wechsle zum Queue-Tab
 | 
			
		||||
        
 | 
			
		||||
        # Optional: Leere die URL-Box
 | 
			
		||||
        self.url_input.clear()
 | 
			
		||||
        
 | 
			
		||||
        # Aktualisiere Queue-Buttons
 | 
			
		||||
        self.update_queue_buttons()
 | 
			
		||||
        
 | 
			
		||||
        # Queue speichern
 | 
			
		||||
        self.save_queue()
 | 
			
		||||
        
 | 
			
		||||
        QMessageBox.information(self, "Hinzugefügt", "Download wurde zur Queue hinzugefügt.")
 | 
			
		||||
    
 | 
			
		||||
    def update_queue_list(self):
 | 
			
		||||
        """Aktualisiert die Anzeige der Queue-Liste."""
 | 
			
		||||
        self.queue_list.clear()
 | 
			
		||||
        for item in self.download_queue:
 | 
			
		||||
            list_item = QListWidgetItem(f"{item.status}: {item.get_display_name()}")
 | 
			
		||||
            list_item.setData(Qt.UserRole, item.id)  # Speichere die ID als Daten
 | 
			
		||||
            self.queue_list.addItem(list_item)
 | 
			
		||||
    
 | 
			
		||||
    def update_queue_buttons(self):
 | 
			
		||||
        """Aktualisiert den Status der Queue-Buttons basierend auf dem Zustand der Queue."""
 | 
			
		||||
        has_items = len(self.download_queue) > 0
 | 
			
		||||
        is_downloading = self.download_thread and self.download_thread.isRunning()
 | 
			
		||||
        
 | 
			
		||||
        self.start_queue_btn.setEnabled(has_items and not is_downloading)
 | 
			
		||||
        self.clear_queue_btn.setEnabled(has_items and not is_downloading)
 | 
			
		||||
    
 | 
			
		||||
    def show_queue_context_menu(self, position):
 | 
			
		||||
        """Zeigt das Kontextmenü für die Queue-Liste an."""
 | 
			
		||||
        if not self.queue_list.count():
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        menu = QMenu()
 | 
			
		||||
        
 | 
			
		||||
        # Aktionen erstellen
 | 
			
		||||
        remove_action = QAction("Entfernen", self)
 | 
			
		||||
        remove_action.triggered.connect(self.remove_selected_queue_item)
 | 
			
		||||
        
 | 
			
		||||
        move_up_action = QAction("Nach oben", self)
 | 
			
		||||
        move_up_action.triggered.connect(lambda: self.move_queue_item(-1))
 | 
			
		||||
        
 | 
			
		||||
        move_down_action = QAction("Nach unten", self)
 | 
			
		||||
        move_down_action.triggered.connect(lambda: self.move_queue_item(1))
 | 
			
		||||
        
 | 
			
		||||
        # Prüfe ob ein Element ausgewählt ist
 | 
			
		||||
        if self.queue_list.currentItem():
 | 
			
		||||
            menu.addAction(remove_action)
 | 
			
		||||
            menu.addAction(move_up_action)
 | 
			
		||||
            menu.addAction(move_down_action)
 | 
			
		||||
            
 | 
			
		||||
            # Zeige Menü
 | 
			
		||||
            menu.exec_(self.queue_list.mapToGlobal(position))
 | 
			
		||||
    
 | 
			
		||||
    def remove_selected_queue_item(self):
 | 
			
		||||
        """Entfernt das ausgewählte Element aus der Queue."""
 | 
			
		||||
        current_item = self.queue_list.currentItem()
 | 
			
		||||
        if not current_item:
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        item_id = current_item.data(Qt.UserRole)
 | 
			
		||||
        self.download_queue = [item for item in self.download_queue if item.id != item_id]
 | 
			
		||||
        self.update_queue_list()
 | 
			
		||||
        self.update_queue_buttons()
 | 
			
		||||
        
 | 
			
		||||
        # Queue speichern
 | 
			
		||||
        self.save_queue()
 | 
			
		||||
    
 | 
			
		||||
    def move_queue_item(self, direction):
 | 
			
		||||
        """Verschiebt ein Queue-Element nach oben oder unten."""
 | 
			
		||||
        current_row = self.queue_list.currentRow()
 | 
			
		||||
        if current_row < 0:
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        new_row = current_row + direction
 | 
			
		||||
        if new_row < 0 or new_row >= self.queue_list.count():
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        # Tausche Elemente in der Queue
 | 
			
		||||
        self.download_queue[current_row], self.download_queue[new_row] = \
 | 
			
		||||
            self.download_queue[new_row], self.download_queue[current_row]
 | 
			
		||||
        
 | 
			
		||||
        # Aktualisiere UI
 | 
			
		||||
        self.update_queue_list()
 | 
			
		||||
        self.queue_list.setCurrentRow(new_row)
 | 
			
		||||
        
 | 
			
		||||
        # Queue speichern
 | 
			
		||||
        self.save_queue()
 | 
			
		||||
    
 | 
			
		||||
    def start_queue(self):
 | 
			
		||||
        """Startet die Download-Queue."""
 | 
			
		||||
        if not self.download_queue:
 | 
			
		||||
            QMessageBox.information(self, "Queue leer", "Die Download-Queue ist leer.")
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        if self.download_thread and self.download_thread.isRunning():
 | 
			
		||||
            QMessageBox.warning(self, "Download läuft", "Es läuft bereits ein Download.")
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        # Starte den ersten Download in der Queue
 | 
			
		||||
        self.process_next_queue_item()
 | 
			
		||||
    
 | 
			
		||||
    def process_next_queue_item(self):
 | 
			
		||||
        """Verarbeitet das nächste Element in der Queue."""
 | 
			
		||||
        if not self.download_queue:
 | 
			
		||||
            self.log_output.append("Download-Queue abgeschlossen.")
 | 
			
		||||
            self.current_queue_item = None
 | 
			
		||||
            self.update_queue_buttons()
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        # Nehme das erste Element aus der Queue
 | 
			
		||||
        self.current_queue_item = self.download_queue[0]
 | 
			
		||||
        self.current_queue_item.status = "Wird heruntergeladen"
 | 
			
		||||
        self.update_queue_list()
 | 
			
		||||
        
 | 
			
		||||
        # Starte den Download
 | 
			
		||||
        self.tabs.setCurrentIndex(0)  # Wechsle zum Ausgabe-Tab
 | 
			
		||||
        self.log_output.clear()
 | 
			
		||||
        self.log_output.append(f"Starte Download von: {self.current_queue_item.url}")
 | 
			
		||||
        self.log_output.append(f"Preset: {self.current_queue_item.preset_data.get('name', 'Unbekannt')}")
 | 
			
		||||
        self.log_output.append(f"Ausgabeverzeichnis: {self.current_queue_item.output_dir}")
 | 
			
		||||
        
 | 
			
		||||
        # Download-Thread erstellen und starten
 | 
			
		||||
        self.download_thread = DownloadThread(
 | 
			
		||||
            url=self.current_queue_item.url,
 | 
			
		||||
            output_dir=self.current_queue_item.output_dir,
 | 
			
		||||
            cmd_args=self.current_queue_item.extra_args,
 | 
			
		||||
            use_local_ytdlp=self.current_queue_item.use_local_ytdlp,
 | 
			
		||||
            output_filename=self.current_queue_item.output_filename
 | 
			
		||||
        )
 | 
			
		||||
        
 | 
			
		||||
        self.download_thread.update_signal.connect(self.update_log)
 | 
			
		||||
        self.download_thread.finished_signal.connect(self.queue_download_finished)
 | 
			
		||||
        
 | 
			
		||||
        # Ändere den Button-Text und deaktiviere UI-Elemente während des Downloads
 | 
			
		||||
        self.download_btn.setText("Download abbrechen")
 | 
			
		||||
        self.disable_ui_during_download(True)
 | 
			
		||||
        
 | 
			
		||||
        self.download_thread.start()
 | 
			
		||||
    
 | 
			
		||||
    def queue_download_finished(self, success, message):
 | 
			
		||||
        """Callback wenn ein Download aus der Queue fertig ist."""
 | 
			
		||||
        # UI-Elemente wieder aktivieren
 | 
			
		||||
        self.disable_ui_during_download(False)
 | 
			
		||||
        # Button-Text zurücksetzen
 | 
			
		||||
        self.download_btn.setText("Download starten")
 | 
			
		||||
        
 | 
			
		||||
        # Bearbeite das aktuelle Queue-Element
 | 
			
		||||
        if self.current_queue_item:
 | 
			
		||||
            self.current_queue_item.status = "Fertig" if success else "Fehler"
 | 
			
		||||
            
 | 
			
		||||
            # Entferne das Element aus der Queue (es bleibt in der Liste, aber mit Status)
 | 
			
		||||
            if self.download_queue and self.download_queue[0].id == self.current_queue_item.id:
 | 
			
		||||
                self.download_queue.pop(0)
 | 
			
		||||
            
 | 
			
		||||
            self.update_queue_list()
 | 
			
		||||
            
 | 
			
		||||
            # Queue speichern
 | 
			
		||||
            self.save_queue()
 | 
			
		||||
        
 | 
			
		||||
        if success:
 | 
			
		||||
            self.log_output.append(message)
 | 
			
		||||
        else:
 | 
			
		||||
            self.log_output.append(f"Fehler: {message}")
 | 
			
		||||
        
 | 
			
		||||
        # Wenn die Queue nicht manuell abgebrochen wurde, verarbeite das nächste Element
 | 
			
		||||
        if not message.startswith("Download wurde abgebrochen"):
 | 
			
		||||
            self.process_next_queue_item()
 | 
			
		||||
        
 | 
			
		||||
        # Aktualisiere Queue-Buttons
 | 
			
		||||
        self.update_queue_buttons()
 | 
			
		||||
    
 | 
			
		||||
    def clear_queue(self):
 | 
			
		||||
        """Leert die Download-Queue."""
 | 
			
		||||
        if not self.download_queue:
 | 
			
		||||
            return
 | 
			
		||||
            
 | 
			
		||||
        reply = QMessageBox.question(
 | 
			
		||||
            self, 
 | 
			
		||||
            "Queue leeren",
 | 
			
		||||
            "Möchten Sie wirklich die gesamte Download-Queue leeren?",
 | 
			
		||||
            QMessageBox.Yes | QMessageBox.No, 
 | 
			
		||||
            QMessageBox.No
 | 
			
		||||
        )
 | 
			
		||||
        
 | 
			
		||||
        if reply == QMessageBox.Yes:
 | 
			
		||||
            self.download_queue.clear()
 | 
			
		||||
            self.update_queue_list()
 | 
			
		||||
            self.update_queue_buttons()
 | 
			
		||||
            
 | 
			
		||||
            # Queue speichern (leere Liste)
 | 
			
		||||
            self.save_queue()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == "__main__":
 | 
			
		||||
    app = QApplication(sys.argv)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user