import os import sys import shutil import subprocess import argparse import importlib.util import json import re def check_requirements(): """Überprüft, ob alle erforderlichen Pakete installiert sind.""" try: import PyQt5 import PyInstaller except ImportError as e: print(f"Fehler: {e}") print("Bitte führe 'pip install -r requirements.txt' aus.") return False return True def find_yt_dlp(): """Versucht, yt-dlp im PATH zu finden.""" try: result = subprocess.run( ["where", "yt-dlp"] if os.name == "nt" else ["which", "yt-dlp"], capture_output=True, text=True ) if result.returncode == 0: path = result.stdout.strip().split("\n")[0] return path return None except Exception: return None def download_yt_dlp(): """Lädt die aktuelle Version von yt-dlp herunter.""" bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin") if not os.path.exists(bin_dir): os.makedirs(bin_dir) print("Lade yt-dlp herunter...") ytdlp_url = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe" ytdlp_path = os.path.join(bin_dir, "yt-dlp.exe") try: import requests response = requests.get(ytdlp_url) with open(ytdlp_path, "wb") as f: f.write(response.content) print(f"yt-dlp wurde nach {ytdlp_path} heruntergeladen.") return True except Exception as e: print(f"Fehler beim Herunterladen von yt-dlp: {e}") print("Bitte lade yt-dlp manuell herunter und platziere es im 'bin' Ordner.") return False def copy_yt_dlp_from_path(): """Kopiert yt-dlp aus dem PATH in den bin-Ordner.""" ytdlp_path = find_yt_dlp() if not ytdlp_path: print("yt-dlp wurde nicht im PATH gefunden.") return False bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin") if not os.path.exists(bin_dir): os.makedirs(bin_dir) try: dest_path = os.path.join(bin_dir, "yt-dlp.exe" if os.name == "nt" else "yt-dlp") shutil.copy2(ytdlp_path, dest_path) print(f"yt-dlp wurde nach {dest_path} kopiert.") return True except Exception as e: print(f"Fehler beim Kopieren von yt-dlp: {e}") return False def build_exe(onedir=False, console=False): """Erstellt die ausführbare Datei mit PyInstaller.""" print("Erstelle EXE-Datei...") # Nur Default-Presets übernehmen main_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "main.py") with open(main_path, "r", encoding="utf-8") as f: main_code = f.read() # Default-Presets extrahieren (vereinfachte Suche) match = re.search(r'defaults\s*=\s*\[(.*?)\n\s*\]', main_code, re.DOTALL) if match: defaults_code = "[" + match.group(1) + "]" try: # eval mit eingeschränktem Namespace defaults = eval(defaults_code, {"__builtins__": None}, {}) except Exception as e: print(f"Fehler beim Parsen der Default-Presets: {e}") defaults = [] else: print("Konnte Default-Presets nicht finden!") defaults = [] # Presets-Ordner bereinigen und nur Default-Presets schreiben bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin") presets_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "presets") if os.path.exists(presets_dir): for f in os.listdir(presets_dir): if f.endswith('.json'): try: os.remove(os.path.join(presets_dir, f)) except Exception: pass else: os.makedirs(presets_dir) for preset in defaults: filename = f"{preset['name'].lower().replace(' ', '_')}.json" try: with open(os.path.join(presets_dir, filename), 'w', encoding='utf-8') as f: json.dump(preset, f, indent=4, ensure_ascii=False) except Exception as e: print(f"Fehler beim Schreiben von Default-Preset {preset['name']}: {e}") # Rest wie gehabt cmd = ["pyinstaller"] if not onedir: cmd.append("--onefile") if not console: cmd.append("--windowed") # Icon-Pfad festlegen und zur Befehlszeile hinzufügen icon_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "icon.ico") if os.path.exists(icon_path): cmd.extend(["--icon", icon_path]) print(f"Icon wird verwendet: {icon_path}") else: print("Warnung: icon.ico wurde nicht gefunden.") if os.path.exists(bin_dir) and os.listdir(bin_dir): cmd.extend(["--add-data", f"{bin_dir}{os.pathsep}bin"]) if os.path.exists(presets_dir): cmd.extend(["--add-data", f"{presets_dir}{os.pathsep}presets"]) cmd.append("main.py") print(f"Führe aus: {' '.join(cmd)}") try: try: subprocess.run(cmd, check=True) except FileNotFoundError: print("pyinstaller nicht im PATH gefunden, versuche 'python -m PyInstaller' ...") cmd[0:1] = [sys.executable, "-m", "PyInstaller"] subprocess.run(cmd, check=True) if onedir: print("Die ausführbare Datei wurde im 'dist/main' Ordner erstellt.") else: print("Die ausführbare Datei wurde als 'dist/main.exe' erstellt.") return True except subprocess.CalledProcessError as e: print(f"Fehler beim Erstellen der EXE-Datei: {e}") return False except Exception as e: print(f"Unerwarteter Fehler: {e}") return False def parse_arguments(): """Parst die Kommandozeilenargumente.""" parser = argparse.ArgumentParser(description="Build-Skript für YT-DLP GUI") parser.add_argument("--onedir", action="store_true", help="Erstellt einen Ordner statt einer einzelnen Datei") parser.add_argument("--console", action="store_true", help="Zeigt die Konsole an") parser.add_argument("--download-ytdlp", action="store_true", help="Lädt yt-dlp herunter") parser.add_argument("--copy-ytdlp", action="store_true", help="Kopiert yt-dlp aus dem PATH") return parser.parse_args() def main(): args = parse_arguments() if not check_requirements(): return 1 # Überprüfe, ob yt-dlp bereits im bin-Ordner existiert bin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin") ytdlp_exists = os.path.exists(os.path.join(bin_dir, "yt-dlp.exe" if os.name == "nt" else "yt-dlp")) if not ytdlp_exists: if args.download_ytdlp: if not download_yt_dlp(): return 1 elif args.copy_ytdlp: if not copy_yt_dlp_from_path(): print("yt-dlp konnte nicht kopiert werden. Versuche, es herunterzuladen...") if not download_yt_dlp(): return 1 else: # Frage den Benutzer print("yt-dlp wurde nicht im bin-Ordner gefunden.") choice = input("Möchten Sie (1) yt-dlp herunterladen, (2) aus dem PATH kopieren oder (3) ohne fortfahren? [1/2/3]: ") if choice == "1": if not download_yt_dlp(): return 1 elif choice == "2": if not copy_yt_dlp_from_path(): print("yt-dlp konnte nicht kopiert werden. Versuche, es herunterzuladen...") if not download_yt_dlp(): return 1 # Erstelle die ausführbare Datei if not build_exe(onedir=args.onedir, console=args.console): return 1 return 0 if __name__ == "__main__": sys.exit(main())