#!/bin/zsh # shellcheck shell=bash ############################################################################## ## ## Based partially on a message that was originally posted to rivendell-dev by ## Wayne Merricks with Subject: "[RDD] Getting ## Airplay to Auto Play at correct time" ## ## BUT ALERT: This script assumes that tomorrows Log has already been prepared! ## ## NOTICE: This script is highly site-specific. Experience has shown that every ## "midnight transition" is slightly different. The sequence of Rivendell Macros ## need to be adjusted based on station policy and preferences. ## ## This script does not start the next Log, it simply loads tomorrows Log and ## makes the first Cart in the new Log the next Cart to play. This is to work ## around the seemingly broken setting in rdadmin -> Manage Services -> "Insert ## CHAIN TO at log end" (also seemingly in older version of Rivendell). You ## should DISABLE that setting when using this script and the associated RML ## Macro. ## ## This is meant to be run non-interactively from either a cron job, or from ## another job scheduler such as rdcatch(1) at several seconds before midnight. ## ## This script MUST run ON the host running RDAirPlay! ## ############################################################################## zmodload zsh/datetime myName="${0:t}" # This script complies with Semantic Versioning: http://semver.org/ declare -ir v_major=0 declare -ir v_minor=2 declare -ir v_patch=6 # SC2016: $Hash$ is not a shell variable. # shellcheck disable=SC2016 declare -r v_hash='$Hash$' ########################################################################################## ########################################################################################## ## ## Locally defined subroutines ## ########################################################################################## ########################################################################################## # How to use this command. usage() { local myName="${1}" # SC2154: CAT is set by mk-ourCommands. # shellcheck disable=SC2154 ${CAT} < ] [ ] [ --help (-h) ] [ --version (-V) ] [ --verbose (-v) ] Description ${myName} is a ZSH sript that performs some sanity checking then loads "tomorrow's" Log in the currently running instance of RDAirplay on the current workstation. ${myName} searches for "tomorrow's" Log in RDAirplay's default Service (as configured in RDAdmin->Manage Hosts->RDAirplay) for this workstation, but you may override that with the --service option. The Service named 'Production' is used if no default Service is set. You may also direct ${myName} to load a single additional Log in the Aux Log 1 Log Machine. Simply include the name of the Log as the last parameter on the command line. Specifying the --verbose option causes ${myName} to enable the ZSH "XTRACE" and "SOURCE_TRACE" options. EOF } ########################################################################################## ########################################################################################## ## ## Script Main Line ## ########################################################################################## ########################################################################################## ############# BEGIN external shell commands used in this script. ############# # This script uses these 5 external commands. # Look for them in their upper case, parameter expanded form. our_commands=( cat getopt hostname logger rmlsend ) # Find the executables we need; this uses some basic shell and a ZSH trick: # the (U) in the eval says to evaluate the parameter as all upper case # letters. This snippet generates shell parameters representing the upper case # equivalent of the command names and sets the parameter values to the full path # of the commands. # Refresh this segment in Emacs by marking the appropriate region (or the whole # buffer with C-xH) and replacing it with C-uM-|mk-ourCommands --script (shell-command-on-region). typeset C D # SC2048: shellcheck overly aggressive quote recommendation. # shellcheck disable=SC2048 for C in ${our_commands[*]} ; do # shellcheck disable=SC2154 # ZSH: ${path} is set by the shell. for D in ${path} ; do # shellcheck disable=SC2140,SC2086 # we need the quotes [[ -x "${D}/${C}" ]] && { eval "${(U)C//-/_}"="${D}/${C}" ; break ; } done [[ -x $(eval print \$"${(U)C//-/_}") ]] || { print "Cannot find ${C}! Done."; return 1 ; } done unset our_commands C D ############## END external shell commands used in this script. ############## declare -i show_version=0 declare -i VERBOSE=0 # SC2154: GETOPT is set by mk-ourCommands. # shellcheck disable=SC2154 if ! TEMP=$(${GETOPT} -o hs:vV --long help,service:,verbose,version, -n "${0:t}" -- "${@}") ; then print "getopt(1) Fatal Error (${?}). Terminating..." >&2 return 1 fi eval set -- "${TEMP}" while : ; do # VERBOSE is used, but in a non-Bash way. # shellcheck disable=SC2034 case "${1}" in -h|--help*) usage "${myName}" ; exit ;; -s|--serv*) SERVICE_NAME="${2}" ; shift 2 ;; -v|--verb*) VERBOSE=1 ; PASSFILE=none ; shift ;; -V|--vers*) show_version=1 ; shift ;; --) shift ; break ;; *) print "${0:t}: getopt internal error!. Terminating..." >&2 ; return 1 ;; esac done unset TEMP if ((show_version)) ; then typeset commit_hash="${v_hash}" # SC2016: $Hash$ is not a shell variable. # shellcheck disable=SC2016 [[ "${v_hash}" == '$Hash$' ]] && commit_hash="prerelase" print "${0:t}: version ${v_major}.${v_minor}.${v_patch}-${${commit_hash#\$Hash: }%$}" exit 0 fi # Redirect STDOUT and STDERR to separate files. if ! ((VERBOSE)) ; then exec 1> "/var/tmp/${myName}.out" exec 2> "/var/tmp/${myName}.err" fi # Enable ZSH XTRACE and SOURCE_TRACE options if --verbose. All output will go to # ${0}.err (see above). ((VERBOSE)) && setopt xtrace source_trace # Optional argument names a Log to load in the Aux Log 1 Machine. if [[ -n "${1}" ]] ; then auxLog="${1}" shift fi # Get zsh functions necessary for this script. if [[ -r /usr/bin/zsh-functions ]] ; then # shellcheck disable=SC1090 source /usr/bin/zsh-functions elif [[ -r /usr/local/bin/zsh-functions ]] ; then # shellcheck disable=SC1090 source /usr/local/bin/zsh-functions else # SC2154: LOGGER is set by mk-ourCommands. # shellcheck disable=SC2154 ${LOGGER} --stderr -t "${myName}" -p local7.err -i "ERROR: Cannot find zsh-functions. Cannot continue." exit 3 fi # Calculate the the name of tomorrow's Log based on the current time. # SC2154: EPOCHSECONDS is set for us by ZSH. # shellcheck disable=SC2154 timeNow=${EPOCHSECONDS} oneDay=$(( 60 * 60 * 24 )) hours=$(( $(strftime "%H" "${timeNow}") * 60 * 60 )) minutes=$(( $(strftime "%M" "${timeNow}") * 60 )) seconds=$(strftime "%S" "${timeNow}") secondsPastMidnight=$(( hours + minutes + seconds )) tomorrow=$(( timeNow - secondsPastMidnight + oneDay )) # Retrieve the default Serivce name for this workstation. Use the name # Production if no default Service is set. defaultService=$(doSQL "SELECT default_service FROM RDAIRPLAY WHERE station='$(${HOSTNAME} -s)'") SERVICE_NAME="${SERVICE_NAME:-${defaultService:-Production}}" # Get the Log name template for this Service from the SERVICES table. # This will be placed in an associative array indexed on the SERVICE name. typeset -A logNameTemplate # shellcheck disable=SC2190 # shellcheck disable=SC2207 logNameTemplate=( $(doSQL "SELECT name,name_template FROM SERVICES WHERE name = '${SERVICE_NAME}'") ) # There will really be a single key-value pair in this array, but this # is an easy way to get at it. for service in ${(k)logNameTemplate} ; do # Rivendell uses %s for "Service Name", strftime uses %s for # "Seconds since the Epoch". "Manually" replace the %s with the # Service Name in the Log Template before substituting the date # stuff in the Log Template. if [[ "${logNameTemplate[${service}]}" =~ %s ]] ; then logNameTemplate[${service}]=${logNameTemplate[${service}]//\%s/${service}} fi # SC2079: ZSH (()) arithmetic expressions can do floating point math. # SC2154: ZSH_VERSION is set by ZSH. # shellcheck disable=SC2079,SC2154 if (( ${ZSH_VERSION[1,3]} < 5.6 )) ; then # shellcheck disable=SC2046 nextLog=$(date --date=$(strftime "%F" "${tomorrow}") "+${logNameTemplate[${service}]}") else nextLog=$(strftime "${logNameTemplate[${service}]}" "${tomorrow}") fi # Rivendell versions prior to version 3 tacked "_LOG" to the end of # the Log Name. if (( $(rdDatabaseVersion) < 300 )) ; then nextLog=${nextLog}_LOG fi # Verify that the Log exists before running the Macros nextLogLookup=$(doSQL "SELECT name FROM LOGS WHERE name = '${nextLog}'") if [[ -n "${nextLogLookup}" ]] ; then # NOTICE: the following here-doc is highly site-specific. Please update # these Macro calls as appropriate for the station. # # What this here-doc does: # PW 1: Select Widget, "Main Log" # LL 1: Load Log, RDAirPlay load tomorrows Log, but do not start it (-1) # auxLog: if the shell variable auxLog is set, load the named Log in Auxiliary Log 1 (Log Machine 2) # MN 1: Make Next, the first Cart in the Log (line ID 0, should be a "Start Immediately", or "Make Next") # auxLog: if the shell variable auxLog is set, Make Next the first Cart in Auxiliary Log 1 (line ID 0) # Two possible alternatives here (probably not both PM and PN). Either # PM 2: Set Mode, RDAirPlay mode "Auto" # - or - # PN 1: Play Next, Play the next line in the Main Log # SC2154: RMLSEND is set by mk-ourCommands. # shellcheck disable=SC2154 if rmlsendOutput=$(${RMLSEND} --from-file=- 2>&1) <