Skip to content

Instantly share code, notes, and snippets.

@tildelowengrimm
Last active April 18, 2020 18:26
Show Gist options
  • Save tildelowengrimm/e3e5d2b6e0765155db0647d77895e984 to your computer and use it in GitHub Desktop.
Save tildelowengrimm/e3e5d2b6e0765155db0647d77895e984 to your computer and use it in GitHub Desktop.
Archive Synthwave Mixes from Astral Throb
## Download the excellent synthwave mixes created by Astral Throb, split the
## audio into individual songs, and label them with metadata, including
## excellent cover art. Ideal for offline listening.
## Dependencies:
## - youtube-dl
## - jq
## - ffmpeg
## - eyeD3
## TODO
## 1. Catch errors where YouTube-DL fails to grab the initial playlist.
## 2. Don't allow the infofile, album, title, &c to be blank when parsing —
## treat as an error and skip that album while downloading.
## 3. If there have been errors, don't try to move the final file.
ALBUM_ARTIST="Astral Throb"
GENRE="Electronic"
ARTIST_HOMEPAGE="https://www.youtube.com/channel/UCpbH_7H71IPKq4eH7CD5spg"
PLAYLIST_URL="https://www.youtube.com/playlist?list=UUpbH_7H71IPKq4eH7CD5spg"
TARGET_DIR="$HOME/media/music/library/$ALBUM_ARTIST"
ARTIST_LOGO="$TARGET_DIR/astral-throb.jpg" # This file is not created, it should already exist in the target directory
## Colors for output
RED='\033[0;31m'
LIGHT_PURPLE='\033[1;35m'
NC='\033[0m' # No Color
echo "Archiving $ALBUM_ARTIST to ${LIGHT_PURPLE}$TARGET_DIR${NC}."
## Download and parse the list of URLs in the playlist
echo "Fetching work queue…"
PLAYLIST_LIST=$(youtube-dl --dump-json --flat-playlist "$PLAYLIST_URL" | jq -r '.id' | sed 's_^_https://youtube.com/v/_')
#PLAYLIST_LIST="https://www.youtube.com/watch?v=isIj3tuQTDY&t=2015s" # For testing with individual albums which encounter errors
for URL in $PLAYLIST_LIST
do
## Skip SIMULAKRUM LAB, which isn't actually a mix
[[ "$URL" == "https://youtube.com/v/6DaQbh45OxI" ]] && echo "Skipping SIMULAKRUM LAB…" && continue
## Download the metadata file for the album
INFOFILE=$(youtube-dl --skip-download --write-info-json "$URL" | grep "Writing video description metadata as JSON to" | cut -c 55- ) #; echo "INFOFILE: $INFOFILE"
[[ "$INFOFILE" == "" ]] && echo "Metadata download failed, skipping…" && continue
PREFIX=$(echo "$INFOFILE" | rev | cut -c 11- | rev)
## Parse basic album metadata from the file
ALBUM_TITLE=$(cat "$INFOFILE" | jq .fulltitle | cut -d ' ' -f 1 | cut -c 2-) #; echo "ALBUM_TITLE: $ALBUM_TITLE" # The short all-caps title
ALBUM_YEAR=$(cat "$INFOFILE" | jq ".upload_date" | cut -c 2-5) #; echo "ALBUM_YEAR: $ALBUM_YEAR" # Four-digit album year
ALBUM_DIRECTORY="$ALBUM_ARTIST - $ALBUM_TITLE ($ALBUM_YEAR)" #; echo "ALBUM_DIRECTORY: $ALBUM_DIRECTORY"
## Check to see if this album already existst in the target directory, otherwise create it here
if [ -d "$TARGET_DIR/$ALBUM_DIRECTORY" ]
then
rm "$INFOFILE"
echo "$ALBUM_TITLE has already been downloaded."
rm "$PREFIX"*
continue
else
mkdir "$ALBUM_DIRECTORY"
fi
ALBUM_FULLTITLE=$(cat "$INFOFILE" | jq --raw-output .fulltitle)
echo "Processing $ALBUM_FULLTITLE …"
## Download the audio and the thumbnail from YouTube
echo " Downloading $ALBUM_TITLE combined mix & art…"
ALBUM_AUDIO=$(youtube-dl --format bestaudio --extract-audio --write-thumbnail "$URL" | grep Destination | grep ffmpeg | cut -c 23-)
## Parse the remaining album metadata
RELEASE_DATE=$(cat "$INFOFILE" | jq ".upload_date" | cut -c 2-5)-$(cat "$INFOFILE" | jq ".upload_date" | cut -c 6-7)-$(cat "$INFOFILE" | jq ".upload_date" | cut -c 8-9)
TRACKS=$(cat "$INFOFILE" | jq ".chapters | length")
## Move the album art
echo " Exporting $ALBUM_TITLE cover art…"
ALBUM_ART="$ALBUM_DIRECTORY/$ALBUM_FULLTITLE.jpg"
mv "$PREFIX.jpg" "$ALBUM_ART"
## Extract the individual audio files from the combined album mix
for INDEX in $(seq 1 $TRACKS)
do
## Parse this audio track's metadata
TRACK_ARTIST="$(cat "$INFOFILE" | jq --raw-output ".chapters["$[$INDEX-1]"].title" | cut -d - -f 1 | rev | cut -c 2- | rev | sed 's/^\///;s/\// /g' )"
TRACK_TITLE="$(cat "$INFOFILE" | jq --raw-output ".chapters["$[$INDEX-1]"].title" | cut -d - -f 2 | cut -c 2- | sed 's/^\///;s/\// /g' )"
TRACK_START="$(cat "$INFOFILE" | jq ".chapters["$[$INDEX-1]"].start_time")"
TRACK_END="$(cat "$INFOFILE" | jq ".chapters["$[$INDEX-1]"].end_time")"
## Single-digit track numbers are zero-prefixed in the filename
if (( $INDEX < 10 )) ; then
FILENAME="$ALBUM_DIRECTORY/0$INDEX. $TRACK_ARTIST - $TRACK_TITLE.mp3"
else
FILENAME="$ALBUM_DIRECTORY/$INDEX. $TRACK_ARTIST - $TRACK_TITLE.mp3"
fi
## The heavy lifting of audio extraction for this track
echo " Extracting $ALBUM_TITLE track $INDEX/$TRACKS $TRACK_ARTIST - $TRACK_TITLE …"
ffmpeg -loglevel warning -y -i "$ALBUM_AUDIO" -ss "$TRACK_START" -to "$TRACK_END" "$FILENAME" && echo " Track extraction successful." || echo " ${RED}Track extraction failed!${NC}"
## Write the metadata to the file
echo " Writing tack metadata for $TRACK_ARTIST - $TRACK_TITLE …"
eyeD3 \
--artist "$TRACK_ARTIST" \
--album "$ALBUM_FULLTITLE" \
--album-artist "$ALBUM_ARTIST" \
--title "$TRACK_TITLE" \
--release-year "$ALBUM_YEAR" \
--track "$INDEX" \
--track-total "$TRACKS" \
--genre "$GENRE" \
--release-date "$RELEASE_DATE" \
--url-frame "WOAS:$URL" \
--url-frame "WOAR:$ARTIST_HOMEPAGE" \
--add-image "$ARTIST_LOGO:BAND_LOGO" \
--add-image "$ALBUM_ART:FRONT_COVER" \
"$FILENAME" >/dev/null
done
## Move the complete albim to the target directory
echo " Extraction complete. Moving $ALBUM_TITLE to library…"
rsync --recursive --remove-source-files --compress "$ALBUM_DIRECTORY" "$TARGET_DIR"
## Remove the original audio, thumbnail, and metadata file
echo " $ALBUM_TITLE archived, cleaning up…"
rm "$PREFIX"*
rm -r "$ALBUM_DIRECTORY"
done
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment