Simple YouTube audio (music) 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:

#!/bin/bash
#
# This script is used to download YT videos as
# audio using yt-dlp and save them to the ~/Music/
# directory. The user must provide the URL as the
# first argument.
#

# ======================= #
# ======= globals ======= #
# ======================= #

# User defined flies and directories
g_music_dir="/home/$USER/Music/"
g_temp_file="/home/$USER/.cache/playlist.txt"

# 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.
function f_check_dependencies {
        if command -v aria2c > /dev/null 2>&1 ; then
                true
        else
                echo -e "${c_red}Program 'aria2' not found!$c_normal"
                exit 1
        fi

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

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

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

        yt-dlp --quiet \
                --no-warnings \
                --progress \
                --ignore-errors \
                --downloader aria2c \
                --downloader-args "--max-connection-per-server=16 --max-concurrent-downloads=16 --user-agent='$g_user_agent'" \
                --no-mtime \
                --extract-audio \
                --audio-format mp3 \
                --audio-quality 0 \
                --prefer-ffmpeg \
                --postprocessor-args "-q:a 0 -map a" \
                -o "$dir%(title)s.%(ext)s" \
                "$url"
}

# Downloads song. Takes two parameters. First is the song URL and seconds is
# the directory where the song will be located.
function f_dw_song_and_notify {
        local url="$1"
        local dir="$2"

        echo "Downloading video from URL '$url'"

        if ! f_dw_song "$url" "$dir"; then
                echo -e "${c_red}FAILED to download video from URL '$url' properly!$c_normal"
        else
                echo -e "${c_green}Video from URL '$url' has been downloaded!$c_normal"
        fi
}

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

        start_time="$(date +%s)"

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

                dir="${g_music_dir}$(date '+%H%M%S%d%m')-playlist-download/"

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


                readarray -t urls < "$g_temp_file"

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

                rm "$g_temp_file"
        else
                f_dw_song_and_notify "$url" "$dir"
        fi

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

# The main function. Starts the program.
function f_main {
        f_check_dependencies
        f_parse_data_and_dw "$1"
}

# ======================= #
# ======== main ========= #
# ======================= #

f_main "$1"
Created at: 05-Mar-2025 Updated at: 08-Apr-2025