Skip to content

Instantly share code, notes, and snippets.

@PatOConnor43
Last active December 6, 2020 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PatOConnor43/c53fe1f52a4a658dc5d1b160ab4197dc to your computer and use it in GitHub Desktop.
Save PatOConnor43/c53fe1f52a4a658dc5d1b160ab4197dc to your computer and use it in GitHub Desktop.
#!/bin/bash
#================================================================
# HEADER
#================================================================
#% SYNOPSIS
#+ ${SCRIPT_NAME} [-h] channelId
#%
#% DESCRIPTION
#% Download the latest audio from a channel. The channelId can be found in
#% the url for the channel or in the channel's html. It should start with "UC".
#% Setting YOUTUBE_API_KEY is required in order to use this script.
#%
#%
#% OPTIONS
#% -h, --help Print this help
#% -v, --version Print script information
#%
#% EXAMPLES
#% ${SCRIPT_NAME} UCVI66VMGYg0dLPEkWPrCkBw
#%
#================================================================
#- IMPLEMENTATION
#- version ${SCRIPT_NAME} 0.0.1
#- author Pat O'Connor
#- license MIT
#-
#================================================================
# DEBUG OPTION
# set -n # Uncomment to check your syntax, without execution.
# set -x # Uncomment to debug this shell script
set -e # stop if an error occurs
#
#================================================================
# END_OF_HEADER
#================================================================
#== needed variables ==#
SCRIPT_HEADSIZE=$(head -200 ${0} |grep -n "^# END_OF_HEADER" | cut -f1 -d:)
SCRIPT_NAME="$(basename ${0})"
#== usage functions ==#
usage() { printf "Usage: "; head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#+" | sed -e "s/^#+[ ]*//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" ; }
usagefull() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#[%+-]" | sed -e "s/^#[%+-]//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g" ; }
scriptinfo() { head -${SCRIPT_HEADSIZE:-99} ${0} | grep -e "^#-" | sed -e "s/^#-//g" -e "s/\${SCRIPT_NAME}/${SCRIPT_NAME}/g"; }
check_dependencies() {
for dep in "ffmpeg" "jq" "sqlite3" "youtube-dl"; do
if ! command -v ${dep} &> /dev/null; then
echo "ERROR: ${dep} required in order to proceed."
exit 8
fi
done
}
init_sqlite() {
sqlite3 monocular.db <<EOL
CREATE TABLE IF NOT EXISTS video (
id varchar(32) PRIMARY KEY,
title text
);
EOL
}
select_video_id() {
echo "SELECT id FROM video WHERE id='$1'" | sqlite3 monocular.db
}
insert_video() {
echo "INSERT INTO video (id, title) VALUES ('$1', '$2')" | sqlite3 monocular.db
}
# Define list of arguments expected in the input
optstring=":hv"
while getopts ${optstring} arg; do
case "${arg}" in
h) usagefull; exit 0;;
v) scriptinfo; exit 0;;
?)
echo "ERROR: Invalid option: -${OPTARG}."
echo
usagefull
exit 1
;;
esac
done
if test "$1" = ""; then
echo "ERROR: Missing channelId"
usagefull
exit 2
fi
if test "${YOUTUBE_API_KEY}" = ""; then
echo "ERROR: YOUTUBE_API_KEY is not set. Please set this env variable."
exit 4
fi
main() {
local channelId="$1"
local limit=10
local url="https://www.googleapis.com/youtube/v3/search?key=${YOUTUBE_API_KEY}&channelId=${channelId}&maxResults=${limit}&order=date&type=video&videoDuration=long&part=snippet"
# results should come back in the for of '<videoId> <title>' this format
# should allow us to capture each field with cut
mapfile -t tuples <<<"$(curl -s ${url} | jq -r '.items[] | [.id.videoId, .snippet.title] | @sh' | xargs -n 2)"
init_sqlite
i=0
while [ "$i" -ne $limit ]
do
local id=$(echo "${tuples[$i]}" | cut -d ' ' -f1)
if test "${id}" = ""; then
echo "ERROR: There was an issue fetching youtube results."
exit 16
fi
local title=$(echo "${tuples[$i]}" | cut -d ' ' -f2-)
if test "$(select_video_id ${id})" = ""; then
youtube-dl -f bestaudio --extract-audio --audio-format mp3 --embed-thumbnail -o "%(title)s.%(ext)s" "https://www.youtube.com/watch?v=${id}"
insert_video "$id" "$title"
fi
i=$((i + 1))
done
}
check_dependencies
main "$1"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment