#!/usr/bin/env bash ############# # Variables # ############# # Define formatting variables fb="$(tput bold)" ; readonly fb fr="$(tput sgr0)" ; readonly fr # Define name regular expression name_regex='[^a-zA-Z0-9]' ; readonly name_regex # Create required commands array req_cmds=( 'wkhtmltopdf' 'xclip' ) ; readonly req_cmds o_loc="" ; readonly o_loc # Set output location for PDF files pdf_app='' ; readonly pdf_app # Set PDF viewer application # Create required variables array required_vars=( 'o_loc' 'pdf_app' ) ; readonly required_vars ############# # Functions # ############# display_usage() { local help_msg # Define local variable help_msg="Usage: '${0}' Purpose: Save web pages to PDF files. Requires: wkhtmltopdf html to pdf converter xclip command line interface to X selections (clipboard) Variables to set: o_loc Output location for the PDF files. pdf_app Application to view output PDF files in." echo "${help_msg}" } # Verify string is valid URL val_url() { local to_test 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 "${?}" } # Parse arguments parse_args() { local parsed_args inv_ents parsed_args="$(getopt \ -n "${0##*/}" \ -o h \ --long help \ -- "${@}")" # Check for invalid entries inv_ents="${?}" ; readonly inv_ents 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 ;; '--') ## End of options shift break ;; esac done } # Run initialization checks run_init_cks() { local \ err_msg \ mis_cmds \ req_cmd \ unset_vars \ required_var # Verify script is being run from a desktop environment if ! [[ "${XDG_CURRENT_DESKTOP}" ]]; then err_msg='\nA desktop environment must be available to ' err_msg+='use this script.' echo -e "${err_msg}" 1>&2 exit 1 fi # 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 # Create unset variables array declare -a unset_vars # Verify that required variables are set for required_var in "${required_vars[@]}"; do if ! [[ "${!required_var}" ]]; then unset_vars+=("${required_var}") fi done # Exit script if variables are not set if [[ "${unset_vars[*]}" ]]; then err_msg='\nSet the following variable(s) before ' err_msg+='running the script again:' echo -e "${err_msg}\n${fb}${unset_vars[*]}${fr}" 1>&2 exit 1 fi } # Sanitize name clean_name() { local cleaned # Replace most non-alphanumeric characters with underscores cleaned="${1//${name_regex}/_}" # Squeeze underscores and lowercase name cleaned="$(echo -n "${cleaned}" | tr -s '_' | tr '[:upper:]' '[:lower:]')" echo "${cleaned}" } # Define starting point for execution of the program main() { parse_args "${@}" run_init_cks # Prompt for input, save to variable echo '' read -p 'Enter PDF filename and URL (q to quit): ' -r filename url # Check for valid selection until [[ "${filename}" == 'q' || "${url}" == 'q' ]]; do filename="$(clean_name "${filename}")" # Sanitize filename while true; do pass_or_fail="$(val_url "${url}")" if [[ "${url}" == 'q' ]]; then exit 0 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 read -p 'Enter URL (q to quit): ' -r url fi done # Try to generate and open PDF if timeout -k 30 30 wkhtmltopdf "${url}" "${o_loc}/${filename}.pdf" \ > '/dev/null' 2>&1; then timeout 5 "${pdf_app}" "${o_loc}/${filename}.pdf" > \ '/dev/null' 2>&1 else # Set and display error message, place clean filename on clipboard err_msg="\n${fb}wkhtmltopdf timed out. Try manually " err_msg+="saving the page.${fr}" echo -e "${err_msg}" 1>&2 && echo "${filename}" | xclip -selection c fi echo '' read -p 'Enter PDF filename and URL (q to quit): ' -r filename url done } ########### # Program # ########### main "${@}" # Start program exit 0 # Exit script with successful exit status