#!/usr/bin/env python3 """ Installer for YouTube Downloader dependencies. Installs: yt-dlp, ffmpeg Supports: Windows, macOS, Linux (Debian/Ubuntu, Fedora/RHEL, Arch) """ import os import sys import shutil import subprocess import platform # ── Helpers ──────────────────────────────────────────────────────────────────── def run(cmd: list[str], check=True) -> subprocess.CompletedProcess: print(f" → {' '.join(cmd)}") return subprocess.run(cmd, check=check) def ok(msg: str): print(f" ✅ {msg}") def info(msg: str): print(f" ℹ️ {msg}") def warn(msg: str): print(f" ⚠️ {msg}") def fail(msg: str): print(f" ❌ {msg}") sys.exit(1) def section(title: str): print(f"\n{'─' * 50}") print(f" {title}") print(f"{'─' * 50}") # ── Platform detection ───────────────────────────────────────────────────────── OS = platform.system() # 'Windows', 'Darwin', 'Linux' IS_WIN = OS == "Windows" IS_MAC = OS == "Darwin" IS_LINUX = OS == "Linux" def linux_distro() -> str: """Return 'debian', 'fedora', 'arch', or 'unknown'.""" if shutil.which("apt-get"): return "debian" if shutil.which("dnf") or shutil.which("yum"): return "fedora" if shutil.which("pacman"): return "arch" return "unknown" # ── Python / pip check ───────────────────────────────────────────────────────── def check_python(): section("Checking Python") major, minor = sys.version_info[:2] print(f" Python {major}.{minor} detected") if major < 3 or (major == 3 and minor < 8): fail("Python 3.8+ is required. Please upgrade and re-run this script.") ok("Python version is compatible") def ensure_pip(): section("Checking pip") try: import pip # noqa: F401 ok("pip is available") except ImportError: info("pip not found — installing via ensurepip...") run([sys.executable, "-m", "ensurepip", "--upgrade"]) ok("pip installed") # Always upgrade pip to avoid resolver issues run([sys.executable, "-m", "pip", "install", "--upgrade", "pip"]) ok("pip is up to date") # ── yt-dlp ───────────────────────────────────────────────────────────────────── def install_ytdlp(): section("Installing yt-dlp") run([sys.executable, "-m", "pip", "install", "--upgrade", "yt-dlp"]) ok("yt-dlp installed/updated") # ── ffmpeg ───────────────────────────────────────────────────────────────────── def ffmpeg_already_installed() -> bool: if shutil.which("ffmpeg"): result = subprocess.run( ["ffmpeg", "-version"], capture_output=True, text=True, check=False ) version_line = result.stdout.splitlines()[0] if result.stdout else "unknown" info(f"ffmpeg already installed: {version_line}") return True return False def install_ffmpeg_windows(): """ On Windows, download the pre-built ffmpeg binary via winget or chocolatey. Falls back to manual instructions if neither is available. """ if shutil.which("winget"): info("Using winget to install ffmpeg...") run(["winget", "install", "--id", "Gyan.FFmpeg", "-e", "--silent"]) elif shutil.which("choco"): info("Using Chocolatey to install ffmpeg...") run(["choco", "install", "ffmpeg", "-y"]) elif shutil.which("scoop"): info("Using Scoop to install ffmpeg...") run(["scoop", "install", "ffmpeg"]) else: warn("No package manager found (winget / choco / scoop).") print(""" Please install ffmpeg manually: 1. Go to https://www.gyan.dev/ffmpeg/builds/ 2. Download the latest 'release essentials' zip 3. Extract it and add the 'bin' folder to your PATH """) return ok("ffmpeg installed") def install_ffmpeg_mac(): if shutil.which("brew"): info("Using Homebrew to install ffmpeg...") run(["brew", "install", "ffmpeg"]) elif shutil.which("port"): info("Using MacPorts to install ffmpeg...") run(["sudo", "port", "install", "ffmpeg"]) else: warn("Homebrew not found. Installing Homebrew first...") install_cmd = ( '/bin/bash -c "$(curl -fsSL ' 'https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' ) subprocess.run(install_cmd, shell=True, check=True) run(["brew", "install", "ffmpeg"]) ok("ffmpeg installed") def install_ffmpeg_linux(): distro = linux_distro() if distro == "debian": info("Using apt-get (Debian/Ubuntu)...") run(["sudo", "apt-get", "update", "-qq"]) run(["sudo", "apt-get", "install", "-y", "ffmpeg"]) elif distro == "fedora": info("Using dnf (Fedora/RHEL)...") # ffmpeg lives in RPM Fusion on Fedora run(["sudo", "dnf", "install", "-y", "https://download1.rpmfusion.org/free/fedora/" "rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm"], check=False) run(["sudo", "dnf", "install", "-y", "ffmpeg"]) elif distro == "arch": info("Using pacman (Arch Linux)...") run(["sudo", "pacman", "-Sy", "--noconfirm", "ffmpeg"]) else: warn("Unrecognised Linux distro — cannot auto-install ffmpeg.") print(""" Please install ffmpeg with your distro's package manager, e.g.: sudo apt-get install ffmpeg # Debian / Ubuntu sudo dnf install ffmpeg # Fedora sudo pacman -S ffmpeg # Arch """) return ok("ffmpeg installed") def install_ffmpeg(): section("Installing ffmpeg") if ffmpeg_already_installed(): ok("Skipping — ffmpeg is already installed") return if IS_WIN: install_ffmpeg_windows() elif IS_MAC: install_ffmpeg_mac() elif IS_LINUX: install_ffmpeg_linux() else: warn(f"Unsupported OS: {OS}") # ── Final verification ───────────────────────────────────────────────────────── def verify(): section("Verification") all_good = True # yt-dlp try: import yt_dlp ok(f"yt-dlp {yt_dlp.version.__version__}") except ImportError: fail("yt-dlp import failed after installation!") all_good = False # ffmpeg if shutil.which("ffmpeg"): result = subprocess.run( ["ffmpeg", "-version"], capture_output=True, text=True, check=False ) version_line = result.stdout.splitlines()[0] if result.stdout else "unknown version" ok(f"ffmpeg — {version_line}") else: warn("ffmpeg not found in PATH. High-quality merging may not work.") warn("You can still download videos but 1080p/4K may be unavailable.") all_good = False return all_good # ── Main ─────────────────────────────────────────────────────────────────────── def main(): print("\n" + "=" * 50) print(" YouTube Downloader — Dependency Installer") print("=" * 50) print(f" OS : {OS} ({platform.machine()})") print(f" Python : {sys.version.split()[0]}") check_python() ensure_pip() install_ytdlp() install_ffmpeg() all_good = verify() print("\n" + "=" * 50) if all_good: print(" 🎉 All dependencies installed successfully!") print(" Run python yt_downloader.py to start downloading.") else: print(" ⚠️ Setup finished with warnings (see above).") print("=" * 50 + "\n") if __name__ == "__main__": main()