v2
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user