Skip to content

Instantly share code, notes, and snippets.

@scivision
Last active February 10, 2026 13:14
Show Gist options
  • Select an option

  • Save scivision/c81e43fe0f26c4fec70938b14d236e6b to your computer and use it in GitHub Desktop.

Select an option

Save scivision/c81e43fe0f26c4fec70938b14d236e6b to your computer and use it in GitHub Desktop.
YouTube channel download with yt-dlp from Python script

YouTube channel download using yt-dlp from Python

Just a simple script to store useful yt-dlp options. Like what one would do with a Bash script, but platform-agnostic.

#!/usr/bin/env python3
"""
Download all videos from a YouTube channel using yt-dlp.
Comments, thumbnails, and metadata are included.
"""
import argparse
import subprocess
from pathlib import Path
from ytdlp_command import find_yt_dlp
def run_yt_dlp(channel_handle: str, output_dir: Path | str) -> None:
"""
Execute yt-dlp with the recommended settings for full channel download.
"""
base_dir = Path(output_dir).resolve()
base_dir.mkdir(parents=True, exist_ok=True)
# Archive file prevents re-downloading already saved videos
archive_path = base_dir / "archive.txt"
# Output template: channel_name / date - title [id].mp4
output_template = str(
base_dir / "%(uploader)s/%(upload_date)s - %(title)s [%(id)s].%(ext)s"
)
cmd = [
find_yt_dlp(),
"--no-warnings", # cleaner output
"-f",
"bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best",
"--merge-output-format",
"mp4",
"-o",
output_template,
"--download-archive",
str(archive_path),
"--sleep-requests",
"2", # polite rate limiting
"--write-thumbnail",
"--embed-thumbnail",
"--write-info-json",
"--write-comments",
"--embed-metadata", # bonus: embeds title/description/etc.
f"https://www.youtube.com/{channel_handle}",
]
print(f"\nStarting download for YouTube channel: {channel_handle}")
print(f"Output will be saved to: {base_dir}")
print(f"Archive file: {archive_path}")
try:
# Run yt-dlp and stream output live to terminal
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1, # line buffered
)
# Print output in real time
if process.stdout is not None:
for line in process.stdout:
print(line, end="", flush=True)
return_code = process.wait()
if return_code == 0:
print("\n\nDownload completed successfully ✓")
else:
raise SystemExit(f"\nyt-dlp exited with code {return_code}")
except KeyboardInterrupt:
raise SystemExit("\n\nRun the script again to resume.")
def main():
parser = argparse.ArgumentParser(
description="Download all videos from a YouTube channel using yt-dlp",
)
parser.add_argument("channel", help="YouTube channel handle")
parser.add_argument(
"-o",
"--output-dir",
help="Base folder where channel subfolder will be created",
default=Path.cwd(),
)
args = parser.parse_args()
# Normalize: make sure it starts with @
channel = args.channel
if not channel.startswith("@"):
channel = "@" + channel
run_yt_dlp(channel, args.output_dir)
if __name__ == "__main__":
main()
"""
Download a single video from YouTube at best quality using yt-dlp.
Comments, thumbnails, and metadata are included.
"""
import argparse
import subprocess
from pathlib import Path
from ytdlp_common import find_yt_dlp
def run_yt_dlp(video_url: str, output_dir: Path | str) -> None:
"""
Execute yt-dlp with the recommended settings for single video download.
"""
output_dir = Path(output_dir).resolve()
# Output template: date - title [id].mp4
output_template = str(output_dir / "%(upload_date)s - %(title)s [%(id)s].%(ext)s")
cmd = [
find_yt_dlp(),
"--no-warnings", # cleaner output
"-f",
"bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best",
"--merge-output-format",
"mp4",
"-o",
output_template,
"--sleep-requests",
"2", # polite rate limiting
"--write-thumbnail",
"--embed-thumbnail",
"--write-info-json",
"--write-comments",
"--embed-metadata", # bonus: embeds title/description/etc.
video_url,
]
print(f"\nStarting download for YouTube video: {video_url}")
print(f"Output will be saved to: {output_template}*")
try:
# Run yt-dlp and stream output live to terminal
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1, # line buffered
)
# Stream output live to terminal
for line in process.stdout:
print(line, end="")
process.wait()
except KeyboardInterrupt:
print("\nDownload interrupted by user.")
def main():
parser = argparse.ArgumentParser(
description="Download a single YouTube video at best quality using yt-dlp."
)
parser.add_argument(
"video_url",
type=str,
help="The full URL of the YouTube video to download.",
)
parser.add_argument(
"-o",
"--output-dir",
type=str,
default=".",
help="Directory to save the downloaded video. Defaults to current directory.",
)
args = parser.parse_args()
run_yt_dlp(args.video_url, args.output_dir)
if __name__ == "__main__":
main()
import functools
from shutil import which
@functools.cache
def find_yt_dlp() -> str:
"""
Find the yt-dlp executable in the system PATH.
Caches the result for future calls.
"""
yt_dlp_path = which("yt-dlp")
if yt_dlp_path is None:
raise FileNotFoundError(
"yt-dlp executable not found in system PATH. Please install yt-dlp and ensure it's accessible."
)
return yt_dlp_path
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment