This tool provides a graphical interface for batch downloading videos or audio using yt-dlp. It supports playlists, format selection, cookie authentication, and live progress display.
best, mp4, bestaudio, mp3)yt-dlp in a text boxyt-dlp installed and available in system PATHtkintersubprocessthreadingosrecookies.txt file.'URL Entry': Input field for video/playlist links'Listbox': Displays queued URLs'Format Dropdown': Choose download format'Buttons':'Progress Bar': Shows download percentage'Text Output': Displays live yt-dlp outputyt-dlp output using regular expressions.–extract-audio for MP3.This script is provided as-is. Feel free to modify and redistribute under an open-source license of your choice.
import tkinter as tk from tkinter import ttk, filedialog, messagebox import subprocess import threading import os import re download_queue = [] current_process = None # ---------------- GUI ---------------- root = tk.Tk() root.title("Mikos Batch Downloader") cookies_file = tk.StringVar(master=root) # für den Cookies-Dateipfad output_dir = tk.StringVar(master=root) # Ausgabeverzeichnis def add_link(): url = url_entry.get() if url: download_queue.append(url) url_listbox.insert(tk.END, url) url_entry.delete(0, tk.END) def clear_links(): download_queue.clear() url_listbox.delete(0, tk.END) def choose_directory(): folder = filedialog.askdirectory() if folder: output_dir.set(folder) def choose_cookies(): file = filedialog.askopenfilename( title="Choose cookies.txt", filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")] ) if file: cookies_file.set(file) status_label.config(text=f"Cookies loaded: {os.path.basename(file)}") def cancel_download(): global current_process if current_process and current_process.poll() is None: confirm = messagebox.askyesno("Cancel Download", "Are you sure you want to cancel?") if confirm: current_process.terminate() cancel_button.config(state="disabled") status_label.config(text="Download cancelled.") progress_text.insert(tk.END, "\nDownload was manually cancelled.\n") progress_text.see(tk.END) def start_downloads(): format_choice = format_var.get() out_dir = output_dir.get() cookies_path = cookies_file.get() # ✅ Zugriff im Hauptthread if not download_queue: messagebox.showwarning("No Links", "Please add at least one URL.") return threading.Thread(target=run_downloads, args=(format_choice, out_dir, cookies_path), daemon=True).start() def run_downloads(format_choice, out_dir, cookies_path): global current_process idx = 0 cancel_button.config(state="normal") while idx < len(download_queue): url = download_queue[idx] status_label.config(text=f"Downloading {idx+1}/{len(download_queue)}…") cmd = ["yt-dlp"] if cookies_path: cmd += ["--cookies", cookies_path] if format_choice == "mp3": cmd += ["--extract-audio", "--audio-format", "mp3"] else: cmd += ["-f", format_choice] if out_dir: cmd += ["-o", os.path.join(out_dir, "%(title)s.%(ext)s")] cmd.append(url) try: current_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) except FileNotFoundError: messagebox.showerror("Error", "yt-dlp not found. Please ensure it is installed and in PATH.") cancel_button.config(state="disabled") return progress_text.delete("1.0", tk.END) for line in current_process.stdout: progress_text.insert(tk.END, line) progress_text.see(tk.END) match = re.search(r"(\d{1,3}(?:\.\d+)?)%", line) if match: percent = float(match.group(1)) progress_bar["value"] = percent current_process.wait() progress_bar["value"] = 0 # ✅ Reset nach Abschluss if current_process.returncode == 0: url_listbox.delete(idx) download_queue.pop(idx) else: idx += 1 current_process = None cancel_button.config(state="disabled") status_label.config(text="All downloads completed.") messagebox.showinfo("Done", "All videos have been processed.") # ---------------- GUI Layout ---------------- tk.Label(root, text="Video or Playlist URL:").pack() url_entry = tk.Entry(root, width=80) url_entry.pack() button_frame = tk.Frame(root) button_frame.pack(pady=5) tk.Button(button_frame, text="Add Link", command=add_link).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="Clear List", command=clear_links).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="Choose Folder", command=choose_directory).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="Choose Cookies", command=choose_cookies).pack(side=tk.LEFT, padx=5) url_listbox = tk.Listbox(root, width=80, height=5) url_listbox.pack(pady=5) tk.Label(root, text="Select Format:").pack() format_var = tk.StringVar(value="best") format_dropdown = ttk.Combobox(root, textvariable=format_var, values=["best", "mp4", "bestaudio", "mp3"], width=20) format_dropdown.pack() tk.Label(root, textvariable=output_dir).pack() action_frame = tk.Frame(root) action_frame.pack(pady=10) tk.Button(action_frame, text="Start Downloads", command=start_downloads).pack(side=tk.LEFT, padx=10) cancel_button = tk.Button(action_frame, text="Cancel Downloads", command=cancel_download, state="disabled") cancel_button.pack(side=tk.LEFT, padx=10) status_label = tk.Label(root, text="Ready") status_label.pack() progress_bar = ttk.Progressbar(root, length=400, mode="determinate") progress_bar.pack(pady=5) progress_text = tk.Text(root, height=10, width=80) progress_text.pack() root.mainloop()