#!/usr/bin/env bash ############# # Variables # ############# # Define formatting variables fb="$(tput bold)" ; readonly fb ft="$(tput sitm)" ; readonly ft fr="$(tput sgr0)" ; readonly fr # Create required commands array req_cmds=('ffmpeg' 'yt-dlp') ; readonly req_cmds log_root='/tmp' ; readonly log_root # Set log root directory script_name="${0##/*/}" # Obtain script name # Remove suffix from script name script_name="${script_name%.*}" ; readonly script_name t_stamp="$(date +'%s')" ; readonly t_stamp # Create timestamp using UNIX epoch yt_dlp_opts='-f b ' # Initialize yt-dlp options string o_mode='Video' # Initialize output mode sub_lang='en-US' # Initialize subtitle language ############# # Functions # ############# display_usage() { help_msg="Usage: ${0} [ex_option]... Purpose: Download audio/video content with yt-dlp. A log is saved in the /tmp/${script_name}/ directory. Options: -a, --audio Download audio content. -g, --greatest-quality Download greatest quality content. -s, --subtitles Embed subtitles into video content. Requires: ffmpeg ffmpeg video converter yt-dlp A youtube-dl fork with additional features and patches" echo "${help_msg}" } # Verify string is valid URL val_url() { local to_test url_regex # Define local variables to_test="${1}" url_regex='https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.' url_regex+='[a-zA-Z0-9()]{1,18}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)' [[ "${to_test}" =~ ${url_regex} ]] ; echo "${?}" } # Set URL set_url() { local prompt pass_or_fail err_msg prompt="${1}" while true; do # Prompt for input, save to variable read -p "${prompt}" -r url # Validate input pass_or_fail="$(val_url "${url}")" if [[ "${url}" == 'q' ]]; then if [[ -s "${log_path}" ]]; then ish_msg='\nPotential issue encountered.' ish_msg+="\nView ${fb}${log_path}${fr} for more information." echo -e "${ish_msg}" fi exit 0 # Exit script with successful exit status elif [[ "${pass_or_fail}" -eq 0 ]]; then break else err_msg='\nInvalid URL. Try again or enter q to quit.\n' echo -e "${err_msg}" 1>&2 fi done } # Handle a SIGINT signal hndl_sigint() { echo -e '\n\nSIGINT or Ctrl+c detected. Exiting gracefully.' exit 0 } # Initialize logging init_logging() { # If script log directory does not exist, create it if ! [[ -d "${log_root}/${script_name}" ]]; then mkdir -p "${log_root}/${script_name}" fi # Define log file path log_path="${log_root}/${script_name}/${t_stamp}_${script_name}.log" } # Make yt-dlp options string adjustments adj_yt_dlp_opts() { if [[ "${a_on}" == 'true' ]]; then if [[ "${g_on}" == 'true' ]]; then yt_dlp_opts='-f ba[ext=m4a] ' o_mode='Greatest Quality Audio' else yt_dlp_opts='-f ba ' o_mode='Audio' fi else if [[ "${g_on}" == 'true' ]]; then yt_dlp_opts='-f bv[ext=mp4]+ba[ext=m4a]/b[ext=mp4]/b ' o_mode='Greatest Quality Video' fi if [[ "${s_on}" == 'true' ]]; then yt_dlp_opts+="--embed-subs --sub-langs ${sub_lang} " o_mode+=' (With Embedded Subtitles)' fi fi } # Define starting point for execution of the program main() { # Parse arguments parsed_args="$(getopt \ -n "${0##*/}" \ -o hags \ --long help,audio,greatest-quality,subtitles \ -- "${@}")" inv_ents="${?}" # Check for invalid entries if [[ "${inv_ents}" -ne 0 ]]; then echo '' display_usage exit 1 fi # Set positional parameters using parsed argument string eval set -- "${parsed_args}" # Evaluate options while true; do case "${1}" in '-h' | '--help') display_usage exit 0 ;; '-a' | '--audio') a_on='true' shift ;; '-g' | '--greatest-quality') g_on='true' shift ;; '-s' | '--subtitles') s_on='true' shift ;; '--') ## End of options shift break ;; esac done # Create missing commands array declare -a mis_cmds # Verify that required commands are installed for req_cmd in "${req_cmds[@]}"; do if ! command -v "${req_cmd}" > '/dev/null' 2>&1; then mis_cmds+=("${req_cmd}") fi done # Exit script if commands are missing if [[ "${mis_cmds[*]}" ]]; then err_msg='\nInstall the following command(s) before ' err_msg+='running the script again:' echo -e "${err_msg}\n${fb}${mis_cmds[*]}${fr}" 1>&2 exit 1 fi trap hndl_sigint SIGINT # Capture SIGINT signal init_logging # Initialize logging adj_yt_dlp_opts # Adjust yt-dlp options hdr="\nOutput Mode: ${ft}${o_mode}${fr}" hdr_len="${#hdr}" echo -e "${hdr}" yes '~' | head -n "$(( hdr_len - 12 ))" | tr -d '\n' && echo '' prompt='Enter URL (q to quit): ' while true; do set_url "${prompt}" yt-dlp ${yt_dlp_opts}-q "${url}" 2>> "${log_path}" & done } ########### # Program # ########### main "${@}" # Start program