Skip to content

Instantly share code, notes, and snippets.

@32teeth
Last active October 23, 2025 18:10
Show Gist options
  • Save 32teeth/5d571a09aaababb015bbd43b0720265e to your computer and use it in GitHub Desktop.
Save 32teeth/5d571a09aaababb015bbd43b0720265e to your computer and use it in GitHub Desktop.
YouTube Audio Downloader
# youtube.sh
#
# Description:
# Downloads a single YouTube (or supported site) video as a high-quality MP3 (320 kbps)
# using yt-dlp and ffmpeg. It:
# - Validates required commands (yt-dlp, ffmpeg)
# - Fetches video title and uploader
# - Sanitizes the title for a safe filename
# - Downloads best available audio
# - Extracts / converts to MP3 @ 320k
# - Embeds thumbnail and metadata (artist, title)
# - Falls back to listing formats if the main download attempt fails
#
# Requirements:
# - yt-dlp (https://github.com/yt-dlp/yt-dlp)
# - ffmpeg
#
# Installation (example):
# brew install yt-dlp ffmpeg
#
# Usage:
# youtube <YouTube URL>
#
# Example:
# youtube "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
#
# Notes:
# - Output file name is derived from the video title, sanitized.
# - If metadata extraction fails, a generic filename is used.
# - Does not process playlists (single video only).
#
# To source in zsh (e.g. from ~/.zshrc):
# source /Users/andreug/.zsh_functions/utils/youtube.sh
youtube() {
local url="$1"
# Ensure a URL was provided
if [[ -z "$url" ]]; then
echo "Usage: youtube <YouTube URL>"
return 1
fi
# Verify required commands exist
for cmd in yt-dlp ffmpeg; do
if ! command -v "$cmd" >/dev/null 2>&1; then
echo "Error: $cmd is not installed." >&2
return 1
fi
done
# Show yt-dlp version (helps debugging)
yt-dlp --version
# Retrieve title and uploader (suppress warnings; ignore failure)
local title artist safe_title
title="$(yt-dlp --no-warnings --skip-download --print title -- "$url" 2>/dev/null || true)"
artist="$(yt-dlp --no-warnings --skip-download --print uploader -- "$url" 2>/dev/null || true)"
# Sanitize title for filesystem (fallback to 'audio' if empty)
safe_title="$(printf '%s' "${title:-audio}" \
| tr '/<>:\"\\|?*' '_' \
| tr -cd '[:alnum:] _-' \
| sed -E 's/ +/ /g; s/[[:space:]]+$//')"
# Prefer multiple player clients to improve success rate
local extractor_args="youtube:player_client=ios,android,web"
echo "Downloading and converting → ${safe_title}.mp3"
# Main download & convert
yt-dlp \
--no-playlist \
--extractor-args "$extractor_args" \
-f "bestaudio/best" \
-o "${safe_title}.%(ext)s" \
-x --audio-format mp3 --audio-quality 320k \
--add-metadata \
--parse-metadata "%(uploader)s:%(artist)s" \
--parse-metadata "%(title)s:%(title)s" \
--embed-thumbnail \
-- "$url" || {
# On failure, attempt a format listing with a stricter single client
echo "yt-dlp failed. Trying a stricter fallback client (web only) to inspect formats..."
yt-dlp --extractor-args "youtube:player_client=web" -F -- "$url"
return 2
}
echo "Done: ${safe_title}.mp3"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment