#!/usr/bin/env python3 """ yt_download.py — Download YouTube video v 1080p (16:9) za reels pipeline. Primer: python3 yt_download.py "https://youtu.be/dQw4w9WgXcQ" /data/uploads/video.mp4 """ import argparse import os import subprocess import sys from pathlib import Path import json def download(url, output, max_height=1080, format_str=None, cookies_file=None): """ Download YT video. Privzeto: best mp4 ≤1080p z audiotrackom. """ if format_str is None: format_str = ( f"bestvideo[height<={max_height}][ext=mp4]+bestaudio[ext=m4a]/" f"best[height<={max_height}][ext=mp4]/best" ) cmd = [ "yt-dlp", "-f", format_str, "--merge-output-format", "mp4", "--no-playlist", "--write-info-json", "--restrict-filenames", "-o", str(output), ] # Auto-detect cookies file če ni eksplicitno podan if cookies_file is None: for candidate in [ "/data/cookies/youtube.txt", os.environ.get("YT_COOKIES_FILE", ""), ]: if candidate and Path(candidate).exists(): cookies_file = candidate break if cookies_file and Path(cookies_file).exists(): cmd += ["--cookies", str(cookies_file)] print(f"🍪 Using cookies: {cookies_file}", file=sys.stderr) cmd.append(url) print(f"⬇ Downloading {url}...", file=sys.stderr) result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: print(f"❌ yt-dlp napaka:\n{result.stderr[-1500:]}", file=sys.stderr) sys.exit(1) print(f"✅ {output}", file=sys.stderr) return output def get_info(url, cookies_file=None): """Vrni metadata brez prenosa.""" cmd = ["yt-dlp", "--dump-json", "--no-playlist"] if cookies_file is None: for candidate in ["/data/cookies/youtube.txt", os.environ.get("YT_COOKIES_FILE", "")]: if candidate and Path(candidate).exists(): cookies_file = candidate break if cookies_file and Path(cookies_file).exists(): cmd += ["--cookies", str(cookies_file)] cmd.append(url) result = subprocess.run(cmd, capture_output=True, text=True) if result.returncode != 0: return None return json.loads(result.stdout.strip().split("\n")[0]) def get_playlist(url, cookies_file=None): """Vrni listo videov v playlistu (samo metadata, ne pobere). Returns: { "is_playlist": bool, "playlist_title": str, "items": [ {"id": "VIDEO_ID", "title": "...", "url": "https://...", "duration": 234}, ... ] } Če URL ni playlist, vrne is_playlist=False in samo en item. """ cmd = ["yt-dlp", "--flat-playlist", "--dump-json"] if cookies_file is None: for candidate in ["/data/cookies/youtube.txt", os.environ.get("YT_COOKIES_FILE", "")]: if candidate and Path(candidate).exists(): cookies_file = candidate break if cookies_file and Path(cookies_file).exists(): cmd += ["--cookies", str(cookies_file)] cmd.append(url) print(f"📋 Resolving playlist: {url}", file=sys.stderr) result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) if result.returncode != 0: print(f"❌ yt-dlp playlist napaka:\n{result.stderr[-1500:]}", file=sys.stderr) return {"is_playlist": False, "playlist_title": "", "items": [], "error": result.stderr[-500:]} items = [] playlist_title = "" for line in result.stdout.strip().split("\n"): if not line.strip(): continue try: entry = json.loads(line) except json.JSONDecodeError: continue # Playlist header (typ=playlist) if entry.get("_type") == "playlist": playlist_title = entry.get("title", "") continue # Video entry vid = entry.get("id") if not vid: continue items.append({ "id": vid, "title": entry.get("title", "") or "", "url": entry.get("url") or f"https://www.youtube.com/watch?v={vid}", "duration": entry.get("duration"), "uploader": entry.get("uploader") or entry.get("channel") or "", }) is_playlist = len(items) > 1 or ("list=" in url) return { "is_playlist": is_playlist, "playlist_title": playlist_title or (items[0]["title"] if items else ""), "items": items, } def main(): ap = argparse.ArgumentParser() ap.add_argument("url") ap.add_argument("output") ap.add_argument("--max-height", type=int, default=1080) ap.add_argument("--cookies", default=None, help="Pot do cookies.txt (Netscape format)") ap.add_argument("--info-only", action="store_true", help="Samo metadata, brez prenosa") args = ap.parse_args() if args.info_only: info = get_info(args.url, cookies_file=args.cookies) if info: print(json.dumps({ "title": info.get("title"), "duration": info.get("duration"), "uploader": info.get("uploader"), "thumbnail": info.get("thumbnail"), }, indent=2)) else: print("❌ Ne morem dobiti info", file=sys.stderr) sys.exit(1) return download(args.url, args.output, max_height=args.max_height, cookies_file=args.cookies) if __name__ == "__main__": main()