Bash script to download audio from Youtube

2024-06-26

This post is actually about a trick I learned that allows bash scripts to accept input either as a string or from stdin.

Here is the code. It first checks whether at least one argument is provided to the script. If an argument is found it creates a variable containing all the arguments. If no arguments are found, then it waits for input from stdin, which can either come from a pipe or can be typed in after the script is called.

#!/usr/bin/env bash

# If argument provided
if [ $# -gt 0 ]; then
    input="$*"
else
    # Read from stdin 
    while IFS= read -r line; do
        input+="$line"
    done
fi

echo $input

I used this trick to write a script to download audio files from Youtube using yt-dlp . I wanted to be able to integrate the script with ytfzf , which can search Youtube from the terminal using FZF and optionally print the URL of the selected video.

#!/usr/bin/env sh

# Download audio only using yt-dlp

# If argument provided
if [ $# -gt 0 ]; then
    input="$*"
else
    # Read from stdin 
    while IFS= read -r line; do
        input+="$line"
    done
fi

# Download 
yt-dlp \
	-f bestaudio \
	--extract-audio \
	--audio-format m4a \
	-S +size,+br \
	-o "$PWD/%(title)s.%(ext)s" \
	--external-downloader aria2c \
	--external-downloader-args "-x 5 -s 5 -j 5 -c -k 1M" $input

The script can be called in various ways.

Passing an argument:

yt_audio https://www.youtube.com/watch?v=Atkp8mklOh0

Using stdin:

echo "https://www.youtube.com/watch?v=Atkp8mklOh0" | yt_audio

Using stdin with ytfzf:

ytfzf -L Terry Barentsen Hotline Cooper Ray | yt_audio

With multiple URLs as arguments:

yt_audio https://www.youtube.com/watch?v=WyV894c8oqI https://www.youtube.com/watch?v=Atkp8mklOh0

With multiple URLs from stdin:

echo "https://www.youtube.com/watch?v=WyV894c8oqI https://www.youtube.com/watch?v=Atkp8mklOh0" | yt_audio