TITLE: Bash script to download audio from Youtube
DATE: 2024-06-26
AUTHOR: John L. Godlee
====================================================================


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.

 [yt-dlp]: https://github.com/yt-dlp/yt-dlp
 [ytfzf]: https://ytfzf.github.io/

   #!/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