#!/bin/bash - #=============================================================================== # # FILE: past_upload # # USAGE: ./past_upload [-h] [-r] [-v] [-d {0|1}] start [count] # # DESCRIPTION: Run the commands necessary to upload a batch of older HPR # shows to archive.org # # OPTIONS: --- # REQUIREMENTS: --- # BUGS: --- # NOTES: --- # AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com # VERSION: 0.0.12 # CREATED: 2021-04-17 22:14:16 # REVISION: 2022-07-07 16:17:41 # #=============================================================================== set -o nounset # Treat unset variables as an error SCRIPT=${0##*/} # DIR=${0%/*} VERSION="0.0.12" STDOUT="/dev/fd/2" # # Select the appropriate working directory # case $(hostname) in i7-desktop) BASEDIR="$HOME/HPR/InternetArchive" UPLOAD="$BASEDIR/uploads" ;; borg) BASEDIR="$HOME/IA" UPLOAD="/data/IA/uploads" ;; *) echo "Wrong host!" exit 1 ;; esac cd "$BASEDIR" || exit 1 # # Load library functions # LIB="$HOME/bin/function_lib.sh" [ -e "$LIB" ] || { echo "Unable to source functions"; exit; } # shellcheck disable=SC1090 source "$LIB" # # Log file # LOGS="$BASEDIR/logs" LOGFILE="$LOGS/$SCRIPT.log" # # Make temporary files and set traps to delete them # TMP1=$(mktemp) || { echo "$SCRIPT: creation of temporary file failed!"; exit 1; } trap 'cleanup_temp $TMP1' SIGHUP SIGINT SIGPIPE SIGTERM EXIT #=== FUNCTION ================================================================ # NAME: _verbose # DESCRIPTION: Writes a message in verbose mode # PARAMETERS: $1 message # RETURNS: Nothing #=============================================================================== _verbose () { local msg=${1:-} [[ $VERBOSE -eq 1 ]] && echo "$msg" } #=== FUNCTION ================================================================ # NAME: _usage # DESCRIPTION: Reports usage; always exits the script after doing so # PARAMETERS: 1 - the integer to pass to the 'exit' command # RETURNS: Nothing #=============================================================================== _usage () { local -i result=${1:-0} cat >$STDOUT <<-endusage ${SCRIPT} - version: ${VERSION} Usage: ./${SCRIPT} [-h] [-r] [-v] [-d {0|1}] start [count] Generates the necessary metadata and script and uses them to upload HPR audio and other show-related files held on the VPS to the Internet Archive. This script is similar to 'weekly_upload' but it's for dealing with older shows where we only have the MP3 audio. Options: -h Print this help -v Run in verbose mode where more information is reported -d 0|1 Dry run: -d 1 (the default) runs the script in dry-run mode where nothing is changed but the actions that will be taken are reported; -d 0 turns off dry-run mode and the actions will be carried out. -F Force an upload even if the items are already on the IA. Use with *GREAT* caution! -m Update the item's metadata from the file generated for (re-)uploads. This ensures that any changes to the notes, summary, tags, etc are propagated. This does not happen by default, but shows with assets are always updated this way. -r Run in 'remote' mode, using the live database over an (already established) SSH tunnel. Default is to run against the local database. -Y Answer 'Y' to the confirmation question (really don't ask at all) Arguments: start the starting show number to be uploaded count (optional, default 1) the number of shows to be uploaded; not allowed to exceed 20 Notes: 1. When running on 'borg' the method used is to run in faux 'local' mode. This means we have an open tunnel to the HPR server (mostly left open) and the default file .hpr_db.cfg points to the live database via this tunnel. So we do not use the -r option here. This is a bit of a hack! Sorry! TODO: Needs fix! 2. There are potential problems when a show has no tags which haven't been fully resolved. The make_metadata script fails in default mode when it finds such a show, but this (weekly_upload) script can continue on and run the generated script which uploads the source audio files. This can mean the IA items end up as books! In this mode the description is not stored and so there are no show notes. endusage exit "$result" } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # Prerequisites # jq=$(command -v jq) [ -z "$jq" ] && { echo "Needs the 'jq' JSON filter"; exit 1; } ia=$(command -v ia) [ -z "$ia" ] && { echo "Needs the 'ia' Internet Archive script"; exit 1; } transfer_tags=$(command -v transfer_tags) [ -z "$transfer_tags" ] && { echo "Needs the 'transfer_tags' script"; exit 1; } tunnel_is_open=$(command -v tunnel_is_open) [ -z "$tunnel_is_open" ] && { echo "Needs the 'tunnel_is_open' script"; exit 1; } [ -e "$BASEDIR/transcode" ] || { echo "Needs the 'transcode' script" exit 1 } [ -e "$BASEDIR/make_metadata" ] || { echo "Needs the 'make_metadata' script" exit 1 } # # Constant # RETRIES=5 # # Check the tunnel is open # if ! tunnel_is_open; then echo "Open the tunnel before running this script (open_tunnel)" exit 1 fi #------------------------------------------------------------------------------- # Process options #------------------------------------------------------------------------------- while getopts :d:FhmrvY opt do case "${opt}" in d) DRYRUN=$OPTARG;; F) FORCE=1;; h) _usage 1;; m) METADATA=1;; r) REMOTE=1;; v) VERBOSE=1;; Y) YES=1;; *) _usage 1;; esac done shift $((OPTIND - 1)) # # Check choices and set defaults # DRYRUN=${DRYRUN:-1} if [[ $DRYRUN -ne 0 && $DRYRUN -ne 1 ]]; then echo "** Use '-d 0' or '-d 1'" _usage 1 fi FORCE=${FORCE:-0} METADATA=${METADATA:-0} YES=${YES:-0} VERBOSE=${VERBOSE:-0} REMOTE=${REMOTE:-0} if [[ $REMOTE -eq 0 ]]; then dbconfig="$BASEDIR/.hpr_db.cfg" _verbose "Local database mode" else dbconfig="$BASEDIR/.hpr_livedb.cfg" _verbose "Remote database mode" fi # # Check argument count # if [[ ! ( $# -eq 1 || $# -eq 2 ) ]]; then echo "Wrong number of arguments" _usage 1 fi # # Validate arguments # for arg; do if [[ ! $arg =~ ^[0-9]{1,4}$ ]]; then echo "Invalid number: $arg" echo "Use a plain number" exit 1 fi done # # Set variables for the range of shows # start=$1 count=${2:-1} if [[ $count -gt 20 ]]; then echo "Can't process more than 20 shows at a time" exit 1 fi ((end = start + count - 1)) [[ $DRYRUN -eq 1 ]] && _verbose "Dry run mode" if [[ $VERBOSE -eq 1 ]]; then echo "Processing $count $(ngettext show shows "$count") from $start" else echo "${start}..${end}" fi # # Log the start of this run # [[ $DRYRUN -eq 0 ]] && \ echo "$(date +%Y%m%d%H%M%S) Processing ${start}..${end} (v$VERSION)" >> "$LOGFILE" # # Store the show numbers in an array. We need 'eval' to substitute `$start' # and '$end' for the 'printf'. # declare -a shows mapfile -t shows < <(eval "printf '%04d\n' {$start..$end}") # # Walk the array and delete elements that are already on the IA # if [[ $FORCE -eq 1 ]]; then _verbose 'Not checking for shows on archive.org; forcing!' [[ $DRYRUN -eq 0 ]] && echo "$(date +%Y%m%d%H%M%S) Forcing an update (-F)" >> "$LOGFILE" else _verbose 'Checking for shows on archive.org' [[ $DRYRUN -eq 0 ]] && echo "$(date +%Y%m%d%H%M%S) Checking archive.org" >> "$LOGFILE" i=0 for item in "${shows[@]}"; do if ia list "hpr$item" > /dev/null 2>&1; then _verbose "Found hpr$item on archive.org" unset "shows[$i]" fi ((i++)) done fi # # Stop if there's nothing to do # if [[ ${#shows[@]} -eq 0 ]]; then echo "Nothing to do; nominated show(s) are currently on archive.org" [[ $DRYRUN -eq 0 ]] && echo "$(date +%Y%m%d%H%M%S) Nothing to do" >> "$LOGFILE" exit 1 else _verbose "There $(ngettext 'is 1 show' "are ${#shows[@]} shows" "${#shows[@]}") to process" fi # # Find which audio needs to be downloaded and go get it # _verbose "Downloading missing audio..." if [[ $DRYRUN -eq 1 ]]; then echo "Would have attempted to download ${#shows[@]} $(ngettext show shows "${#shows[@]}") (dry run)" else for item in "${shows[@]}"; do if [[ ! -e $UPLOAD/hpr$item.mp3 ]]; then echo "Downloading hpr$item.mp3" wget -q "http://hackerpublicradio.org/local/hpr$item.mp3" \ -O "$UPLOAD/hpr$item.mp3" _verbose "Downloaded $UPLOAD/hpr$item.mp3" else _verbose "$UPLOAD/hpr$item.mp3 already exists" fi done fi # # Transcode the audio as needed # _verbose "Transcoding missing audio..." if [[ $DRYRUN -eq 1 ]]; then echo "Would have transcoded ${#shows[@]} $(ngettext show shows "${#shows[@]}") (dry run)" else [[ $DRYRUN -eq 0 ]] && \ echo "$(date +%Y%m%d%H%M%S) Transcoding ${#shows[@]} $(ngettext show shows "${#shows[@]}")" >> "$LOGFILE" for item in "${shows[@]}"; do if [[ $VERBOSE -eq 1 ]]; then ./transcode -v "$UPLOAD/hpr$item.mp3" else ./transcode "$UPLOAD/hpr$item.mp3" fi done fi # # We now have a list of shows in the right state to be uploaded, so we can do # what's necessary # _verbose "Uploading $(ngettext show shows "${#shows[@]}")..." # # Define files for make_metadata. For aesthetic reasons don't use '1-1' when # there's only one show! # if [[ $start -eq $end ]]; then printf -v metadata 'metadata_%04d.csv' "$start" printf -v script 'script_%04d.sh' "$start" else printf -v metadata 'metadata_%04d-%04d.csv' "$start" "$end" printf -v script 'script_%04d-%04d.sh' "$start" "$end" fi # # Check on the dry-run choice # if [[ $DRYRUN -eq 1 ]]; then echo "Dry run: Would have uploaded $count $(ngettext show shows "$count") from $start" echo "Dry run: Would have created $metadata and $script" echo "Dry run: Would have uploaded $metadata and run $script" echo "Dry run: Would have used $dbconfig" echo -n "Dry run: Would have done metadata updates for " if [[ $METADATA -eq 0 ]]; then echo "shows with assets" else echo "all shows" fi else # # Really do the upload # if [[ $start -eq $end ]]; then echo "Uploading $start" else echo "Uploading $start to $end inclusive" fi # # Implement the -Y (override) option # if [[ $YES -eq 1 ]]; then confirmed=1 else echo "$(date +%Y%m%d%H%M%S) Waiting for confirmation" >> "$LOGFILE" if yes_no "OK to continue? %s " "N"; then confirmed=1 else confirmed=0 fi fi #--------------------------------------------------------------------------- # Do the work #--------------------------------------------------------------------------- if [[ $confirmed -eq 1 ]]; then # shellcheck disable=2086 { # # Make the metadata # _verbose "Running make_metadata" $BASEDIR/make_metadata -dbconf=${dbconfig} \ -from=$start -count=$count \ -verb -out -script -a_count=$TMP1 RES=$? # # If it all went OK perform the uploads, otherwise report the # problem(s) # if [[ $RES -eq 0 ]]; then _verbose "Uploading audio and any assets" ia upload --retries=$RETRIES --spreadsheet=${metadata} \ -H x-archive-keep-old-version:0 && \ [ -e $script ] && ./${script} echo "$(date +%Y%m%d%H%M%S) Uploaded shows" >> "$LOGFILE" else echo "Upload aborted due to errors" echo "$(date +%Y%m%d%H%M%S) Upload failed due to errors" >> "$LOGFILE" exit 1 fi # # Update metadata for all shows if requested # if [[ $METADATA -eq 1 ]]; then _verbose "Uploading changed metadata" ia metadata --spreadsheet=${metadata} echo "$(date +%Y%m%d%H%M%S) Metadata uploaded for all shows" >> "$LOGFILE" else # # We aren't updating metadata for all, but if any shows had # assets we need to do metadata updates. The show details are # in the temporary file $TMP1 # if [[ -s $TMP1 ]]; then _verbose "Refreshing metadata for shows with assets" declare -a mshows mapfile -t mshows < <(cut -f1 -d' ' $TMP1 | sed -e 's/^hpr//' | sort) mlist="${mshows[*]}" if [[ ${#mshows[@]} -eq 1 ]]; then printf -v metadata 'meta_metadata_%04d.csv' "${mshows[0]}" else printf -v metadata 'meta_metadata_%04d-%04d.csv' "${mshows[0]}" "${mshows[-1]}" fi _verbose "Regenerating metadata" $BASEDIR/make_metadata -dbconf=${dbconfig} -list="${mlist/ /,}" \ -out=${metadata} -meta -noassets -verb RES=$? if [[ $RES -eq 0 ]]; then _verbose "Uploading new metadata" ia metadata --spreadsheet=${metadata} echo "$(date +%Y%m%d%H%M%S) Metadata uploaded for eligible shows" >> "$LOGFILE" else echo "Metadata update aborted due to errors" echo "$(date +%Y%m%d%H%M%S) Metadata upload failed due to errors" >> "$LOGFILE" exit 1 fi fi fi } else echo "Not uploaded" echo "$(date +%Y%m%d%H%M%S) Upload aborted" >> "$LOGFILE" fi fi # vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21