Skip to main content

Download YouTube Videos Using a Python Script

· 6 min read

Want to save YouTube videos locally? This post walks through a Python script that handles everything for you — set it up once, then just swap the URL each time.


Setting Up the Environment

Your Mac needs the following four tools. Install them in order.

Homebrew

macOS package manager — the foundation for installing everything else.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Verify:

brew --version

✅ Success: shows Homebrew 4.x.x ❌ Failure: shows command not found


ffmpeg

Merges audio and video streams — without it you'll only get a silent video.

brew install ffmpeg

Verify:

ffmpeg -version

✅ Success: shows ffmpeg version 7.x.x ❌ Failure: shows command not found


Node.js

Solves YouTube's JS encryption challenge — without it all format options are lost.

brew install node

Verify:

node --version

✅ Success: shows v26.x.x ❌ Failure: shows command not found


yt-dlp

The core download library.

pip3 install yt-dlp --break-system-packages

Verify:

yt-dlp --version

✅ Success: shows 2026.x.xx ❌ Failure: shows command not found


Two Extra Configuration Steps

Grant Terminal Full Disk Access (needed to read Safari cookies)

System Settings → Privacy & Security → Full Disk Access → Add "Terminal"

Enable a proxy (required to access YouTube outside China)

I'm definitely not going to teach you that one!


Get the Code

You can download the script I wrote, or write it yourself (or have AI write it — see the next section).

Download main.py

Script contents:

import subprocess
import sys
import os

# ── Configuration ────────────────────────────────────────────────────────────
VIDEO_URL = "XXXX" # Replace with a real YouTube URL
OUTPUT_DIR = os.path.expanduser("~/Desktop") # Output to Desktop
NODE_PATH = "/opt/homebrew/bin/node" # Node.js path (installed via Homebrew)
# ─────────────────────────────────────────────────────────────────────────────


def download_video(url: str, output_dir: str) -> None:
"""
Calls the yt-dlp CLI to download a YouTube video in H.264 MP4 format.
"""
output_template = os.path.join(output_dir, "%(title)s.%(ext)s")

cmd = [
"yt-dlp",
# Prefer H.264 video stream + best audio
"--format", "bestvideo[vcodec^=avc1]+bestaudio/bestvideo[ext=mp4]+bestaudio/best",
# Force MP4 container
"--merge-output-format", "mp4",
# Specify Node.js path for solving YouTube's JS encryption
"--js-runtimes", f"node:{NODE_PATH}",
# Download JS challenge decryption script from GitHub (requires internet on first run)
"--remote-components", "ejs:github",
# Read Safari cookies to bypass bot detection
"--cookies-from-browser", "safari",
# Output file path template
"--output", output_template,
url,
]

print(f"[INFO] Starting download: {url}")
print(f"[INFO] Output directory: {output_dir}\n")

result = subprocess.run(cmd)

if result.returncode == 0:
print("\n[✓] Download complete! Video saved to Desktop.")
else:
print("\n[✗] Download failed. Check the error output above.", file=sys.stderr)
sys.exit(1)


if __name__ == "__main__":
# Supports passing a URL as a command-line argument: python3 main.py <url>
url = sys.argv[1] if len(sys.argv) > 1 else VIDEO_URL

if url == "XXXX":
print("[✗] Please replace VIDEO_URL with a real URL, or pass it as a command-line argument.",
file=sys.stderr)
print(" Usage: python3 main.py \"YouTube URL\"", file=sys.stderr)
sys.exit(1)

download_video(url, OUTPUT_DIR)

The Lazy Approach: Let AI Write the Code

Don't want to write the code yourself? Just paste one of these prompts into ChatGPT, DeepSeek, or Claude and they'll output a working script.

English prompt (recommended — more stable output):

I need you to help me set up a YouTube video download environment on macOS and write a complete Python script.

## My Environment
- Device: MacBook (Apple Silicon, M-series chip)
- OS: macOS

## What I Need You To Do

### Step 1 — Check and Install Dependencies
Check whether the following tools are installed one by one. If not, provide the install command:
1. Homebrew: via https://brew.sh/
2. ffmpeg: via brew install ffmpeg
3. Node.js: via brew install node
4. yt-dlp: via pip3 install yt-dlp --break-system-packages

### Step 2 — Write the Python Script
Filename: youtube_downloader.py
Requirements:
- Use subprocess to call the yt-dlp CLI (do NOT use the yt_dlp Python API)
- Video format: H.264 codec, MP4 container
- Quality: automatically select the highest available quality
- Cookies: read from Safari (--cookies-from-browser safari)
- Node.js path: /opt/homebrew/bin/node
- Include --remote-components ejs:github to solve JS challenges
- Output directory: Desktop (~/Desktop)
- Accept video URL as a command-line argument: python3 youtube_downloader.py "YouTube URL"
- Add comments in English

### Step 3 — Tell Me How To Use It
Explain how to run the script in one sentence.

## Important Notes
- macOS root directory / is read-only — do NOT output files there
- Terminal needs Full Disk Access enabled in System Settings to read Safari cookies — please remind me to do this
- Do NOT use "ios" as the player_client — it does not support cookies

AI can write the code for you, but you still need to set up the environment yourself (the four tools above). If you don't want to do that manually either, use Claude Code or Codex to run the install commands automatically — just keep clicking yes.


Usage

Once the environment is set up, every download only takes one command.

Open Terminal and run:

python3 ~/Downloads/main.py "paste your YouTube URL here"

If you saved main.py somewhere else, replace ~/Downloads/main.py with the actual path. ~/Downloads refers to your Downloads folder — no need to substitute your username.

Example:

python3 ~/Downloads/main.py "https://www.youtube.com/watch?v=5wvq8w7YBXU"

Press Enter and wait — the video will appear on your Desktop when done.


Two things to check before each use:

① Your proxy is active (e.g. Shadowrocket is connected)

② You're using a freshly opened Terminal window (not one that's been open for days)

You only need to set up the environment once. After that, any YouTube URL works.


FAQ

What is Homebrew? I wrote a separate post about it — check that out.

What video quality will I get? The highest available by default. This line in the script controls the resolution selection logic:

"bestvideo[vcodec^=avc1]+bestaudio/bestvideo[ext=mp4]+bestaudio/best"

It selects the highest-quality stream among all H.264-encoded video tracks.

Terminal is stuck and nothing's happening? The first run downloads a decryption script from the internet, which can be slow on some networks. Make sure your proxy is active, or wait 1–2 minutes.

command not found error? A dependency didn't install correctly. Go back to the "Setting Up the Environment" section and verify each tool one by one.

permission denied or cookie read failure? Terminal doesn't have Full Disk Access. Go to System Settings → Privacy & Security → Full Disk Access → Add "Terminal", then open a new Terminal window and try again.

Download failed and you can't read the error? Check in order: ① Is your proxy on? ② Is yt-dlp up to date? (pip3 install -U yt-dlp --break-system-packages) ③ Is the URL complete and wrapped in quotes?