Simple YouTube Audio Downloader

This blog contains my shell script to download audio from YouTube videos. The programs you would need installed on your system for this script to work are:

It is also available on my GitHub.

sh
#!/usr/bin/env bash

# =========================== #
# ========= GLOBALS ========= #
# =========================== #

# User defined flies and directories
g_url="$1"
g_audio_dir="${AUDIO_DIRECTORY:-"$HOME/music"}"
g_temp_dir="/tmp/ytdw"

# Control variables used between multiple functions
g_dir_or_audio_name="$2"
g_temp_file=""
g_is_playlist=0

# Colors
c_normal="\e[0m"
c_red="\e[1;31m"
c_green="\e[1;32m"

# Constants
g_user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0"

# =========================== #
# ======== FUNCTIONS ======== #
# =========================== #

# Checks for the program dependencies, which are: aria2c, yt-dlp and ffmpeg.
# And creates the temporary directory in $g_temp_dir
function f_check_dependencies {
   if ! command -v aria2c &> /dev/null; then
    echo -e "${c_red}Program 'aria2' not found!$c_normal"
    exit 1
  fi

  if ! command -v yt-dlp &> /dev/null; then
    echo -e "${c_red}Program 'yt-dlp' not found!$c_normal"
    exit 1
  fi

  if ! command -v ffmpeg &> /dev/null; then
    echo -e "${c_red}Program 'ffmpeg' not found!$c_normal"
    exit 1
  fi

  if [ ! -d "$g_temp_dir" ]; then
    mkdir -p "$g_temp_dir"
  fi
}

# Downloads audio. Takes two parameters. First is the audio URL and seconds is
# the directory where the audio will be located. The "return" of this function
# is the return code of the yt-dlp program call.
function f_dw_audio {
  local url="$1"
  local dir="$2"
  local name=""

  if [ $g_is_playlist -eq 1 ] || [ -z "$g_dir_or_audio_name" ]; then
    name="$dir/%(title)s.%(ext)s"
  else
    name="$dir/$g_dir_or_audio_name.%(ext)s"
  fi

  echo "Downloading video from URL '$url'"

  if ! yt-dlp --quiet \
    --no-warnings \
    --progress \
    --ignore-errors \
    --no-mtime \
    --downloader aria2c \
    --downloader-args "\
      --user-agent='$g_user_agent' \
      --max-connection-per-server=16 \
      --split=16 \
    " \
    --extract-audio \
    --prefer-ffmpeg \
    --audio-quality 0 \
    --postprocessor-args "-q:a 0 -map a" \
    -o "$name" \
    "$url"; then
    echo -e "${c_red}Failed to download audio from URL '$url'!$c_normal"
  else
    echo -e "${c_green}Audio from URL '$url' downloaded successfully!$c_normal"
  fi
}

# Parses the command line parameter which can either be a playlist or a single
# audio from YT.
function f_parse_data_and_dw {
  local dir="$g_audio_dir"
  local start_time=0
  local end_time=0
  local runtime=0

  start_time="$(date +%s)"

  if [[ "$g_url" == *"playlist"* ]]; then
    echo "Starting to download playlist at URL: $g_url"

    g_is_playlist=1

    if [ -n "$g_dir_or_audio_name" ]; then
      dir="$g_audio_dir/$g_dir_or_audio_name"
    else
      dir="$g_audio_dir/$(date '+%H%M%S%d%m')-playlist"
    fi

    if [ ! -d "$dir" ]; then
      mkdir -p "$dir"
    fi

    g_temp_file="${g_temp_dir}/$(date '+%H%M%S%d%m')-playlist.txt"

    yt-dlp --quiet \
      --no-warnings \
      --flat-playlist \
      --ignore-errors \
      --print-to-file url \
      "$g_temp_file" "$g_url"

    readarray -t urls < "$g_temp_file"

    for url in "${urls[@]}"; do
      f_dw_audio "$url" "$dir"
      echo
    done

    rm "$g_temp_file"
  else
    f_dw_audio "$g_url" "$dir"
  fi

  end_time="$(date +%s)"
  runtime=$((end_time-start_time))
  echo
  echo "Total program runtime lasted for $runtime seconds!"
  echo
  exit 0
}

# =========================== #
# =========== MAIN ========== #
# =========================== #

function f_main {
  f_check_dependencies
  f_parse_data_and_dw
}

f_main
Created at: 05-Mar-2025