diff --git a/yt_playlist_video_downloader/README.md b/yt_playlist_video_downloader/README.md new file mode 100644 index 0000000..2e358dc --- /dev/null +++ b/yt_playlist_video_downloader/README.md @@ -0,0 +1,266 @@ +# YOUTUBE PLAYLIST/VIDEO DOWNLOADER + +A Python CLI tool that downloads entire YouTube playlists or single videos in the highest quality possible, with automatic merging of video and audio streams (if ffmpeg is installed). Built on yt-dlp -- fast, reliable, and actively maintained. + +## FEATURES + +* * * * * + +- Download entire playlists or single videos with one command. + +- Highest quality -- selects the best video + best audio streams and merges them into a single MP4 (requires ffmpeg). + +- Fallback to H.264 -- force a lighter, widely‑compatible codec to avoid playback lag. + +- Limit the number of videos downloaded from a playlist. + +- Skip existing files -- no duplicate downloads. + +- Progress bar during download. + +- Works with private/unlisted playlists (as long as you have access). + +## REQUIREMENTS + +* * * * * + +- Python 3.6+ + +- yt-dlp -- installed via pip + +- ffmpeg (optional but highly recommended for best quality) -- installed separately + +## INSTALLATION + +* * * * * + +1. Install Python dependencies: + ```bash + pip install yt-dlp + ``` + +2. Install FFmpeg (for merging highest quality streams): + + - Windows: Download from [gyan.dev](https://gyan.dev/) (choose correct architecture -- 64‑bit or 32‑bit). Extract, then add the bin folder to your system PATH. Verify with: `ffmpeg -version` in a new Command Prompt. + + - macOS: `brew install ffmpeg` + + - Linux (Debian/Ubuntu): `sudo apt update && sudo apt install ffmpeg` + + - Linux (Fedora): `sudo dnf install ffmpeg` + + Without ffmpeg, the script falls back to a single‑stream format (usually 720p or lower). For maximum quality, install it. + +## USAGE + +* * * * * + +`python main.py [options]` + +Required argument: +URL -- YouTube video or playlist URL (must contain "list=" for playlists) + +Optional arguments: +-o, --output DIR -- Output directory (default: current folder) +-n, --limit N -- Download only the first N videos (playlist only) +-q, --quality Q -- Override format filter (see examples below) +-v, --verbose -- Show detailed download logs + +## EXAMPLES + +* * * * * + +1. Download an entire playlist (highest quality): + ```bash + python main.py "[https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxx](https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxx)" -o ./videos + ``` + +2. Download only the first 5 videos from a playlist: + ```bash + python main.py "[https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxx](https://www.youtube.com/playlist?list=PLxxxxxxxxxxxxxxxx)" -n 5 -o ./videos + ``` + +3. Download a single video: + ```bash + python main.py "[https://www.youtube.com/watch?v=abc123](https://www.youtube.com/watch?v=abc123)" -o ./videos + ``` + +4. Force 1080p H.264 (smooth playback on any device): + ```bash + python main.py "URL" -q "bestvideo[height<=1080][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=1080][vcodec^=avc1]" -o ./videos + ``` + +5. Force 720p H.264 (lightweight, fast download): + ```bash + python main.py "URL" -q "bestvideo[height<=720][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=720][vcodec^=avc1]" -o ./videos + ``` + +6. Use verbose mode to debug: + ```bash + python main.py "URL" -v + ``` + +## HOW IT WORKS + +* * * * * + +1. The script fetches the playlist or video metadata. + +2. If ffmpeg is present, it downloads the best video and best audio streams separately, then merges them into an MP4. + +3. If ffmpeg is missing, it falls back to the "best" single‑stream format (quality may be lower). + +4. Videos are saved in a folder named after the playlist (or "Videos/" for single videos) inside your output directory. + +## TROUBLESHOOTING + +* * * * * + +- Only 1 video downloads: Make sure your URL contains "&list=" or is the "/playlist?list=" page -- you are probably pointing to a single video. + +- Error: 'list' is not recognized: You forgot to put the URL in double quotes. Always wrap the URL in quotes on Windows. + +- Video lags in VLC: You are likely playing a VP9 or HEVC (H.265) video that your hardware can't decode. Fix: Force H.264 with the -q filter (see examples above) or enable hardware acceleration in VLC (Tools -> Preferences -> Input/Codecs -> Video codecs -> FFmpeg -> Hardware decoding -> DirectX/D3D11). + +- ffmpeg not found: Install FFmpeg and add it to your system PATH. Restart your terminal after installation. + +- Can't delete downloaded videos: Close VLC and any other media player. Then use the command: `rmdir /s /q "folder_path"` (Windows) or `rm -rf folder_path` (macOS/Linux). + +## LICENSE + +* * * * * + +This script is free to use and modify. No warranty -- use at your own risk. + +## ACKNOWLEDGEMENTS + +* * * * * + +- yt-dlp (https://github.com/yt-dlp/yt-dlp) -- the powerhouse behind the downloads. + +- FFmpeg (https://ffmpeg.org/) -- for merging streams. + +This script and its documentation were created with the assistance of an AI tool (DeepSeek) to ensure clarity and completeness. + +Happy downloading! + +## REQUIREMENTS + +* * * * * + +- Python 3.6+ + +- yt-dlp -- installed via pip + +- ffmpeg (optional but highly recommended for best quality) -- installed separately + +## INSTALLATION + +* * * * * + +1. Install Python dependencies:\ + pip install yt-dlp + +2. Install FFmpeg (for merging highest quality streams): + + - Windows: Download from [gyan.dev](https://gyan.dev/) (choose correct architecture -- 64‑bit or 32‑bit). Extract, then add the bin folder to your system PATH. Verify with: ffmpeg -version in a new Command Prompt. + + - macOS: brew install ffmpeg + + - Linux (Debian/Ubuntu): sudo apt update && sudo apt install ffmpeg + + - Linux (Fedora): sudo dnf install ffmpeg + + Without ffmpeg, the script falls back to a single‑stream format (usually 720p or lower). For maximum quality, install it. + +## USAGE + +* * * * * + +python main.py [options] + +Required argument:\ +URL -- YouTube video or playlist URL (must contain "list=" for playlists) + +Optional arguments:\ +-o, --output DIR -- Output directory (default: current folder)\ +-n, --limit N -- Download only the first N videos (playlist only)\ +-q, --quality Q -- Override format filter (see examples below)\ +-v, --verbose -- Show detailed download logs + +## EXAMPLES + +* * * * * + +1. Download an entire playlist (highest quality):\ +```bash + python main.py "" -o ./videos +``` +2. Download only the first 5 videos from a playlist:\ +```bash + python main.py "" -n 5 -o ./videos +``` +3. Download a single video:\ +```bash + python main.py "" -o ./videos +``` +4. Force 1080p H.264 (smooth playback on any device):\ +```bash + python main.py "URL" -q "bestvideo[height<=1080][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=1080][vcodec^=avc1]" -o ./videos +``` + +5. Force 720p H.264 (lightweight, fast download):\ +```bash + python main.py "URL" -q "bestvideo[height<=720][vcodec^=avc1]+bestaudio[acodec^=mp4a]/best[height<=720][vcodec^=avc1]" -o ./videos +``` + +6. Use verbose mode to debug:\ +```bash + python main.py "URL" -v +``` + +## HOW IT WORKS + +* * * * * + +1. The script fetches the playlist or video metadata. + +2. If ffmpeg is present, it downloads the best video and best audio streams separately, then merges them into an MP4. + +3. If ffmpeg is missing, it falls back to the "best" single‑stream format (quality may be lower). + +4. Videos are saved in a folder named after the playlist (or "Videos/" for single videos) inside your output directory. + +## TROUBLESHOOTING + +* * * * * + +- Only 1 video downloads: Make sure your URL contains "&list=" or is the "/playlist?list=" page -- you are probably pointing to a single video. + +- Error: 'list' is not recognized: You forgot to put the URL in double quotes. Always wrap the URL in quotes on Windows. + +- Video lags in VLC: You are likely playing a VP9 or HEVC (H.265) video that your hardware can't decode. Fix: Force H.264 with the -q filter (see examples above) or enable hardware acceleration in VLC (Tools -> Preferences -> Input/Codecs -> Video codecs -> FFmpeg -> Hardware decoding -> DirectX/D3D11). + +- ffmpeg not found: Install FFmpeg and add it to your system PATH. Restart your terminal after installation. + +- Can't delete downloaded videos: Close VLC and any other media player. Then use the command: rmdir /s /q "folder_path" (Windows) or rm -rf folder_path (macOS/Linux). + +## LICENSE + +* * * * * + +This script is free to use and modify. No warranty -- use at your own risk. + +## ACKNOWLEDGEMENTS + +* * * * * + +- yt-dlp () -- the powerhouse behind the downloads. + +- FFmpeg () -- for merging streams. + +This script and its documentation were created with the assistance of an AI tool (DeepSeek) to ensure clarity and completeness. + +Happy downloading! + +* * * * * diff --git a/yt_playlist_video_downloader/main.py b/yt_playlist_video_downloader/main.py new file mode 100644 index 0000000..2a6f0cf --- /dev/null +++ b/yt_playlist_video_downloader/main.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +""" +YouTube Playlist/Video Downloader – Highest Quality with FFmpeg. +""" + +import os +import sys +import argparse +import subprocess +from pathlib import Path + +try: + import yt_dlp +except ImportError: + print("ERROR: yt-dlp is not installed. Run: pip install yt-dlp") + sys.exit(1) + +def check_ffmpeg(): + """Return True if ffmpeg is available and working.""" + try: + subprocess.run(["ffmpeg", "-version"], capture_output=True, check=True, timeout=5) + return True + except (subprocess.SubprocessError, FileNotFoundError, OSError, subprocess.TimeoutExpired): + return False + +def get_playlist_info(url): + with yt_dlp.YoutubeDL({'quiet': True, 'extract_flat': True}) as ydl: + try: + info = ydl.extract_info(url, download=False) + if 'entries' in info: + return info.get('title', 'Playlist'), len(info['entries']) + else: + return None, 1 + except Exception as e: + print(f"Could not fetch playlist info: {e}") + return None, 1 + +def progress_hook(d): + if d['status'] == 'downloading': + p = d.get('_percent_str', '0%').strip() + s = d.get('_speed_str', 'N/A').strip() + e = d.get('_eta_str', 'N/A').strip() + print(f"\rDownloading: {p} at {s}, ETA: {e}", end='') + elif d['status'] == 'finished': + print("\nDownload completed, now processing...") + +def download_playlist(url, output_dir, limit=None, quality=None): + Path(output_dir).mkdir(parents=True, exist_ok=True) + + # Check for ffmpeg + has_ffmpeg = check_ffmpeg() + if not has_ffmpeg: + print(" ffmpeg is not installed or not working properly!") + print(" Without ffmpeg, we cannot merge separate video+audio streams.") + print(" Falling back to 'best' format (a single stream, may be lower quality).") + print(" For best quality, install ffmpeg from https://ffmpeg.org/ and add it to PATH.\n") + if quality is None: + quality = "best" + else: + print(" ffmpeg found – will merge best video and audio streams.\n") + if quality is None: + quality = "bestvideo+bestaudio/best" + + # Get playlist info + playlist_title, count = get_playlist_info(url) + if playlist_title: + safe_title = "".join(c for c in playlist_title if c.isalnum() or c in " -_").strip() or "Playlist" + subfolder = safe_title + outtmpl = os.path.join(output_dir, subfolder, '%(playlist_index)s - %(title)s.%(ext)s') + print(f" Playlist: {playlist_title} ({count} videos)") + else: + subfolder = "Videos" + outtmpl = os.path.join(output_dir, subfolder, '%(title)s.%(ext)s') + print(" Single video download") + + ydl_opts = { + 'format': quality, + 'outtmpl': outtmpl, + 'merge_output_format': 'mp4', + 'ignoreerrors': True, + 'nooverwrites': True, + 'quiet': False, + 'progress_hooks': [progress_hook], + } + + if limit and playlist_title: + ydl_opts['playlistend'] = limit + print(f" Limiting to first {limit} videos") + + with yt_dlp.YoutubeDL(ydl_opts) as ydl: + try: + print(f"\n Fetching: {url}\n") + ydl.download([url]) + print("\n All downloads completed!") + except Exception as e: + print(f"\n An error occurred: {e}") + sys.exit(1) + +def main(): + parser = argparse.ArgumentParser(description="Download YouTube playlist/video in highest quality.") + parser.add_argument("url", help="Playlist or video URL (must include 'list=' for playlists)") + parser.add_argument("-o", "--output", default=".", help="Output directory (default: current)") + parser.add_argument("-n", "--limit", type=int, help="Max number of videos to download (playlist only)") + parser.add_argument("-q", "--quality", default=None, help="Override format (e.g., 'bestvideo[height<=1080]+bestaudio')") + parser.add_argument("-v", "--verbose", action="store_true", help="Show debug logs") + args = parser.parse_args() + + if args.verbose: + import logging + logging.basicConfig(level=logging.DEBUG) + + download_playlist(args.url, args.output, args.limit, args.quality) + +if __name__ == "__main__": + main() \ No newline at end of file