Skip to content

Instantly share code, notes, and snippets.

@jazz-it
Last active October 23, 2021 17:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jazz-it/b981fa7f3f81089a37257e366c1ef581 to your computer and use it in GitHub Desktop.
Save jazz-it/b981fa7f3f81089a37257e366c1ef581 to your computer and use it in GitHub Desktop.
Download a YouTube Playlist, extract audio in best quality with youtube-dl and normalize volume with r128gain (ReplayGain 2.0)
#!/bin/bash
# helper function parameters: 0 or empty = print only, 1 = rename files!
renamemp3() {
local s="${1:-0}"
for f in *.mp3; do
if [[ "$f" == *[\"\`]* ]]
then
filename=${f%.*}
filename=${filename//\"}
filename=${filename//\`}
extension=${f##*.}
[ "$s" == 0 ] && echo -e "$f 🠪 ${LIGHTGREEN}$filename${NC}.$extension" && i=$((i+1))
[ "$s" == 1 ] && mv -v "$f" "$filename.$extension"
fi
done
}
CYAN='\e[0;36m'
RED='\e[0;31m'
LIGHTGREEN='\e[1;32m'
YELLOW='\e[0;33m'
NC='\e[0m' # No Color
history=".youtuberc"
defaultkey=""
dateafter=""
noplaylist=0
echo -e "Full URL format: ${CYAN}https://www.youtube.com/playlist?list=${RED}PLAYLIST${NC}"
default=""
echo -ne "YouTube playlist ID (${RED}PLAYLIST${NC} argument only!)"
if [[ -f "$history" ]]
then
defaultkey=$(awk '{print $1; exit}' $history)
fi
if [ "$defaultkey" == "playlist" ]
then
default=$(awk '{print $2; exit}' $history)
read -p " [$(echo -e "${YELLOW}$default${NC}")]: " PLAYLIST
PLAYLIST=${PLAYLIST:-"$default"}
else
read -p ": " PLAYLIST
noplaylist=1
fi
URL="https://www.youtube.com/playlist?list=$PLAYLIST"
if wget -q --method=HEAD "$URL";
then
echo -e "[${LIGHTGREEN}OK${NC}] The playlist is reachable!"
else
exit 0
fi
if [[ ! -f "$history" ]]
then
echo -e "[${YELLOW}NOTE${NC}] $history does not exist."
echo
echo -n "Would you like to download the entire playlist? [Y/n] "
read input1
case $input1 in
[yY][eE][sS]|[yY]|"")
echo -e "[${LIGHTGREEN}OK${NC}] Downloading entire playlist..."
;;
[nN])
echo -ne "Upload date of the newest item within the playlist (${RED}dateafter${NC})? (eg. YYYYMMDD, now-1week) "
read dateafter
dateafter="--dateafter $dateafter"
echo -e "[${LIGHTGREEN}OK${NC}] Processing a partial download..."
;;
esac
else
echo -e "[${LIGHTGREEN}OK${NC}] Updating your download history file with new items only..."
fi
if [ "$dateafter" == "" ]
then
youtube-dl "$URL" \
--quiet \
--ignore-errors \
--extract-audio \
--output '%(playlist_index)s - %(title)s.%(ext)s' \
--metadata-from-title "%(artist)s - %(title)s" \
--audio-quality 0 \
--audio-format mp3 \
--embed-thumbnail \
--download-archive $history \
--exec 'echo && r128gain {} > /dev/null'
else
youtube-dl "$URL" \
--quiet \
--ignore-errors \
--extract-audio \
--output '%(playlist_index)s - %(title)s.%(ext)s' \
--metadata-from-title "%(artist)s - %(title)s" \
--audio-quality 0 \
--audio-format mp3 \
--embed-thumbnail \
$dateafter \
--download-archive $history \
--exec 'echo && r128gain {} > /dev/null'
fi
if [ $noplaylist == 1 ]
then
# Add the playlist ID to the first line of the dowload history file.
sed -i "1s/^/playlist $PLAYLIST\n/" "$history"
fi
echo
i=0
renamemp3 0
echo
fsize=$(du -d 0 -Sh . | head -n 1 | tr -s ' ' | cut -d$'\t' -f1)
ls -p *.mp3 | grep -v / | echo -e "There are ${CYAN}$(wc -l)${NC} (${CYAN}${fsize}${NC}) songs available."
if [ "$i" -gt 0 ]
then
echo -n "Rename all files automatically? [Y/n] "
read input1
case $input1 in
[yY][eE][sS]|[yY]|"")
renamemp3 1
echo
echo -e "We're all set. Enjoy your music! 😊"
echo
;;
[nN])
echo "Renaming files omitted."
echo "Done."
;;
esac
fi
@jazz-it
Copy link
Author

jazz-it commented Jun 8, 2020

Great thing about this script is when frequently used for the following scenario:

  1. You initially download your playlist within the empty folder by running this script and entering the playlist's ID
  2. After some time, you'll probably update your playlist on YouTube with many new items and so you'd like to download the new items.
  3. All you have to do is to run the script again and it will remember the playlist's ID by default, so you don't need to copy/paste it again (just hit Enter). It will also download only new items that were not downloaded with the previous run of the script.
  4. Unlike other scripts, this script uses r128gain, not mp3gain. With r128gain you could benefit from the new ReplayGain 2.0 (ReplayGain 2.0 targets the same loudness as ReplayGain 1.0 specification, but utilizes the improved ITU BS.1770 algorithm for measuring original tracks. mp3gain is based on ReplayGain 1.0 specification.)

NOTE: Always use one folder for a single playlist i.e. if you have 5 playlists, you should use 5 different folders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment