Skip to content

Instantly share code, notes, and snippets.

@emendir
Last active July 27, 2024 13:54
Show Gist options
  • Save emendir/e5e02757850fcfdf0d9e9530ae5cf8d3 to your computer and use it in GitHub Desktop.
Save emendir/e5e02757850fcfdf0d9e9530ae5cf8d3 to your computer and use it in GitHub Desktop.
Download YouTube Playlist

Download YouTube Playlist Script

This script downloads videos from a YouTube playlist, either the full video or audio-only in MP3 format. The produced files' names include the track number and title, and the following media info is stored in the files' metadata:

  • title
  • track number
  • album (YouTube playlist title)
  • publisher (name of the YouTube channel)

Usage: python download_youtube_playlist.py <playlist_url> <download_directory> [--audio-only]

Arguments: playlist_url URL of the YouTube playlist to download. download_directory Directory where the downloaded files will be saved. --audio-only Optional flag to download audio-only files.

Requirements: - pytube - yt-dlp - ffmpeg-python

Ensure the following Python packages are installed: pip install pytube yt-dlp ffmpeg-python

#!/bin/python3
"""
Download videos from a YouTube playlist with appropriate filenames and metadata.
Download YouTube Playlist Script
This script downloads videos from a YouTube playlist, either the full video or audio-only in MP3 format.
The produced files' names include the track number and title, and the following media info is stored in the files' metadata:
- title
- track number
- album (YouTube playlist title)
- publisher (name of the YouTube channel)
Usage:
python download_youtube_playlist.py <playlist_url> <download_directory> [--audio-only]
Arguments:
playlist_url URL of the YouTube playlist to download.
download_directory Directory where the downloaded files will be saved.
--audio-only Optional flag to download audio-only files.
Requirements:
- pytube
- yt-dlp
- ffmpeg-python
Ensure the following Python packages are installed:
pip install pytube yt-dlp ffmpeg-python
"""
import os
import sys
from pytube import Playlist
import yt_dlp
import ffmpeg
import tempfile
import shutil
def download_videos_from_playlist(
playlist_url, download_directory, audio_only=False
):
"""Download videos from a YouTube playlist.
Args:
playlist_url (str): URL of the YouTube playlist.
download_directory (str): Directory where the downloaded files will be saved.
audio_only (bool): If True, download audio-only files.
Returns:
None
"""
tempdir = tempfile.mkdtemp()
# Create the directory if it doesn't exist
if not os.path.exists(download_directory):
os.makedirs(download_directory)
# Fetch playlist details using pytube
playlist = Playlist(playlist_url)
videos = playlist.videos
# Prepare yt-dlp options
ydl_opts = {
'format': 'bestaudio' if audio_only else 'best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}] if audio_only else [],
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
for index, video in enumerate(videos, start=1):
print(f'Downloading {index}. {video.title}')
info_dict = ydl.extract_info(video.watch_url, download=False)
# filename without extension
filename = f'{index}. {video.title}'
ext = 'mp3' if audio_only else info_dict.get('ext', 'mp4')
output_template = os.path.join(tempdir, f'{filename}.%(ext)s')
temp_path = os.path.join(tempdir, filename)
ydl_opts['outtmpl'] = output_template
ydl = yt_dlp.YoutubeDL(ydl_opts)
ydl.download([video.watch_url])
temp_path = output_template % {'ext': ext}
# filename with extension
filename = os.path.basename(temp_path)
output_path = os.path.join(download_directory, filename)
# Set metadata using ffmpeg
print(f'Setting metadata for {index}. {video.title}')
metadata = {
"title": video.title,
"track": index,
"album": playlist.title,
"publisher": video.author
}
metadata_list = [f"{key}={value}" for key,
value in list(metadata.items())]
metadata_dict = {f"metadata:g:{i}": e for i,
e in enumerate(metadata_list)}
# Use `ffmpeg` to duplicate the file,
# setting metadata and copying streams without re-encoding
ffmpeg.input(temp_path).output(
output_path,
**metadata_dict,
codec='copy'
).overwrite_output().run()
os.remove(temp_path)
shutil.rmtree(tempdir)
if __name__ == '__main__':
if len(sys.argv) not in [3, 4]:
print(
"Usage: python download_youtube_playlist.py <playlist_url> <download_directory> [--audio-only]")
sys.exit(1)
playlist_url = sys.argv[1]
download_directory = sys.argv[2]
audio_only = '--audio-only' in sys.argv
download_videos_from_playlist(playlist_url, download_directory, audio_only)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment