|
| 1 | +import subprocess as sp |
| 2 | +import time |
| 3 | +from pathlib import Path |
| 4 | + |
| 5 | +import yt_dlp |
| 6 | + |
| 7 | +from ytconverter.constants import URL_RE |
| 8 | +from ytconverter.utils import apply_style, get_download_path, sanitize |
| 9 | + |
| 10 | + |
| 11 | +def run(): |
| 12 | + from ytconverter.config import load_local_version |
| 13 | + |
| 14 | + print("\n" + apply_style("Enter the playlist URL you want to download as MP4:", "/cyan")) |
| 15 | + url = input(">> ").strip() |
| 16 | + if not URL_RE.match(url): |
| 17 | + print(apply_style("Invalid URL. Please enter a valid YouTube URL.", "/red/bold")) |
| 18 | + return |
| 19 | + |
| 20 | + ydl_opts = {"quiet": True, "no_warnings": True} |
| 21 | + try: |
| 22 | + with yt_dlp.YoutubeDL(ydl_opts) as ydl: |
| 23 | + info = ydl.extract_info(url, download=False) |
| 24 | + except Exception as e: |
| 25 | + print(apply_style(f"Failed to fetch playlist info: {e}", "/red/bold")) |
| 26 | + return |
| 27 | + |
| 28 | + playlist_title = info.get("title") or info.get("playlist_title") or "playlist" |
| 29 | + safe_playlist_title = sanitize(playlist_title)[:60] |
| 30 | + |
| 31 | + format_map = { |
| 32 | + "1": "bestvideo[height>=1080]+bestaudio/best[height>=1080]", |
| 33 | + "2": "bestvideo[height<=1080]+bestaudio/best[height<=1080]", |
| 34 | + "3": "bestvideo[height<=720]+bestaudio/best[height<=720]", |
| 35 | + "4": "bestvideo[height<=480]+bestaudio/best[height<=480]", |
| 36 | + "5": "bestvideo[height<=360]+bestaudio/best[height<=360]", |
| 37 | + } |
| 38 | + |
| 39 | + quality_title = """ |
| 40 | +Select desired download quality for playlist: |
| 41 | + [1] >= 1080p Full HD+/4K |
| 42 | + [2] 1080p Full HD |
| 43 | + [3] 720p HD |
| 44 | + [4] 480p SD |
| 45 | + [5] <= 360p Low |
| 46 | + """ |
| 47 | + print(apply_style(quality_title, "/cyan/bold")) |
| 48 | + while True: |
| 49 | + qua_text = apply_style("Enter choice number (1-5): ", "/green/bold") |
| 50 | + choice = input(qua_text).strip() |
| 51 | + if choice in format_map: |
| 52 | + break |
| 53 | + print(apply_style("Invalid choice. Please select a number from 1 to 5.", "/red/bold")) |
| 54 | + |
| 55 | + destination = Path(get_download_path("mp4")) |
| 56 | + playlist_folder = destination / safe_playlist_title |
| 57 | + playlist_folder.mkdir(parents=True, exist_ok=True) |
| 58 | + |
| 59 | + ask_subs = input(apply_style("\nDownload subtitles for playlist videos? (y/n): ", "/cyan")).strip().lower() |
| 60 | + sub_flags = [] |
| 61 | + cookie_path = "" |
| 62 | + if ask_subs == "y": |
| 63 | + print(apply_style("Note: YouTube may block subtitle extraction with HTTP 429. If that happens provide a cookies file.", "/yellow")) |
| 64 | + cookie_path = input(apply_style("Enter path to cookies file for yt-dlp (optional, press Enter to skip): ", "/green")).strip() |
| 65 | + lang = input(apply_style("Enter subtitle language code (e.g. en) or leave blank for all: ", "/green")).strip() |
| 66 | + pref_auto = input(apply_style("Also download automatic subtitles if manual not available? (y/n) [y]: ", "/green")).strip().lower() |
| 67 | + if pref_auto == "": |
| 68 | + pref_auto = "y" |
| 69 | + sub_flags += ["--write-sub"] |
| 70 | + if pref_auto == "y": |
| 71 | + sub_flags += ["--write-auto-sub"] |
| 72 | + if lang: |
| 73 | + sub_flags += ["--sub-lang", lang] |
| 74 | + sub_flags += ["--convert-subs", "srt"] |
| 75 | + if cookie_path: |
| 76 | + sub_flags += ["--cookies", cookie_path] |
| 77 | + |
| 78 | + fmt = format_map[choice] |
| 79 | + out_template = str(playlist_folder / "%(playlist_index)03d - %(title)s.%(ext)s") |
| 80 | + |
| 81 | + cmd = [ |
| 82 | + "yt-dlp", |
| 83 | + "-i", |
| 84 | + "--yes-playlist", |
| 85 | + "-f", fmt, |
| 86 | + "-o", out_template, |
| 87 | + ] |
| 88 | + if sub_flags: |
| 89 | + cmd += sub_flags |
| 90 | + |
| 91 | + cmd += [url] |
| 92 | + |
| 93 | + print(apply_style("\nStarting playlist download. This may take a while depending on size...\n", "/yellow/bold")) |
| 94 | + start = int(time.time()) |
| 95 | + try: |
| 96 | + sp.run(cmd, check=True) |
| 97 | + except Exception as e: |
| 98 | + print(apply_style(f"An error occurred while downloading the playlist: {e}", "/red/bold")) |
| 99 | + return |
| 100 | + end = int(time.time()) |
| 101 | + print(apply_style(f"\nPlaylist '{playlist_title}' downloaded to: {playlist_folder}", "/green/bold")) |
| 102 | + print(apply_style(f"Time taken: {end - start} sec", "/cyan")) |
0 commit comments