forked from HPR/hpr-tools
Moved project directories and files to an empty local repo
This commit is contained in:
56
Show_Submission/.rsync_hpr_upload
Normal file
56
Show_Submission/.rsync_hpr_upload
Normal file
@@ -0,0 +1,56 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
# Last change: 2023-07-03 16:03:16
|
||||
#
|
||||
# rsync rules for copying files from the upload directory on
|
||||
# the hackerpublicradio.org server. We want to visit sub-directories and
|
||||
# collect the file 'shownotes.txt' as well as any ancillary files,
|
||||
# particularly pictures. We do not want the audio, nor do we want the
|
||||
# 'shownotes.html' which we upload after processing. The local directory is
|
||||
# kept in step with the remote one, including deleting files.
|
||||
#
|
||||
# 2019-12-11: The upper-case versions of some file extensions weren't
|
||||
# originally catered for and have been added.
|
||||
#
|
||||
# 2021-11-24: Ken changed a show number (3487->3482) and left its original
|
||||
# directory, then (since the slot was now open) somebody else sent in 3487 but
|
||||
# of course got a different directory name because it contains a random key.
|
||||
# I added an underscore to the start of the directory name to ignore it, and
|
||||
# have catered for this below.
|
||||
#
|
||||
# 2022-12-22: Removed shownotes.txt from the list of files to collect and
|
||||
# added it to the list _not_ to collect!
|
||||
#
|
||||
# 2023-04-07: Added '*.oga' and '*.OGA' to the list of audio types to ignore
|
||||
#
|
||||
# 2023-06-22: Added directories containing the string '_9999_' to the ignore
|
||||
# list. This is apparently used for shows destined for the reserve queue. This
|
||||
# might be a temporary measure because we might want to process such shows in
|
||||
# this workflow.
|
||||
#-------------------------------------------------------------------------------
|
||||
- *.swp
|
||||
- *~
|
||||
- *.aiff
|
||||
- *.AIFF
|
||||
- *.flac
|
||||
- *.FLAC
|
||||
- *.oga
|
||||
- *.OGA
|
||||
- *.ogg
|
||||
- *.OGG
|
||||
- *.mp3
|
||||
- *.MP3
|
||||
- *.wav
|
||||
- *.WAV
|
||||
- *.m4a
|
||||
- *.M4A
|
||||
- *.lzma
|
||||
- *.LZMA
|
||||
- *.diff
|
||||
- shownotes.txt
|
||||
- shownotes.html
|
||||
- photo
|
||||
- processed/
|
||||
- _*/
|
||||
- *_9999_*/
|
||||
+ */
|
||||
+ shownotes.json
|
306
Show_Submission/check_reservations
Executable file
306
Show_Submission/check_reservations
Executable file
@@ -0,0 +1,306 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: check_reservations
|
||||
#
|
||||
# USAGE: ./check_reservations
|
||||
#
|
||||
# DESCRIPTION: Interrogate the 'reservations' table in the live HPR database
|
||||
# through an SSH tunnel. The result is used to look at and
|
||||
# report the state of processing on the local system.
|
||||
#
|
||||
# The original version of this script ran a remote command on
|
||||
# the VPS, but was very vulnerable to VPS and tunnel failure.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.8
|
||||
# CREATED: 2019-01-07 12:29:06
|
||||
# REVISION: 2023-07-01 23:04:16
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use feature qw{ postderef say signatures state };
|
||||
no warnings qw{ experimental::postderef experimental::signatures };
|
||||
|
||||
use Carp;
|
||||
use Getopt::Long;
|
||||
use Config::General;
|
||||
use DBI;
|
||||
|
||||
#
|
||||
# Version number (manually incremented)
|
||||
#
|
||||
our $VERSION = '0.0.8';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
my $cache = "$basedir/shownotes";
|
||||
my $configfile = "$basedir/.hpr_db.cfg";
|
||||
my $reserved = '9999';
|
||||
|
||||
my ( $dbh, $sth1, $h1 );
|
||||
my ( $show, @res);
|
||||
my $count = 0;
|
||||
|
||||
#
|
||||
# Interpretations of the new status values in the database
|
||||
#
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# The sequence seems to be:
|
||||
# 1. User selects a free slot (request.php), status becomes
|
||||
# REQUEST_UNVERIFIED, verified is 0, no email address recorded yet, IP
|
||||
# address recorded
|
||||
# 2. User enters the email address to receive the link to the form and presses
|
||||
# 'Next'. An email is sent with the link and status changes to
|
||||
# REQUEST_EMAIL_SENT, now the email address is filled out but verified
|
||||
# is 0 still.
|
||||
# 3. User clicks the link in the email they received which takes them to the
|
||||
# form, now the state becomes EMAIL_LINK_CLICKED and verified is 1. We see
|
||||
# this as 'pending', the first status we take account of since we exclude
|
||||
# all records in the 'reservations' table where verified is 0.
|
||||
# 4. The user completes the form and hits the 'Send' button. When all files
|
||||
# have been uploaded the status changes to SHOW_SUBMITTED.
|
||||
#
|
||||
# 2022-04-07 New values added:
|
||||
#
|
||||
# 5. METADATA_PROCESSED signals that the processing of notes and related
|
||||
# things is complete
|
||||
# 6. MEDIA_TRANSCODED indicates that Ken has done the transcoding and posted
|
||||
# the show.
|
||||
# 7. UPLOADED_TO_IA indicates that the IA upload has been done (by me usually)
|
||||
# 8. UPLOADED_TO_RSYNC_NET final step shows that the files (audio & assets)
|
||||
# have been archived/backed up
|
||||
#
|
||||
# 2023-07-02 New value added for reserve shows
|
||||
#
|
||||
# 9. RESERVE_SHOW_SUBMITTED indication that a reserve show has been uploaded
|
||||
# and stashed away ready for adding to a slot at a later time.
|
||||
#
|
||||
# I don't think there's a way of knowing what has happened between
|
||||
# EMAIL_LINK_CLICKED and SHOW_SUBMITTED.
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#
|
||||
my %status = (
|
||||
REQUEST_UNVERIFIED => 'unverified', # shouldn't be returned
|
||||
REQUEST_EMAIL_SENT => 'email sent', # been sent the email with a link
|
||||
EMAIL_LINK_CLICKED => 'pending', # filling in the form/sending the show
|
||||
RESERVE_SHOW_SUBMITTED => 'reserved show', # reserve show received
|
||||
SHOW_SUBMITTED => 'uploaded', # all done
|
||||
METADATA_PROCESSED => 'metadata processed', # notes processed, etc
|
||||
SHOW_POSTED => 'in the database', # awaiting audio transcoding
|
||||
MEDIA_TRANSCODED => 'transcoded', # audio transcoded
|
||||
UPLOADED_TO_IA => 'uploaded to IA', # uploaded to IA
|
||||
UPLOADED_TO_RSYNC_NET => 'archived', # archived on rsync.net
|
||||
);
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
binmode STDOUT, ":encoding(UTF-8)";
|
||||
binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Options and arguments
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
my %options;
|
||||
Options( \%options );
|
||||
|
||||
#
|
||||
# Default help
|
||||
#
|
||||
Usage() if ( $options{'help'} );
|
||||
|
||||
#
|
||||
# Collect options
|
||||
#
|
||||
my $cfgfile
|
||||
= ( defined( $options{config} ) ? $options{config} : $configfile );
|
||||
|
||||
#
|
||||
# Sanity checks
|
||||
#
|
||||
die "Unable to find $cfgfile\n" unless ( -e $cfgfile );
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Configuration file - load data
|
||||
#-------------------------------------------------------------------------------
|
||||
my $conf = Config::General->new(
|
||||
-ConfigFile => $cfgfile,
|
||||
-InterPolateVars => 1,
|
||||
-ExtendedAccess => 1,
|
||||
);
|
||||
my %config = $conf->getall();
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Connect to the database
|
||||
#-------------------------------------------------------------------------------
|
||||
my $dbhost = $config{database}->{host} // '127.0.0.1';
|
||||
my $dbport = $config{database}->{port} // 3306;
|
||||
my $dbname = $config{database}->{name};
|
||||
my $dbuser = $config{database}->{user};
|
||||
my $dbpwd = $config{database}->{password};
|
||||
$dbh = DBI->connect( "dbi:mysql:host=$dbhost;port=$dbport;database=$dbname",
|
||||
$dbuser, $dbpwd, { AutoCommit => 1 } )
|
||||
or croak $DBI::errstr;
|
||||
|
||||
#
|
||||
# Enable client-side UTF8
|
||||
#
|
||||
$dbh->{mysql_enable_utf8} = 1;
|
||||
|
||||
#
|
||||
# Set the local timezone to UTC for this connection
|
||||
#
|
||||
$dbh->do("set time_zone = '+00:00'") or carp $dbh->errstr;
|
||||
|
||||
#
|
||||
# Query the reservations table for shows which are more or less kosher.
|
||||
# 2023-07-01 the episode number 9999 is currently a marker that the show is
|
||||
# for the reserve queue, so we omit it
|
||||
#
|
||||
$sth1 = $dbh->prepare(
|
||||
q{SELECT * FROM reservations WHERE ep_num > 0 ORDER BY timestamp});
|
||||
$sth1->execute();
|
||||
if ( $dbh->err ) {
|
||||
carp $dbh->errstr;
|
||||
}
|
||||
|
||||
#
|
||||
# Collect details of all the verified reservations found, with an
|
||||
# interpretation of their state and the email of the sender. For each show
|
||||
# look at its local state and report it.
|
||||
#
|
||||
while ( $h1 = $sth1->fetchrow_hashref() ) {
|
||||
$show = $h1->{ep_num};
|
||||
|
||||
if ($show == $reserved) {
|
||||
push(@res,$h1);
|
||||
next;
|
||||
}
|
||||
|
||||
$count++;
|
||||
|
||||
my @atts;
|
||||
push( @atts, "+dir" ) if ( -e "$cache/hpr${show}" );
|
||||
push( @atts, "+shownotes" ) if ( -s "$cache/hpr${show}/shownotes.txt" );
|
||||
push( @atts, "+processed" ) if ( -e "$cache/hpr${show}/hpr${show}.html" );
|
||||
push( @atts, "+uploaded" ) if ( -e "$cache/hpr${show}/.uploaded" );
|
||||
|
||||
printf "[%02d] %04d: %-18s (%s) %s\n", $count, $show,
|
||||
(
|
||||
exists( $status{ $h1->{status} } )
|
||||
? $status{ $h1->{status} }
|
||||
: 'unknown'
|
||||
),
|
||||
$h1->{email},
|
||||
join( "; ", @atts );
|
||||
}
|
||||
|
||||
#
|
||||
# If for some reason there aren't any reservations tell the caller
|
||||
#
|
||||
say "No show reservations" if ( $count == 0 );
|
||||
|
||||
if (@res) {
|
||||
say " ";
|
||||
say "Reserve queue entries";
|
||||
$count = 0;
|
||||
|
||||
for my $r (@res) {
|
||||
$count++;
|
||||
|
||||
printf "[%02d] %-24s %s (%s)\n", $count,
|
||||
(
|
||||
exists( $status{ $r->{status} } )
|
||||
? $status{ $r->{status} }
|
||||
: 'unknown'
|
||||
),
|
||||
$r->{timestamp},
|
||||
$r->{email};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Usage
|
||||
# PURPOSE: Display a usage message and exit
|
||||
# PARAMETERS: None
|
||||
# RETURNS: To command line level with exit value 1
|
||||
# DESCRIPTION: Builds the usage message using global values
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Usage {
|
||||
print STDERR <<EOD;
|
||||
$PROG v$VERSION
|
||||
|
||||
Usage: $PROG [options]
|
||||
|
||||
Scans the HPR database table 'reservations' and reports what new shows are
|
||||
indicated there and what state they are in.
|
||||
|
||||
Options:
|
||||
|
||||
-help Display this information
|
||||
-config=FILE This option allows an alternative configuration file
|
||||
to be used. This file defines the location of the
|
||||
database, its port, its name and the username and
|
||||
password to be used to access it. This feature was
|
||||
added to allow the script to access alternative
|
||||
databases or the live database over an SSH tunnel.
|
||||
|
||||
If the option is omitted the default file is used:
|
||||
.hpr_db.cfg
|
||||
|
||||
EOD
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Options
|
||||
# PURPOSE: Processes command-line options
|
||||
# PARAMETERS: $optref Hash reference to hold the options
|
||||
# RETURNS: Undef
|
||||
# DESCRIPTION:
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Options {
|
||||
my ($optref) = @_;
|
||||
|
||||
my @options = ( "help", "config=s", );
|
||||
|
||||
Usage() if ( !GetOptions( $optref, @options ) );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=100:fo=tcrqn21:fdm=marker
|
||||
|
116
Show_Submission/copy_shownotes
Executable file
116
Show_Submission/copy_shownotes
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env bash
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: copy_shownotes
|
||||
#
|
||||
# USAGE: ./copy_shownotes
|
||||
#
|
||||
# DESCRIPTION: Copies the shownotes (and related files) downloaded from the
|
||||
# HPR server. This happens after 'sync_hpr' has been run to
|
||||
# collect updates from the ~hpr/upload/ directory on the server
|
||||
# and store the result in the local upload/ directory.
|
||||
# 2022-12-17: Converted to shownotes.json.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.10
|
||||
# CREATED: 2015-09-16 21:51:15
|
||||
# REVISION: 2023-07-01 22:48:53
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
LOGS="$BASEDIR/logs"
|
||||
UPLOAD="$BASEDIR/upload"
|
||||
CACHE="$BASEDIR/shownotes"
|
||||
|
||||
#
|
||||
# Filenames
|
||||
#
|
||||
LOGFILE="$LOGS/${SCRIPT}.log"
|
||||
#SHOWNOTES='shownotes.txt'
|
||||
SHOWNOTES='shownotes.json'
|
||||
ORIGIN='.origin'
|
||||
STATUS='.status'
|
||||
DUMMY='.dummy'
|
||||
|
||||
#
|
||||
# Loop through everything in the $UPLOAD directory using a regular expression
|
||||
# to find sub-directories. These look like:
|
||||
# 1445633350_1906_2015-11-23_f348faf9125c129c1ebe0dd0edd721a0562a9d464bbbf
|
||||
#
|
||||
# The regex used in find takes into account that it needs to match the full
|
||||
# path.
|
||||
#
|
||||
count=0
|
||||
target=".*/[0-9]+_[0-9]{4}_[0-9]{4}-[0-9]{2}-[0-9]{2}_.+$"
|
||||
while read -r d
|
||||
do
|
||||
#
|
||||
# Parse out the show number
|
||||
#
|
||||
show="$(echo "$d" | cut -f2 -d_)"
|
||||
from="$UPLOAD/$d/"
|
||||
dir="$CACHE/hpr${show}"
|
||||
to="$dir/$SHOWNOTES"
|
||||
origin="$dir/$ORIGIN"
|
||||
status="$dir/$STATUS"
|
||||
dummy="$dir/$DUMMY"
|
||||
|
||||
#
|
||||
# Make the receiving directory if it doesn't exist
|
||||
#
|
||||
if [[ ! -e $dir ]]; then
|
||||
mkdir "$dir"
|
||||
fi
|
||||
|
||||
#
|
||||
# Copy files if there are no shownotes or the file exists and is empty.
|
||||
#
|
||||
# 2022-12-17: We're soon not using shownotes.txt any more. The data is in
|
||||
# shownotes.json instead. Also, dummy shows have a '.dummy' file rather
|
||||
# than empty notes.
|
||||
#
|
||||
# if [[ ! -e $to || ! -s $to ]]; then
|
||||
if [[ ! -e $to || -e $dummy ]]; then
|
||||
rsync -vaP "$from" "${dir}/"
|
||||
echo "$d" > "$origin"
|
||||
echo "copied" > "$status"
|
||||
((count++))
|
||||
printf '%(%F %T)T %s\n' -1 "$dir" >> "$LOGFILE"
|
||||
echo "${green}Copied notes for show $show${reset}"
|
||||
fi
|
||||
done < <(find "$UPLOAD" -maxdepth 1 -regextype posix-egrep -regex "$target" -type d -printf '%f\n')
|
||||
|
||||
if [[ $count -eq 0 ]]; then
|
||||
echo "${yellow}Nothing to do${reset}"
|
||||
else
|
||||
echo "${green}Notes copied: $count${reset}"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
133
Show_Submission/do_brave
Executable file
133
Show_Submission/do_brave
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_brave
|
||||
#
|
||||
# USAGE: ./do_brave <epno>
|
||||
#
|
||||
# DESCRIPTION: Run the Brave browser to view completed notes
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: 2020-06-01: New version of Brave (now called 'brave-browser')
|
||||
# necessitates changes in how this script was originally
|
||||
# designed. The softlink between hpr????.out and hpr????.html
|
||||
# has been converted to a hard link.
|
||||
# NOTES: We use a link 'do_browser' to point to whichever script runs
|
||||
# the preferred browser. It's been Brave for several years now,
|
||||
# but we haven't changed this!
|
||||
# 2022-12-22: We now write state changes to the file .status in
|
||||
# the show directory, so we need to do that here too. Also
|
||||
# changed to using the function library for cleanup_temp.
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.5
|
||||
# CREATED: 2016-03-20 15:22:29
|
||||
# REVISION: 2022-12-22 17:28:12
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Basic validation
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage $SCRIPT shownumber"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Directories and files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${1}"
|
||||
RAWNOTES="$SHOWDIR/hpr${1}.out"
|
||||
HTML="$SHOWDIR/hpr${1}.html"
|
||||
FULLHTML="$SHOWDIR/hpr${1}_full.html"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
|
||||
HTMLFILE="$FULLHTML"
|
||||
|
||||
#
|
||||
# Check we have this browser
|
||||
#
|
||||
BRAVE=$(command -v brave-browser)
|
||||
[[ -v BRAVE ]] || { echo "Problem finding the Brave browser"; exit 1; }
|
||||
|
||||
#
|
||||
# We prefer to view the 'full' html which we do by default. If not found
|
||||
# (because the host sent in HTML themselves) we look for hpr????.html, which
|
||||
# is a link to the notes from the form (hpr????.out), and view that. If the
|
||||
# link didn't get created (not sure why) we copy the "raw" notes to
|
||||
# a temporary file with an '.html' extension (TODO: we could just make a link
|
||||
# here). Otherwise we found nothing viewable.
|
||||
#
|
||||
if [[ ! -e $FULLHTML ]]; then
|
||||
if [[ -e $HTML ]]; then
|
||||
echo "No full HTML found, viewing $HTML instead"
|
||||
HTMLFILE="$HTML"
|
||||
elif [[ -e $RAWNOTES ]]; then
|
||||
echo "No files with ''.HTML' suffix, viewing raw notes"
|
||||
|
||||
TMP1=$(mktemp '/tmp/notes_XXXXXX.html') || { echo "$SCRIPT: creation of temporary file failed!"; exit 1; }
|
||||
trap 'cleanup_temp $TMP1' SIGHUP SIGINT SIGPIPE SIGTERM EXIT
|
||||
|
||||
cp "$RAWNOTES" "$TMP1"
|
||||
HTMLFILE="$TMP1"
|
||||
else
|
||||
echo "Nothing to view, giving up"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Open a parent instance of Brave (in the background), then open the HTML
|
||||
# notes after a short delay, thereby ensuring they open in a tab rather than
|
||||
# in another window. Brave has great potential but documentation is a bit
|
||||
# sparse.
|
||||
# NOTE: We're using debug statements for the moment until this method is shown
|
||||
# to be a good one.
|
||||
#
|
||||
# if [[ $(pgrep -u "$USER" -f '/usr/bin/brave-browser' -c) -eq 0 ]]; then
|
||||
# echo "D> Starting parent browser"
|
||||
# $BRAVE > /dev/null 2>&1 &
|
||||
# echo "D> Delaying ..."
|
||||
# sleep 3
|
||||
# fi
|
||||
#
|
||||
# 2020-11-29 Looks like the parent + child model doesn't work any more (they
|
||||
# keep changing this browser!). Also, just running the browser doesn't return
|
||||
# to the command line any more so it seems to need to be in the background.
|
||||
#
|
||||
# echo "D> Starting browser tab"
|
||||
echo "D> Starting browser itself"
|
||||
$BRAVE "${HTMLFILE}" > /dev/null 2>&1 &
|
||||
# $BRAVE "${HTMLFILE}&"
|
||||
# $BRAVE "${HTMLFILE}"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
#
|
||||
# Update the status file
|
||||
#
|
||||
echo "rendered" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
else
|
||||
echo "Oops! Something went wrong!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
1
Show_Submission/do_browser
Symbolic link
1
Show_Submission/do_browser
Symbolic link
@@ -0,0 +1 @@
|
||||
do_brave
|
174
Show_Submission/do_change_format
Executable file
174
Show_Submission/do_change_format
Executable file
@@ -0,0 +1,174 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_change_format
|
||||
#
|
||||
# USAGE: ./do_change_format <epno>
|
||||
#
|
||||
# DESCRIPTION: Changes the declared format of a show. Mainly useful to change
|
||||
# 'markdown_standard' (largely useless) to 'Markdown_Pandoc',
|
||||
# but can be used to override notes declared as 'html5' when
|
||||
# they are 'plain_text'.
|
||||
# 2022-12-22: Now using only shownotes.json, writing the new
|
||||
# value to the .format file and writing status changes to the
|
||||
# .status file. DOES NOT update the JSON.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.4
|
||||
# CREATED: 2018-12-06 11:11:30
|
||||
# REVISION: 2024-02-13 20:33:42
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
VERSION='0.0.4'
|
||||
|
||||
#
|
||||
# Load library functions (make_file_list, range_parse, cleanup_temp)
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Check the argument after any options
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "$SCRIPT ($VERSION): Usage $SCRIPT shownumber"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${1}"
|
||||
FORMAT="$SHOWDIR/.format"
|
||||
FROM="$SHOWDIR/shownotes.json"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
JSONNOTES="$SHOWDIR/shownotes.json"
|
||||
JSONORIG="$SHOWDIR/shownotes.json.orig"
|
||||
RELEASE="$SHOWDIR/.release"
|
||||
ORIGIN="$SHOWDIR/.origin"
|
||||
DEST="hpr@hackerpublicradio.org:upload"
|
||||
SSHPORT=22
|
||||
|
||||
#
|
||||
# Collect the place to write results and the release date
|
||||
#
|
||||
upload_dir=$(cat "$ORIGIN")
|
||||
release_date=$(cat "$RELEASE")
|
||||
|
||||
#
|
||||
# The permitted formats as defined in the web form
|
||||
#
|
||||
declare -A formats
|
||||
formats[plain_text]='FALSE'
|
||||
formats[html5]='FALSE'
|
||||
formats[markdown_standard]='FALSE'
|
||||
formats[Markdown_GitHub]='FALSE'
|
||||
formats[Markdown_Pandoc]='FALSE'
|
||||
formats[restructured_text]='FALSE'
|
||||
formats[txt2tags]='FALSE'
|
||||
|
||||
#
|
||||
# Check that we actually have notes for this show, and they aren't empty
|
||||
#
|
||||
if [[ -e $FROM ]]; then
|
||||
if [[ ! -s $FROM ]]; then
|
||||
echo "File $FROM is empty"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "$SCRIPT: File not found: $FROM"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Make temporary files and set traps to delete them.
|
||||
#
|
||||
# TMP1 - HTML header
|
||||
#
|
||||
TMP1=$(mktemp) || {
|
||||
echo "$SCRIPT: creation of temporary file failed!"
|
||||
exit 1
|
||||
}
|
||||
trap 'cleanup_temp $TMP1' SIGHUP SIGINT SIGPIPE SIGTERM EXIT
|
||||
|
||||
#
|
||||
# Record the current format
|
||||
#
|
||||
FFORMAT="$(cat "$FORMAT")"
|
||||
formats[$FFORMAT]='TRUE'
|
||||
|
||||
# for k in $(printf '%s\n' "${!formats[@]}" | sort); do
|
||||
# printf 'D> %18s: %s\n' "$k" "${formats[$k]}"
|
||||
# done
|
||||
|
||||
#
|
||||
# Generate a Zenity list box with radio buttons. Show current setting and
|
||||
# allow any other to be selected to replace it.
|
||||
#
|
||||
newfmt=$(for k in $(printf '%s\n' "${!formats[@]}" | sort); do
|
||||
printf '%s\n%s\n' "${formats[$k]}" "$k"; done |\
|
||||
zenity --list --radiolist --height=300 --width=300 \
|
||||
--column=Choice --title="Change format of notes" \
|
||||
--text="Choose format" --column=Format 2> /dev/null) ||\
|
||||
{ echo "Cancelled"; exit; }
|
||||
# echo "D> $newfmt"
|
||||
|
||||
#
|
||||
# If there was a change save the new value
|
||||
#
|
||||
if [[ $newfmt != "$FFORMAT" ]]; then
|
||||
echo "Changing format to '$newfmt'"
|
||||
|
||||
#
|
||||
# Update .format
|
||||
#
|
||||
echo "$newfmt" > "$FORMAT"
|
||||
|
||||
#
|
||||
# Update the JSON
|
||||
#
|
||||
cp "$FROM" "${FROM}.orig"
|
||||
cp "$FROM" "$TMP1"
|
||||
jq -c --arg new "$newfmt" \
|
||||
'(.metadata.POST.shownotes_format,.metadata.Shownotes_Format) |= $new' \
|
||||
"$TMP1" > "$FROM"
|
||||
|
||||
#
|
||||
# Upload updated JSON to the server, but only if the release date is in
|
||||
# the future
|
||||
#
|
||||
rd=$(date -d "$release_date" +%s)
|
||||
now=$(date +%s)
|
||||
if [[ $((rd - now)) -gt 0 ]]; then
|
||||
echo "Copying $JSONNOTES to upload/$upload_dir/shownotes.json on the HPR server"
|
||||
echo "Copying $JSONORIG to upload/$upload_dir/shownotes.json.orig on the HPR server"
|
||||
scp -P $SSHPORT "$JSONNOTES" "$JSONORIG" "$DEST/$upload_dir/"
|
||||
else
|
||||
echo "JSON files not uploaded to the server"
|
||||
echo "The release date $release_date is in the past!"
|
||||
fi
|
||||
|
||||
#
|
||||
# Update the status file
|
||||
#
|
||||
echo "format" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
||||
|
1
Show_Submission/do_edit
Symbolic link
1
Show_Submission/do_edit
Symbolic link
@@ -0,0 +1 @@
|
||||
do_vim
|
114
Show_Submission/do_edit_shownotes
Executable file
114
Show_Submission/do_edit_shownotes
Executable file
@@ -0,0 +1,114 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_edit_shownotes
|
||||
#
|
||||
# USAGE: ./do_edit_shownotes <field> <epno>
|
||||
#
|
||||
# DESCRIPTION: Edit one of the fields often needing work in
|
||||
# shownotes.{json,txt}, writing the updates back to the HPR
|
||||
# server in case they are needed there.
|
||||
#
|
||||
# ** Under development, not properly tested **
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: 2022-12-20: The shownotes.txt file is now obsolete
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.3
|
||||
# CREATED: 2022-12-09 21:52:29
|
||||
# REVISION: 2023-07-29 18:26:04
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
# DIR=${0%/*}
|
||||
|
||||
VERSION="0.0.3"
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "[${SCRIPT} ${VERSION}]: Usage: $SCRIPT field shownumber"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Collect arguments and validate them
|
||||
#
|
||||
field="${1,,}"
|
||||
showno="$2"
|
||||
|
||||
field="${field// /}"
|
||||
showno="${showno// /}"
|
||||
|
||||
if ! [[ $field =~ ^(tags|title|summary) ]]; then
|
||||
echo "Invalid field: $field"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ $showno =~ ^[0-9]+$ ]]; then
|
||||
echo "Invalid show number: $showno"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Constants, paths and files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${showno}"
|
||||
# SHOWNOTES="$SHOWDIR/shownotes.txt"
|
||||
# SNORIG="$SHOWDIR/shownotes.txt.orig"
|
||||
JSONNOTES="$SHOWDIR/shownotes.json"
|
||||
JSONORIG="$SHOWDIR/shownotes.json.orig"
|
||||
ORIGIN="$SHOWDIR/.origin"
|
||||
EDITSN="$BASENAME/edit_shownotes"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
DEST="hpr@hackerpublicradio.org:upload"
|
||||
SSHPORT=22
|
||||
|
||||
#
|
||||
# Collect the place to write results and the current MD5 sum of the JSON file
|
||||
#
|
||||
upload_dir=$(cat "$ORIGIN")
|
||||
MD5_1=$(md5sum "$JSONNOTES")
|
||||
|
||||
#
|
||||
# Run the editing program
|
||||
#
|
||||
echo "Editing $field for show $showno"
|
||||
$EDITSN -field="$field" -episode="$showno"
|
||||
RES=$?
|
||||
|
||||
#
|
||||
# Normal exit (0) means something was done. Anything else either means the
|
||||
# program aborted in a controlled way or there was an error.
|
||||
#
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "Edited show notes ok"
|
||||
|
||||
MD5_2=$(md5sum "$JSONNOTES")
|
||||
if [[ $MD5_1 = "$MD5_2" ]]; then
|
||||
echo "The files were not changed"
|
||||
exit
|
||||
else
|
||||
echo "Copying $JSONNOTES to upload/$upload_dir/shownotes.json on the HPR server"
|
||||
echo "Copying $JSONORIG to upload/$upload_dir/shownotes.json.orig on the HPR server"
|
||||
# scp -P 22074 "$JSONNOTES" "$JSONORIG" "hpr@hackerpublicradio.org:upload/$upload_dir/"
|
||||
scp -P $SSHPORT "$JSONNOTES" "$JSONORIG" "$DEST/$upload_dir/"
|
||||
|
||||
#
|
||||
# Update the status file
|
||||
#
|
||||
echo "metadata" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
fi
|
||||
else
|
||||
echo "Editing script ended prematurely"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
||||
|
313
Show_Submission/do_index
Executable file
313
Show_Submission/do_index
Executable file
@@ -0,0 +1,313 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_index
|
||||
#
|
||||
# USAGE: ./do_index <epno>
|
||||
#
|
||||
# DESCRIPTION: Makes an index.html file in the uploads directory of a show
|
||||
# for upload to the show's asset directory on the HPR server.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.5
|
||||
# CREATED: 2022-10-30 15:39:28
|
||||
# REVISION: 2022-12-17 17:38:00
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
# DIR=${0%/*}
|
||||
|
||||
VERSION="0.0.5"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions (make_file_list, range_parse, cleanup_temp)
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
# {{{ -- _usage -- _dryrun --
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-d] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Generates an 'index.html' file for a show with assets
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-d Select dry run mode
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} 3112
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _dryrun
|
||||
# DESCRIPTION: Output a dry run message
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_dryrun () {
|
||||
local prefix="Dry run: "
|
||||
for msg in "$@"; do
|
||||
printf '%9s%s\n' "$prefix" "$msg"
|
||||
prefix=
|
||||
done
|
||||
}
|
||||
# }}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
DRYRUN=0 # not dry run mode by default
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :hd opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) _usage;;
|
||||
d) DRYRUN=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
#
|
||||
# Check there's an argument after removing any options. Abort if not
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "${red}Missing shownumber argument${reset}"
|
||||
_usage
|
||||
fi
|
||||
ep="$1"
|
||||
printf -v show 'hpr%04d' "$ep"
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASEDIR/shownotes/hpr${ep}"
|
||||
RAWFILE="$SHOWDIR/shownotes.txt"
|
||||
JSONFILE="$SHOWDIR/shownotes.json"
|
||||
PICDIR="$SHOWDIR/uploads"
|
||||
INDEXFILE="$PICDIR/index.html"
|
||||
ASSETS="$SHOWDIR/.assets" # Created in parse_JSON
|
||||
PICLIST="$SHOWDIR/.pictures" # Created in parse_JSON
|
||||
STATUS="$SHOWDIR/.status"
|
||||
|
||||
#
|
||||
# Check the show directory exists
|
||||
#
|
||||
if [[ ! -d $SHOWDIR ]]; then
|
||||
echo "$SCRIPT: ${red}Directory $SHOWDIR not found${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# If no assets then don't continue
|
||||
#
|
||||
if [[ ! -e $ASSETS ]]; then
|
||||
echo "$SCRIPT: ${red}Asset file (.assets) not found in $SHOWDIR${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Do we already have an 'index.html'?
|
||||
#
|
||||
if [[ -e $INDEXFILE ]]; then
|
||||
echo "${red}There's already an 'index.html'${reset}"
|
||||
if [[ $DRYRUN -eq 0 ]] && ! yes_no 'Overwrite this file? %s ' 'No'; then
|
||||
echo "${red}Aborting!${reset}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Make temporary files and set traps to delete them.
|
||||
#
|
||||
# TMP1 - HTML header
|
||||
# TMP2 - HTML footer
|
||||
#
|
||||
TMP1=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP2=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
trap 'cleanup_temp $TMP1 $TMP2' SIGHUP SIGINT SIGPIPE SIGTERM EXIT
|
||||
|
||||
#
|
||||
# Parse these fields from the raw input file (shownotes.txt) into Bash
|
||||
# variables so we can make an index.html later.
|
||||
#
|
||||
# Title='' Summary='' Host_Name=''
|
||||
# eval \
|
||||
# "$(sed -n '/^\(Title\|Summary\|Host_Name\):/{s/^\([^:]\+\):\t/\1="/;s/$/"/;p}' "$RAWFILE")"
|
||||
|
||||
#
|
||||
# Parse these fields from the JSON input file (shownotes.json) into Bash
|
||||
# variables so we can make an index.html later.
|
||||
#
|
||||
Title='' Summary='' Host_Name=''
|
||||
jqprog="@sh \"Host_Name=\(.host.Host_Name) Title=\(.episode.Title) Summary=\(.episode.Summary)\""
|
||||
command=$(jq -r "$jqprog" "$JSONFILE")
|
||||
eval "${command}"
|
||||
|
||||
#
|
||||
# Make two HTML templates and two TT² templates. We do this in dry-run mode
|
||||
# too then throw them away!
|
||||
#
|
||||
# {{{
|
||||
cat > "$TMP1" <<ENDHTML1
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="pandoc">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<meta name="author" content="$Host_Name">
|
||||
<title>$Title (HPR Show $ep)</title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link rel="stylesheet" href="https://hackerpublicradio.org/css/hpr.css">
|
||||
</head>
|
||||
|
||||
<body id="home">
|
||||
<div id="container" class="shadow">
|
||||
<header>
|
||||
<h1 class="title">$Title (HPR Show $ep)</h1>
|
||||
<h3 class="summary">$Summary</h3>
|
||||
<h3 class="author">$Host_Name</h3>
|
||||
<hr/>
|
||||
</header>
|
||||
|
||||
<main id="maincontent">
|
||||
<article>
|
||||
<h3 id="index">Index</h3>
|
||||
<ul>
|
||||
ENDHTML1
|
||||
|
||||
cat > "$TMP2" <<ENDHTML2
|
||||
</ul>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
ENDHTML2
|
||||
# }}}
|
||||
|
||||
#
|
||||
# Make a simple index.html file. We use the .assets file and the .pictures
|
||||
# list (if there is one) and read them into an aray and a hash. We can then
|
||||
# generate HTML appropriate to their type.
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
#
|
||||
# Make an array of assets
|
||||
#
|
||||
if [[ -e $ASSETS ]]; then
|
||||
declare -a assets
|
||||
mapfile -t assets < "$ASSETS"
|
||||
else
|
||||
echo "$SCRIPT: ${red}No assets found!${reset}"
|
||||
echo "$SCRIPT: ${red}Show has no $ASSETS file!${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Make a hash of pictures. It's not an error if there are none; we still
|
||||
# need to process assets.
|
||||
#
|
||||
if [[ -e $PICLIST ]]; then
|
||||
declare -A pix
|
||||
while read -er pic; do
|
||||
pix[$pic]=1
|
||||
done < "$PICLIST"
|
||||
else
|
||||
echo "$SCRIPT: ${red}No pictures found!${reset}"
|
||||
echo "$SCRIPT: ${blue}Processing $ASSETS only${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Assemble the index from header, footer and a body of file/picture
|
||||
# references. If an asset is in the 'pix' hash then it's a picture, so we
|
||||
# generate different HTML than in the other case.
|
||||
# TODO: Do a better job with displaying the pictures! Maybe limit the
|
||||
# size? Who's going to be looking at this anyway? Could the image URL
|
||||
# contain a size I wonder?
|
||||
#
|
||||
(
|
||||
cat "$TMP1"
|
||||
for asset in "${assets[@]}"; do
|
||||
# Don't let the index point to itself!
|
||||
if [[ $asset == 'index.html' ]]; then
|
||||
continue
|
||||
fi
|
||||
if [ -e "$PICLIST" ] && [ "${pix[$asset]+set}" == 'set' ]; then
|
||||
printf '<li><img src="https://hackerpublicradio.org/eps/%s/%s" alt="%s"></li>\n' \
|
||||
"$show" "$asset" "$asset"
|
||||
else
|
||||
printf '<li><a href="https://hackerpublicradio.org/eps/%s/%s">%s</a></li>\n' \
|
||||
"$show" "$asset" "$asset"
|
||||
fi
|
||||
done
|
||||
cat "$TMP2"
|
||||
) > "$INDEXFILE"
|
||||
|
||||
#
|
||||
# Report what happened
|
||||
#
|
||||
if [[ -e $INDEXFILE ]]; then
|
||||
echo "${green}Generated index in $INDEXFILE${reset}"
|
||||
else
|
||||
echo "${red}Something went wrong; can't find $INDEXFILE${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Set the status for this show
|
||||
#
|
||||
echo "index" >> "$STATUS"
|
||||
|
||||
else
|
||||
_dryrun "Would have generated index file ${yellow}$INDEXFILE${reset}"
|
||||
fi
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
524
Show_Submission/do_pandoc
Executable file
524
Show_Submission/do_pandoc
Executable file
@@ -0,0 +1,524 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_pandoc
|
||||
#
|
||||
# USAGE: ./do_pandoc [option] <epno>
|
||||
#
|
||||
# DESCRIPTION: Performs an "intelligent" Pandoc run on various types of show
|
||||
# notes. Converts various markup formats into HTML. Treate plain
|
||||
# text as Markdown, though this depends on the prior editing
|
||||
# step doing the right thing. Handles pictures and other assets
|
||||
# in plain text shows that have them - this is done by the edit
|
||||
# phase adding TT² macros and this script processing them with
|
||||
# 'tpage'.
|
||||
# Version 0:2:5 (released 2022-12-04) has not yet been fully
|
||||
# tested. Seems reliable 2023-03-03.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: 2021-04-03: removed the TOC option
|
||||
# 2021-11-07: Added --strip-comments to the HTML snippet
|
||||
# generation stage
|
||||
# 2022-11-01: Big rewrite over the month. Refer to
|
||||
# do_pandoc_0.1.6 for the previous version since there have been
|
||||
# some big changes.
|
||||
# 2022-12-17: Ending reliance on shownotes.txt, and using
|
||||
# shownotes.json instead into the future. Some massive tidying
|
||||
# and rationalisation are still required.
|
||||
# 2023-03-03: If the title contained a quote then the previous
|
||||
# algorithm made bad YAML which caused the 'full' html to fail.
|
||||
# Fixed.
|
||||
# 2023-11-15: The 'prefix' setting is wrong. It needs another
|
||||
# 'hpr1234' directory level. This is needed because the
|
||||
# top-level stuff for the show is already in such a directory,
|
||||
# and while we have assets in a sub-directory we need to be
|
||||
# careful about collisions.
|
||||
#
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.2.10
|
||||
# CREATED: 2016-08-16 15:34:30
|
||||
# REVISION: 2024-02-18 13:27:40
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
VERSION='0.2.10'
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
# {{{ Functions: -- _usage -- _DEBUG --
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-d] [-D] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Runs Pandoc against a particular show, choosing a format as
|
||||
defined by the declared format (in the file '.format').
|
||||
|
||||
(In this version there is no method to force an explicit input format)
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-d Select dry run mode
|
||||
-D Turn on debug mode with lots of extra output
|
||||
|
||||
The default behaviour is now to access the '.format' file in the show
|
||||
directory.
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -d 2240
|
||||
./${SCRIPT} -D 2250
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _DEBUG
|
||||
# DESCRIPTION: Writes one or more message lines if in DEBUG mode
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_DEBUG () {
|
||||
[ "$DEBUG" == 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf 'D> %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
# }}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
#
|
||||
# Formats offered by the web form on the HPR site:
|
||||
#
|
||||
# Keyword Explanation
|
||||
# ------- -----------
|
||||
# plain_text Plain text
|
||||
# html5 HTML5 (preferred)
|
||||
# markdown_standard Markdown (standard)
|
||||
# Markdown_GitHub Markdown (GitHub flavoured)
|
||||
# Markdown_Pandoc Markdown (Pandoc flavoured)
|
||||
# restructured_text RestructuredText
|
||||
# txt2tags txt2tags
|
||||
#
|
||||
|
||||
#
|
||||
# Hash to perform translation from declared format to Pandoc "-from" value
|
||||
#
|
||||
# {{{ -- 'lookup' hash --
|
||||
declare -A lookup
|
||||
lookup[plain_text]='markdown-implicit_figures'
|
||||
lookup[html5]='html'
|
||||
lookup[markdown_standard]='markdown_strict'
|
||||
lookup[Markdown_GitHub]='gfm' # Extensions are limited
|
||||
lookup[Markdown_Pandoc]='markdown-implicit_figures'
|
||||
lookup[restructured_text]='rst'
|
||||
lookup[txt2tags]='t2t'
|
||||
# }}}
|
||||
|
||||
#
|
||||
# Hash for options when generating standalone readable HTML
|
||||
#
|
||||
# (The 'smart' extension is only applicable to markdown, commonmark, latex,
|
||||
# mediawiki, org, rst, twiki; we want to turn it off to remove smart quotes)
|
||||
#
|
||||
# {{{ -- 'options' hash --
|
||||
declare -A options
|
||||
options[plain_text]='-smart'
|
||||
options[html5]=''
|
||||
options[markdown_standard]='+yaml_metadata_block'
|
||||
options[Markdown_GitHub]=''
|
||||
options[Markdown_Pandoc]='-smart+yaml_metadata_block'
|
||||
options[restructured_text]='-smart'
|
||||
options[txt2tags]=''
|
||||
# }}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Sanity checks
|
||||
#
|
||||
JQ=$(command -v jq)
|
||||
[ -n "$JQ" ] || { echo "Program 'jq' was not found"; exit 1; }
|
||||
# YQ=$(command -v yq)
|
||||
# [ -n "$YQ" ] || { echo "Program 'yq' was not found"; exit 1; }
|
||||
|
||||
#
|
||||
# Process options first
|
||||
#
|
||||
while getopts :dDh opt
|
||||
do
|
||||
case "${opt}" in
|
||||
d) DRYRUN=1;;
|
||||
D) DEBUG=1;;
|
||||
h) _usage;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
#
|
||||
# Default options if not provided
|
||||
#
|
||||
DEBUG=${DEBUG:-0}
|
||||
DRYRUN=${DRYRUN:-0}
|
||||
|
||||
#
|
||||
# Check there's an argument after removing any options. Abort if not
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
_usage
|
||||
fi
|
||||
|
||||
#
|
||||
# Declare variables for later
|
||||
# TODO: Is this necessary?
|
||||
#
|
||||
declare SHOWID FROM POPTIONS
|
||||
|
||||
#
|
||||
# Make the explicit show id, catering for leading zeroes (belt & braces)
|
||||
#
|
||||
printf -v SHOWID 'hpr%04d' "$1"
|
||||
|
||||
#
|
||||
# Make temporary files and set traps to delete them
|
||||
#
|
||||
TMP1=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP2=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP3=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
trap 'cleanup_temp $TMP1 $TMP2 $TMP3' SIGHUP SIGINT SIGPIPE SIGTERM EXIT
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
# ------------------------------------------------------------------------------
|
||||
# Main directory
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
|
||||
# JSON to YAML Perl script
|
||||
J2Y="$BASENAME/author_title.pl"
|
||||
[ -e "$J2Y" ] || { echo "Program '$J2Y' was not found"; exit 1; }
|
||||
|
||||
# The notes for all shows are here
|
||||
SHOWNOTES="$BASENAME/shownotes"
|
||||
|
||||
# Notes for this show are here
|
||||
SHOWDIR="$SHOWNOTES/$SHOWID"
|
||||
|
||||
# Paths to all files already created or being created here
|
||||
#RAWFILE="$SHOWDIR/shownotes.txt"
|
||||
JSONFILE="$SHOWDIR/shownotes.json"
|
||||
FMTFILE="$SHOWDIR/.format"
|
||||
PICLIST="$SHOWDIR/.pictures"
|
||||
STATUS="$SHOWDIR/.status"
|
||||
EXTRACT="$SHOWDIR/${SHOWID}.out"
|
||||
FULLHTML="$SHOWDIR/${SHOWID}_full.html"
|
||||
HTML="$SHOWDIR/${SHOWID}.html"
|
||||
|
||||
# TT² macros and paths for adding pictures
|
||||
PICTPL="$BASENAME/pic_definitions.tpl"
|
||||
MANIFEST="$SHOWDIR/.pictures.mf" # From do_pictures
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
#
|
||||
# The partial URL for pictures on the HPR site
|
||||
#
|
||||
BASEURL='https://hackerpublicradio.org/eps/'
|
||||
|
||||
#{{{ --- Obsolete 2022-12-17 ---
|
||||
#
|
||||
# Make a metadata file by parsing the raw data file fields with awk. Save it
|
||||
# in a temporary file.
|
||||
#
|
||||
# See the original do_pandoc_0.1.6 for the extended comments that led to this
|
||||
# design. We were trying to make acceptable YAML, but ended up extracting
|
||||
# metadata from the result.
|
||||
# ----
|
||||
# TODO: 2022-12-01 Rationalise all of this; it's full of debris from previous
|
||||
# attempts to solve the problem of passing metadata to Pandoc.
|
||||
# ----
|
||||
#
|
||||
# awk -f - "$RAWFILE" > "$TMP1" <<'ENDAWK'
|
||||
# BEGIN {print "---"}
|
||||
# /^Title:/ && got_title == 0 {
|
||||
# sub(/^Title:\s+/,"")
|
||||
# printf "#title: %s\n",$0
|
||||
# gsub(/'/,"''")
|
||||
# printf "title: '%s'\n",$0
|
||||
# got_title = 1
|
||||
# }
|
||||
# /^Host_Name:/ && got_author == 0 {
|
||||
# sub(/^Host_Name:\s+/,"")
|
||||
# printf "#author: %s\n",$0
|
||||
# gsub(/'/,"''")
|
||||
# printf "author: '%s'\n",$0
|
||||
# got_author = 1
|
||||
# }
|
||||
# END {print "---"}
|
||||
# ENDAWK
|
||||
#}}}
|
||||
|
||||
#
|
||||
# Use 'jq' to parse the JSON and make the metadata (in the form of YAML)
|
||||
# needed for Pandoc
|
||||
#
|
||||
# Non-YAML alternative - not chosen
|
||||
#jqprog="@text \"author: \(.host.Host_Name)\ntitle: \(.episode.Title)\""
|
||||
#
|
||||
# Testing another formatter (Journal 2023-03-03)
|
||||
#jqprog="@sh \"---\nauthor: \(.host.Host_Name)\ntitle: \(.episode.Title)\n---\""
|
||||
# Added quotes around the generated strings (2023-03-31)
|
||||
# jqprog="@text \"---\nauthor: \(.host.Host_Name)\ntitle: \(.episode.Title)\n---\""
|
||||
# Moved to 'yq' 2023-04-01
|
||||
# jqprog="@text \"---\nauthor: '\(.host.Host_Name)'\ntitle: '\(.episode.Title)'\n---\""
|
||||
# jq -r "$jqprog" "$JSONFILE" > "$TMP1"
|
||||
# On 2023-10-01 wrote a Perl JSON to YAML generator just for these two
|
||||
# elements. It's called 'author_title.pl'
|
||||
# yqprog='{author:.host.Host_Name,title:.episode.Title}'
|
||||
# ( echo "---"; $YQ -y "$yqprog" "$JSONFILE"; echo "---"; ) > "$TMP1"
|
||||
$J2Y "$JSONFILE" "$TMP1"
|
||||
_DEBUG "YAML:" "$(cat "$TMP1")"
|
||||
|
||||
#
|
||||
# Check the main output file from do_parse exists
|
||||
#
|
||||
if [[ ! -e $EXTRACT ]]; then
|
||||
echo "$SCRIPT: ${red}File not found: $EXTRACT${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Get the format or fail with an error
|
||||
#
|
||||
if [[ -e $FMTFILE ]]; then
|
||||
FORMAT=$(cat "$FMTFILE")
|
||||
else
|
||||
# TODO: Should we default to something rather than abort?
|
||||
echo "$SCRIPT: ${red}Could not find declared format (.format file)${reset}"
|
||||
echo "${yellow}Has do_parse been run? If so try and fix the .format file.${reset}"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Need to match plain text and Markdown variants when deciding to use the
|
||||
# manifest file and 'tpage'
|
||||
#
|
||||
FMTRE='^(plain_text|[Mm]arkdown_)'
|
||||
|
||||
#
|
||||
# Determine if there are pictures
|
||||
#
|
||||
if [[ -e $PICLIST ]]; then
|
||||
hasPictures=1
|
||||
else
|
||||
hasPictures=0
|
||||
fi
|
||||
|
||||
#
|
||||
# Here we use the declared format to determine what to do.
|
||||
#
|
||||
# This code now blocks HTML->HTML processing since it just confuses matters.
|
||||
# The files hprNNNN.out and hprNNNN.html are linked to one another, so editing
|
||||
# the former will edit the latter in preparation for uploading if there are
|
||||
# changes that need to be made. See the journal discussion for 2018-05-24.
|
||||
# ---
|
||||
# TODO: 2022-12-01 If the notes are HTML but declared as something else then
|
||||
# this check will not work. Trouble is, parse_JSON will have worked this out
|
||||
# but not saved it so we can't avoid running Pandoc on HTML in this case.
|
||||
# ---
|
||||
# TODO: 2022-12-01 Look at resolving this in parse_JSON?
|
||||
# ---
|
||||
#
|
||||
if [[ $FORMAT == 'html5' ]]; then
|
||||
echo "${red}Running Pandoc on HTML is not allowed${reset}"
|
||||
echo "${yellow}Run do_edit to edit as necessary and do_browser to view${reset}"
|
||||
exit
|
||||
elif [[ $FORMAT == 'plain_text' ]]; then
|
||||
echo "${yellow}Format chosen is plain text${reset}"
|
||||
if [[ $hasPictures -eq 0 ]]; then
|
||||
echo "${yellow}This will be treated as Markdown${reset}"
|
||||
else
|
||||
echo "${yellow}This will be treated as Markdown and will need special action${reset}"
|
||||
echo "${yellow}since there are pictures${reset}"
|
||||
fi
|
||||
fi
|
||||
FROM=${lookup[$FORMAT]}
|
||||
POPTIONS=${options[$FORMAT]}
|
||||
echo "${green}Will process $FORMAT with 'pandoc -f ${FROM}'${reset}"
|
||||
echo "${yellow}Options chosen for --standalone are '${POPTIONS}'${reset}"
|
||||
|
||||
#
|
||||
# Only for plain text notes, process pictures for the HTML we'll be adding to
|
||||
# the database.
|
||||
#
|
||||
# We need the following things:
|
||||
# - The notes to be plain text format
|
||||
# - Some pictures
|
||||
# - Files written by do_parse and do_pictures:
|
||||
# - .assets (not used here)
|
||||
# - .pictures (were previously used here, but no longer)
|
||||
# - .pictures.mf (needed by the TT² macros)
|
||||
# - .pictures.tt2 (the TT² macro calls - already edited into the notes)
|
||||
# - pic_definitions.tpl (macro definitions, common to all shows)
|
||||
# - Not to be in dry run mode; if we are we just report intentions
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
# if [[ $FORMAT == 'plain_text' && -e $MANIFEST ]]; then
|
||||
if [[ $FORMAT =~ $FMTRE && -e $MANIFEST ]]; then
|
||||
#
|
||||
# Deal with pictures using the TT² macros
|
||||
#
|
||||
_DEBUG "Processing TT² inclusions"
|
||||
|
||||
# Make a picture manifest with a header
|
||||
awk 'BEGIN{print "file : thumb"}{p1=$0; getline p2; printf "%s : %s\n",p1,p2}' \
|
||||
"$MANIFEST" > "$TMP2"
|
||||
|
||||
_DEBUG "Picture list:" "$(cat "$TMP2")" "---" \
|
||||
"BASEURL=${BASEURL}${SHOWID}/" \
|
||||
"EXTRACT=$EXTRACT" \
|
||||
"Extract file contents:" "$(cat "$EXTRACT")" "---"
|
||||
|
||||
# Run the macros on the notes to make $TMP3 for Pandoc
|
||||
tpage --pre_process="$PICTPL" \
|
||||
--define "piclist=$TMP2" \
|
||||
--define "prefix=${BASEURL}${SHOWID}/${SHOWID}/" \
|
||||
"$EXTRACT" > "$TMP3"
|
||||
|
||||
_DEBUG "Processed by tpage" "$(cat "$TMP3")" "---"
|
||||
else
|
||||
# Not plain text or a Markdown variant and no pictures, so put the
|
||||
# notes in $TMP3 where Pandoc will look for them
|
||||
cat "$EXTRACT" > "$TMP3"
|
||||
fi
|
||||
else
|
||||
#
|
||||
# We would not have used TT² unless the notes were plain text (or
|
||||
# a Markdown variant) and there were pictures
|
||||
#
|
||||
# if [[ $FORMAT == 'plain_text' && -e $MANIFEST ]]; then
|
||||
if [[ $FORMAT =~ $FMTRE && -e $MANIFEST ]]; then
|
||||
echo "${yellow}Would have prepared TT² code for pandoc${reset}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Generate an HTML snippet for adding to the database.
|
||||
# (Note 2021-11-24: Added --ascii option.)
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
# shellcheck disable=SC2086
|
||||
pandoc -f "$FROM"-smart -t html5 --ascii --no-highlight --strip-comments \
|
||||
"$TMP3" -o "$HTML" # $EXTRAS
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "$SCRIPT: ${green}Created shownotes/$SHOWID/${HTML##*/}${reset}"
|
||||
else
|
||||
echo "$SCRIPT: ${red}Oops! Something went wrong! (line $LINENO)${reset}"
|
||||
echo "${yellow}$SCRIPT: Aborting now${reset}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "${yellow}Would have run pandoc to make HTML for upload${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Make HTML for proof reading. All pictures referenced are now on the HPR
|
||||
# server (we ran 'do_asset_upload'), so we want to refer to them here.
|
||||
#
|
||||
# File $TMP2 contains the .pictures.mf contents with a header line; and it
|
||||
# contains data for the macros. It was created when we prepared the main HTML
|
||||
# for the database. We use $BASEURL again here because we want to reference
|
||||
# the pictures on the server.
|
||||
#
|
||||
# We use the awk-formatted file (now yq-formatted) in $TMP1 from earlier to do
|
||||
# this. At the end TMP3 contains Markdown for Pandoc.
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
# if [[ $FORMAT == 'plain_text' && -e $MANIFEST ]]; then
|
||||
if [[ $FORMAT =~ $FMTRE && -e $MANIFEST ]]; then
|
||||
tpage --pre_process="$PICTPL" \
|
||||
--define "piclist=$TMP2" \
|
||||
--define "prefix=${BASEURL}${SHOWID}/${SHOWID}/" \
|
||||
"$EXTRACT" > "$TMP3"
|
||||
else
|
||||
cat "$EXTRACT" > "$TMP3"
|
||||
fi
|
||||
|
||||
#
|
||||
# Generate complete HTML that we can proofread. We need metadata for this
|
||||
# stand-alone HTML which is in the form of YAML in this version.
|
||||
#
|
||||
# ----------------------------------------------------------------------
|
||||
# Original options below when using 'awk' to parse shownotes.txt:
|
||||
# --metadata="$(sed -n '/^#author:/{s/#//;p}' "$TMP1")" \
|
||||
# --metadata="$(sed -n '/^#title:/{s/#//;p}' "$TMP1")" \
|
||||
#
|
||||
# shellcheck disable=SC2086
|
||||
pandoc -f ${FROM}${POPTIONS} -t html5 --ascii \
|
||||
--standalone --template=hpr.html5 --no-highlight \
|
||||
-c https://hackerpublicradio.org/css/hpr.css \
|
||||
--metadata-file="$TMP1" -o "$FULLHTML" "$TMP3"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "$SCRIPT: ${green}Created shownotes/$SHOWID/${FULLHTML##*/}${reset}"
|
||||
else
|
||||
echo "$SCRIPT: ${red}Oops! Something went wrong making the full HTML! (line $LINENO)${reset}"
|
||||
fi
|
||||
else
|
||||
# Dry run
|
||||
echo "${yellow}Would have run pandoc to make HTML for proof reading${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Set the status for this show
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "converted" >> "$STATUS"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
149
Show_Submission/do_parse
Executable file
149
Show_Submission/do_parse
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_parse
|
||||
#
|
||||
# USAGE: ./do_parse <epno>
|
||||
#
|
||||
# DESCRIPTION: Run 'parse_JSON' on a given show
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.15
|
||||
# CREATED: 2016-05-14 14:21:34
|
||||
# REVISION: 2022-10-01 21:49:32
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
VERSION="0.0.15"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :fh opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) echo "Usage: $SCRIPT [-h] [-f] shownumber"; exit 0;;
|
||||
f) FORCE=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
FORCE="${FORCE:-0}"
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "[${SCRIPT} ${VERSION}] Usage: ${red}$SCRIPT shownumber${reset}"
|
||||
exit
|
||||
fi
|
||||
|
||||
show="$1"
|
||||
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${show}"
|
||||
LOGDIR="$BASENAME/logs"
|
||||
#PARSER="$BASENAME/parse_shownotes"
|
||||
PARSER="$BASENAME/parse_JSON"
|
||||
PARSELOG="$LOGDIR/${PARSER##*/}.log"
|
||||
#FROM="$BASENAME/shownotes/hpr${show}/hpr${show}_shownotes.txt"
|
||||
#FROM="$BASENAME/shownotes/hpr${show}/shownotes.txt"
|
||||
FROM="$SHOWDIR/shownotes.json"
|
||||
TO="$SHOWDIR/hpr${show}.out"
|
||||
TOTPL="$SHOWDIR/hpr%d.out"
|
||||
SLINK="$SHOWDIR/hpr${show}.html"
|
||||
FMT="$SHOWDIR/.format"
|
||||
REL="$SHOWDIR/.release"
|
||||
PICTURES="$SHOWDIR/.pictures"
|
||||
ASSETS="$SHOWDIR/.assets"
|
||||
ZIP="$SHOWDIR/.backup.zip"
|
||||
#JSONTPL="$SHOWDIR/hpr%d.json"
|
||||
SHOWLOG="$SHOWDIR/error.log"
|
||||
|
||||
#
|
||||
# Sanity checks
|
||||
#
|
||||
[ -e "$PARSER" ] || {
|
||||
echo "$SCRIPT: ${red}$PARSER not found${reset}"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ ! -e $FROM ]]; then
|
||||
echo "$SCRIPT: ${red}File not found: $FROM${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Allow overwriting of the output file if the -f option is given. Also, if
|
||||
# there's a link delete it so parse_shownotes can re-create it (we use '-ef'
|
||||
# to check that the files have the same inode).
|
||||
#
|
||||
if [[ $FORCE -eq 0 ]]; then
|
||||
if [[ -e $TO ]]; then
|
||||
echo "$SCRIPT: ${red}The output file $TO already exists${reset}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [[ $TO -ef $SLINK ]]; then
|
||||
rm -f "$SLINK"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ! -s $FROM ]]; then
|
||||
echo "$SCRIPT: ${red}Input file $FROM is empty${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Run the parser, don't validate, and use the show number argument. Read the
|
||||
# input file 'shownotes.txt' and generate an output file derived from the
|
||||
# template '$TOTPL'. Write a JSON version of the output and write the declared
|
||||
# format to a file for future reference.
|
||||
#
|
||||
# Updated 2021-02-23: Now we parse the incoming JSON file .shownotes.json'.
|
||||
# There's no validation and we don't write JSON output.
|
||||
#
|
||||
# $PARSER -novalid -ep "${show}" -in "$FROM" -show "$TOTPL" \
|
||||
# -json "$JSONTPL" -format="$FMT"
|
||||
$PARSER -ep "${show}" -in "$FROM" -show "$TOTPL" \
|
||||
-format="$FMT" -release="$REL" -pictures="$PICTURES" -assets="$ASSETS" \
|
||||
-zip="$ZIP"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -ne 0 ]]; then
|
||||
echo "$SCRIPT: ${red}Oops! Something went wrong!${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Make a reference copy of the output file
|
||||
#
|
||||
cp "$TO" "${TO%.out}.orig"
|
||||
|
||||
#
|
||||
# Grep the common log file for error reports relating to this show
|
||||
#
|
||||
grep -E "^$(date +%Y/%m/%d).+ \[ERROR\] $show" "$PARSELOG" >> "$SHOWLOG"
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
699
Show_Submission/do_pictures
Executable file
699
Show_Submission/do_pictures
Executable file
@@ -0,0 +1,699 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_pictures
|
||||
#
|
||||
# USAGE: ./do_pictures [options] <epno>
|
||||
#
|
||||
# DESCRIPTION: Process pictures associated with a show.
|
||||
#
|
||||
# If there are pictures associated with an episode they will
|
||||
# have been found amongst the show media, including unpacking
|
||||
# any archives. Their names will have been written to a file
|
||||
# which is called '.pictures' in the show directory. The files
|
||||
# themselves will have been moved to a directory called
|
||||
# 'uploads' in the show directory.
|
||||
# {{{ --- lengthy details ---
|
||||
# We no longer write files to the previous directory 'hpr<epno>'
|
||||
# because we will not make a tar file any more but will upload
|
||||
# directly to the server (elsewhere). We need the names because
|
||||
# we want to process them from the '.pictures' file. Processing
|
||||
# consists of renaming by replacing spaces with underscores and
|
||||
# using 'gm convert' to remove EXIF data. If the picture size is
|
||||
# too large a thumbnail is created, called
|
||||
# '<name>_thumbnail.<ext>'. If the notes are plain text (which
|
||||
# will be without links) then we will use `.pictures' as an
|
||||
# ordered list as we place them into the Markdown we create as
|
||||
# TT² macros. The list is reordered by asking the user to
|
||||
# resequence it with a list of reference numbers.
|
||||
#
|
||||
# Also for plain text and Markdown variant notes we create
|
||||
# a file called '.pictures.tt2' which contains the TT² commands
|
||||
# to add the pictures. When editing the notes this list is
|
||||
# shown in another window so the contents can be copied and
|
||||
# pasted. There are two TT² macros, 'pic1' for stand-alone
|
||||
# pictures and 'pic2' for pictures with thumbnails (clicking the
|
||||
# thumbnail causes the larger picture to be opened).
|
||||
#
|
||||
# Running `do_pandoc` on plain text and Markdown variant notes
|
||||
# will assemble the TT² macros from 'pic_definitions.tpl', and
|
||||
# the notes containing the statements in '.pictures.tt2' placed
|
||||
# as required.
|
||||
#
|
||||
# If the notes are not plain text then different paths are
|
||||
# taken:
|
||||
#
|
||||
# Markdown variants: any links will require editing to refer to
|
||||
# any filename changes, and if the picture needs a thumbnail
|
||||
# then this will need to be catered for. There will be no need
|
||||
# for `.pictures', `.pictures.tt2' or 'pic_definitions.tpl'
|
||||
# unless ther are no links already. The notes will be processed
|
||||
# with 'do_pandoc' which will cater for these differences.
|
||||
#
|
||||
# HTML: again, links might need adjusting, and as for Markdown,
|
||||
# no supplementary files will be required. The modified notes
|
||||
# will not be further processed before uploading.
|
||||
# }}}
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.2.3
|
||||
# CREATED: 2020-05-25 13:20:18
|
||||
# REVISION: 2024-02-22 14:32:03
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
# DIR=${0%/*}
|
||||
|
||||
VERSION="0.2.3"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions (make_file_list, range_parse, cleanup_temp)
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
# {{{ -- _usage --
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-d] [-D] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Processes pictures associated with an HPR show.
|
||||
|
||||
The script detects any pictures downloaded with an episode, looking for JPEG
|
||||
and PNG. It copies them to a sub-directory called 'hpr<epno>' (since that's
|
||||
the name of the directory where where they'll go on the server).
|
||||
|
||||
As it copies the files the script renames the copies if necessary, mainly by
|
||||
replacing spaces with underscores. The copying process uses 'gm convert' and
|
||||
removes EXIF data along the way. It also generates a thumbnail for each
|
||||
picture if the size warrants it, called 'NAME_thumbnail.ext'.
|
||||
|
||||
The script also makes a list of the newly named pictures in a file called
|
||||
'.pictures' which is used to refer to them in the notes (by position in the
|
||||
list). The order in which the pictures are processed and the list built up can
|
||||
be controlled by the user by the ordering of the presented enumerated list.
|
||||
|
||||
A file called '.pictures.tt2' contains the TT² commands to add the pictures.
|
||||
When editing the notes this list is shown in another window so the contents
|
||||
can be copied and pasted. There are two TT² macros, 'pic1' for stand-alone
|
||||
pictures and 'pic2' for pictures with thumbnails (clicking the thumbnail
|
||||
causes the larger picture to be opened).
|
||||
|
||||
Running 'do_pandoc' on the notes will assemble the TT² macros from
|
||||
'pic_definitions.tpl', and the notes containing the statements in
|
||||
'.pictures.tt2' which have been placed as required.
|
||||
|
||||
An 'index.html' file is created to allow the images to be visualised outside
|
||||
the notes.
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-d Select dry run mode
|
||||
-D Select debug mode (works the same; more output)
|
||||
-s Silent mode; suppress as many output messages as
|
||||
possible
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -d 3112
|
||||
./${SCRIPT} -D -d 3112
|
||||
./${SCRIPT} 3112
|
||||
./${SCRIPT} -s 3112
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
# }}}
|
||||
|
||||
# {{{ -- _silent -- _dryrun -- _DEBUG --
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _silent
|
||||
# DESCRIPTION: Output a message unless we're being silent
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_silent () {
|
||||
[ "$SILENT" == 1 ] && return
|
||||
for msg in "$@"; do
|
||||
printf '%s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _dryrun
|
||||
# DESCRIPTION: Output a dry run message
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_dryrun () {
|
||||
local prefix="Dry run: "
|
||||
for msg in "$@"; do
|
||||
printf '%9s%s\n' "$prefix" "$msg"
|
||||
prefix=
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _DEBUG
|
||||
# DESCRIPTION: Writes one or more message lines if in DEBUG mode
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_DEBUG () {
|
||||
[ "$DEBUG" == 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf 'D> %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
# }}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Debug mode, default off
|
||||
#
|
||||
DEBUG=0
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
DRYRUN=0 # not dry run mode by default
|
||||
SILENT=0 # not silent by default
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :hdDs opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) _usage;;
|
||||
d) DRYRUN=1;;
|
||||
D) DEBUG=1;;
|
||||
s) SILENT=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
#
|
||||
# Check there's an argument after removing any options. Abort if not
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "${red}Missing shownumber argument${reset}"
|
||||
_usage
|
||||
fi
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASEDIR/shownotes/hpr${1}"
|
||||
# RAWFILE="$SHOWDIR/shownotes.txt"
|
||||
JSONFILE="$SHOWDIR/shownotes.json"
|
||||
PICDIR="$SHOWDIR/uploads"
|
||||
# INDEXFILE="$PICDIR/index.html"
|
||||
FORMAT="$SHOWDIR/.format"
|
||||
ASSETS="$SHOWDIR/.assets" # Created in parse_JSON
|
||||
PICLIST="$SHOWDIR/.pictures" # Created in parse_JSON
|
||||
STATUS="$SHOWDIR/.status"
|
||||
|
||||
# ----
|
||||
# Files to be used by the TT² macros that build Markdown from plain
|
||||
# text notes.
|
||||
# ----
|
||||
|
||||
# MANIFEST contains a list of pictures and thumbnails, with blank lines if no
|
||||
# thumbnail.
|
||||
MANIFEST="$SHOWDIR/.pictures.mf"
|
||||
|
||||
# PICTPL contains TT² macro calls which can be cut and pasted into the plain
|
||||
# text notes
|
||||
PICTPL="$SHOWDIR/.pictures.tt2"
|
||||
|
||||
# ----
|
||||
|
||||
#
|
||||
# Constants
|
||||
#
|
||||
TNSIZE=800 # Thumbnail size
|
||||
TNW=$TNSIZE # Maximum width
|
||||
TNH=$((TNSIZE*2)) # Maximum height
|
||||
|
||||
#
|
||||
# Check the show directory exists
|
||||
#
|
||||
if [[ ! -d $SHOWDIR ]]; then
|
||||
echo "$SCRIPT: ${red}Directory $SHOWDIR not found${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Make temporary files and set traps to delete them.
|
||||
#
|
||||
# TMP1 - HTML header
|
||||
# TMP2 - HTML footer
|
||||
# TMP3 - call to TT² macro 'pic1' (make a plain picture link)
|
||||
# TMP4 - call to TT² macro 'pic2' (make a thumbnail link)
|
||||
#
|
||||
TMP1=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP2=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP3=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
TMP4=$(mktemp) || {
|
||||
echo "$SCRIPT: ${red}creation of temporary file failed!${reset}"
|
||||
exit 1
|
||||
}
|
||||
trap 'cleanup_temp $TMP1 $TMP2 $TMP3 $TMP4' SIGHUP SIGINT SIGPIPE SIGTERM EXIT
|
||||
|
||||
#
|
||||
# Parse these fields from the raw input file (shownotes.txt) into Bash
|
||||
# variables so we can make an index.html later.
|
||||
#
|
||||
# ----
|
||||
# NOTE: We're moving to the JSON file for show info. This could be parsed with
|
||||
# 'jq'. This filter seems reasonably close to our needs:
|
||||
#
|
||||
# command=$(jq -r '@sh "hostname=\(.host.Host_Name) title=\(.episode.Title) summary=\(.episode.Summary)"' $RAWFILE)
|
||||
# eval ${command:1:-1}
|
||||
#
|
||||
# The '@sh' format thing ensures the output is OK for the shell.
|
||||
# It seems 'jq' quotes the returned text (it's a string) which 'eval' doesn't
|
||||
# like, but giving 'eval' the string without the quotes (${command:1:-1})
|
||||
# makes this work.
|
||||
# Update: adding the '-r' option removes the enclosing double quotes
|
||||
# Use the '-f FILE' option to read the filter from a file.
|
||||
# ----
|
||||
#
|
||||
# Title='' Summary='' Host_Name=''
|
||||
# eval \
|
||||
# "$(sed -n '/^\(Title\|Summary\|Host_Name\):/{s/^\([^:]\+\):\t/\1="/;s/$/"/;p}' "$RAWFILE")"
|
||||
#
|
||||
Title='' Summary='' Host_Name=''
|
||||
jqprog="@sh \"Host_Name=\(.host.Host_Name) Title=\(.episode.Title) Summary=\(.episode.Summary)\""
|
||||
command=$(jq -r "$jqprog" "$JSONFILE")
|
||||
eval "${command}"
|
||||
|
||||
#
|
||||
# Make two HTML templates and two TT² templates. We do this in dry-run mode
|
||||
# too then throw them away!
|
||||
#
|
||||
# {{{
|
||||
cat > "$TMP1" <<ENDHTML1
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="generator" content="pandoc">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<meta name="author" content="$Host_Name">
|
||||
<title>$Title (HPR Show $1)</title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link rel="stylesheet" href="https://hackerpublicradio.org/css/hpr.css">
|
||||
</head>
|
||||
|
||||
<body id="home">
|
||||
<div id="container" class="shadow">
|
||||
<header>
|
||||
<h1 class="title">$Title (HPR Show $1)</h1>
|
||||
<h3 class="summary">$Summary</h3>
|
||||
<h3 class="author">$Host_Name</h3>
|
||||
<hr/>
|
||||
</header>
|
||||
|
||||
<main id="maincontent">
|
||||
<article>
|
||||
<h3 id="index">Index</h3>
|
||||
<ul>
|
||||
ENDHTML1
|
||||
|
||||
cat > "$TMP2" <<ENDHTML2
|
||||
</ul>
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
ENDHTML2
|
||||
|
||||
cat > "$TMP3" <<'ENDPIC1'
|
||||
[% row = piclist.$ind -%]
|
||||
[% pic1("$prefix",'*Title*',"$row.file") -%]
|
||||
|
||||
ENDPIC1
|
||||
|
||||
cat > "$TMP4" <<'ENDPIC2'
|
||||
[% row = piclist.$ind -%]
|
||||
[% pic2("$prefix",'*Title*',"$row.thumb","$row.file") -%]
|
||||
|
||||
ENDPIC2
|
||||
# }}}
|
||||
|
||||
#
|
||||
# Read the previously created list of pictures into array 'pix'
|
||||
#
|
||||
if [[ -e $PICLIST ]]; then
|
||||
declare -a pix
|
||||
mapfile -t pix < "$PICLIST"
|
||||
else
|
||||
echo "$SCRIPT: ${red}No pictures found!${reset}"
|
||||
echo "$SCRIPT: ${red}Show has no $PICLIST file!${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
_DEBUG 'Pictures:' "${pix[@]}"
|
||||
|
||||
#
|
||||
# The assets directory doesn't exist - something's wrong
|
||||
#
|
||||
if [[ ! -d $PICDIR ]]; then
|
||||
echo "$SCRIPT: ${red}No picture/asset directory found!${reset}"
|
||||
echo "$SCRIPT: ${red}Expected $PICDIR${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Look for the show note format file
|
||||
#
|
||||
# Formats offered by the web form on the HPR site:
|
||||
#
|
||||
# Keyword Explanation
|
||||
# ------- -----------
|
||||
# plain_text Plain text
|
||||
# html5 HTML5 (preferred)
|
||||
# markdown_standard Markdown (standard)
|
||||
# Markdown_GitHub Markdown (GitHub flavoured)
|
||||
# Markdown_Pandoc Markdown (Pandoc flavoured)
|
||||
# restructured_text RestructuredText
|
||||
# txt2tags txt2tags
|
||||
#
|
||||
NOTEFORMAT=
|
||||
if [[ -e $FORMAT ]]; then
|
||||
NOTEFORMAT="$(cat "$FORMAT")"
|
||||
else
|
||||
echo "$SCRIPT: ${red}No format file found!${reset}"
|
||||
echo "$SCRIPT: ${red}Expected $FORMAT${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Regex to match 'plain_text' or any Markdown variant
|
||||
#
|
||||
FMTRE='^(plain_text|[Mm]arkdown_)'
|
||||
|
||||
_DEBUG "Format: $NOTEFORMAT"
|
||||
|
||||
# ----
|
||||
# Check whether we're trying to run this script a second time. It will
|
||||
# potentially try and make thumbnails of thumbnails if we do!
|
||||
# ----
|
||||
if [[ -e $MANIFEST || -e $PICTPL || $(grep -c pictures "$STATUS") -gt 0 ]]; then
|
||||
echo "$SCRIPT: ${red}This doesn't seem to be the first run of this script!${reset}"
|
||||
echo "$SCRIPT: ${yellow}Delete $MANIFEST, $PICTPL and any thumbnails " \
|
||||
"and run it again - if you are certain about this!${reset}" | fmt -tu
|
||||
echo "$SCRIPT: ${red}Exiting...${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Start the TT² template and order the files (only for plain text and Markdown
|
||||
# variant shows)
|
||||
#
|
||||
declare -a opix
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "[%# Place at the top of the show notes -%]" > "$PICTPL"
|
||||
echo -e "[% ind = 0 -%]\n" >> "$PICTPL"
|
||||
else
|
||||
_dryrun "would have initialised $PICTPL"
|
||||
fi
|
||||
|
||||
#
|
||||
# Get the order of the picture files, assuming they aren't in a usable sort
|
||||
# order, and store them in 'opix'. The user can just type 1-10 (or whatever
|
||||
# the count is) to use them in the presented order. The default prompt
|
||||
# offers such an order for speed. They can abort the script at this point
|
||||
# if they type CTRL-D.
|
||||
#
|
||||
_silent "${blue}Building ordered picture list${reset}" " "
|
||||
if ! make_file_list pix opix; then
|
||||
echo "Script aborted"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
#
|
||||
# Fill the 'opix' array, but we don't care about ordering
|
||||
#
|
||||
mapfile -t -d ' ' opix < <(echo -n "${pix[@]}")
|
||||
fi
|
||||
|
||||
_DEBUG '(Possibly) re-ordered pictures:' "${opix[@]}"
|
||||
|
||||
#
|
||||
# Convert the original pictures and make thumbnails if needed. Thumbnails get
|
||||
# a name in the form 'NAME_thumbnail.EXT'. We record any thumbnails we create.
|
||||
# In plain text mode we write details to a new file called '.pictures.mf'
|
||||
# which is to be a manifest used by 'do_pandoc' to simplify the addition of
|
||||
# Markdown picture and thumbnail links to the notes.
|
||||
#
|
||||
pcount=1
|
||||
for pic in "${opix[@]}"; do
|
||||
#
|
||||
# The extension and name of the file we'll convert the original picture
|
||||
# into. No path here. We replace internal spaces with underscores.
|
||||
# NOTE: Space → underscore conversion has been done in parse_JSON
|
||||
#
|
||||
ext="${pic#*.}"
|
||||
newpic="${pic##*/}"
|
||||
# newpic="${newpic// /_}"
|
||||
|
||||
#
|
||||
# What is this picture and does it need a thumbnail? Collect the type,
|
||||
# width and height.
|
||||
#
|
||||
if [[ -e "$PICDIR/$pic" ]]; then
|
||||
geo=$(gm identify -format "%m:%w:%h/" "$PICDIR/$pic")
|
||||
RES=$?
|
||||
[ $RES -ne 0 ] && { echo "Aborting!"; exit $RES; }
|
||||
fi
|
||||
|
||||
#
|
||||
# Remove repetitions for GIFs and extract the type
|
||||
#
|
||||
geo="${geo%%/*}"
|
||||
type="${geo%%:*}"
|
||||
|
||||
#
|
||||
# Special actions for GIFs, only needed if the notes are plain text or
|
||||
# a Markdown variant
|
||||
#
|
||||
if [[ $type == 'GIF' ]]; then
|
||||
echo "GIF detected"
|
||||
# Cater for plain text and Markdown variant format notes
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "$PICDIR/$newpic" >> "$MANIFEST"
|
||||
echo "" >> "$MANIFEST"
|
||||
|
||||
if [[ $pcount -gt 1 ]]; then
|
||||
echo "[% ind = ind + 1 -%]" >> "$PICTPL"
|
||||
fi
|
||||
|
||||
# Add 'pic1' macro call
|
||||
cat "$TMP3" >> "$PICTPL"
|
||||
else
|
||||
_dryrun "Would have added ${yellow}$PICDIR/$newpic${reset} to" \
|
||||
"${yellow}$MANIFEST${reset}"
|
||||
_dryrun "would have added a blank line to ${yellow}$MANIFEST${reset}"
|
||||
|
||||
_dryrun "Would have added the ${yellow}pic1${reset} macro to" \
|
||||
"${yellow}$PICTPL${reset}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Nothing else needs to be done, so skip the rest of the loop
|
||||
#
|
||||
_silent "No image processing performed for $type file $pic"
|
||||
echo "----"
|
||||
((pcount++))
|
||||
continue
|
||||
else
|
||||
#
|
||||
# A simple image, get its size
|
||||
#
|
||||
geo="${geo#*:}"
|
||||
pw="${geo%:*}"
|
||||
ph="${geo#*:}"
|
||||
if [[ $pw -gt $TNW || $ph -gt $TNH ]]; then
|
||||
THUMB=1
|
||||
tn="${newpic%.*}_thumbnail.$ext"
|
||||
else
|
||||
THUMB=0
|
||||
tn=
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Include thumbnails or omit them
|
||||
#
|
||||
if [[ $THUMB -eq 1 ]]; then
|
||||
_DEBUG 'Thumbnail:' "${newpic}" "${ext}" "${tn}"
|
||||
|
||||
#
|
||||
# Convert originals to new path/file (or document it in dry-run mode)
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
gm convert "$PICDIR/$pic" -strip -auto-orient "$PICDIR/$newpic"
|
||||
gm convert "$PICDIR/$pic" -strip -auto-orient -resize $TNSIZE "$PICDIR/$tn"
|
||||
|
||||
#
|
||||
# Only make a (new) picture list if we have plain text or
|
||||
# a Markdown variant
|
||||
#
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
echo "$PICDIR/$newpic" >> "$MANIFEST"
|
||||
echo "$PICDIR/$tn" >> "$MANIFEST"
|
||||
|
||||
if [[ $pcount -gt 1 ]]; then
|
||||
echo "[% ind = ind + 1 -%]" >> "$PICTPL"
|
||||
fi
|
||||
# Add 'pic2' macro call
|
||||
cat "$TMP4" >> "$PICTPL"
|
||||
fi
|
||||
|
||||
#
|
||||
# All thumbnails are new so need to be recorded
|
||||
#
|
||||
echo "$tn" >> "$PICLIST"
|
||||
echo "$tn" >> "$ASSETS"
|
||||
|
||||
_silent "Converted picture ${yellow}$pic${reset} with thumbnail"
|
||||
else
|
||||
_dryrun \
|
||||
"Would have converted ${yellow}$pic${reset} to " \
|
||||
"${yellow}$newpic${reset} and ${yellow}$tn${reset} in " \
|
||||
"${yellow}$(trimpath "$PICDIR" 3)${reset}"
|
||||
|
||||
#
|
||||
# Only make a (new) picture list if we have plain text or
|
||||
# a Markdown variant
|
||||
#
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
_dryrun "Would have added ${yellow}$PICDIR/$newpic${reset} to" \
|
||||
"${yellow}$MANIFEST${reset}"
|
||||
_dryrun "would have added ${yellow}$PICDIR/$tn${reset} to" \
|
||||
"${yellow}$MANIFEST${reset}"
|
||||
|
||||
_dryrun "Would have added the ${yellow}pic2${reset} macro to" \
|
||||
"${yellow}$PICTPL${reset}"
|
||||
fi
|
||||
|
||||
echo "----"
|
||||
fi
|
||||
else
|
||||
_DEBUG 'No thumbnail:' "${newpic}" "${ext}"
|
||||
|
||||
#
|
||||
# Convert originals to new path/file (or document it)
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
gm convert "$PICDIR/$pic" -strip -auto-orient "$PICDIR/$newpic"
|
||||
|
||||
#
|
||||
# Only make a (new) picture list if we have plain text or
|
||||
# a Markdown variant
|
||||
#
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
echo "$PICDIR/$newpic" >> "$MANIFEST"
|
||||
echo "" >> "$MANIFEST"
|
||||
|
||||
if [[ $pcount -gt 1 ]]; then
|
||||
echo "[% ind = ind + 1 -%]" >> "$PICTPL"
|
||||
fi
|
||||
# Add 'pic1' macro call
|
||||
cat "$TMP3" >> "$PICTPL"
|
||||
fi
|
||||
|
||||
_silent "Converted picture ${yellow}$pic${reset} without thumbnail"
|
||||
else
|
||||
_dryrun "Would have converted ${yellow}$pic${reset} to " \
|
||||
"${yellow}$newpic${reset}"
|
||||
|
||||
#
|
||||
# Only make a (new) picture list if we have plain text or
|
||||
# a Markdown variant
|
||||
#
|
||||
if [[ $NOTEFORMAT =~ $FMTRE ]]; then
|
||||
_dryrun "Would have added ${yellow}$PICDIR/$newpic${reset} to" \
|
||||
"${yellow}$MANIFEST${reset}"
|
||||
_dryrun "would have added a blank line to ${yellow}$MANIFEST${reset}"
|
||||
|
||||
_dryrun "Would have added the ${yellow}pic1${reset} macro to" \
|
||||
"${yellow}$PICTPL${reset}"
|
||||
fi
|
||||
|
||||
echo "----"
|
||||
fi
|
||||
fi
|
||||
|
||||
((pcount++))
|
||||
done
|
||||
|
||||
#
|
||||
# Final steps - not wanted in dry run mode
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
#
|
||||
# If we made thumbnails the .assets and .pictures files will have been
|
||||
# updated. Clean these up here.
|
||||
#
|
||||
perl -i.BAK -ne 'print if ! $x{$_}++' "$PICLIST"
|
||||
perl -i.BAK -ne 'print if ! $x{$_}++' "$ASSETS"
|
||||
|
||||
#
|
||||
# Set the status for this show
|
||||
#
|
||||
echo "pictures" >> "$STATUS"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
73
Show_Submission/do_repair
Executable file
73
Show_Submission/do_repair
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_repair
|
||||
#
|
||||
# USAGE: ./do_repair <epno>
|
||||
#
|
||||
# DESCRIPTION: Run vim on the raw shownotes.txt file for a show and offer to
|
||||
# upload it to the server
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.1
|
||||
# CREATED: 2019-04-28 11:06:45
|
||||
# REVISION: 2019-04-28 11:26:09
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
VERSION="0.0.1"
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "[${SCRIPT} ${VERSION}]: Usage $SCRIPT shownumber"
|
||||
exit
|
||||
fi
|
||||
|
||||
BASENAME="/home/cendjm/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${1}"
|
||||
SHOWNOTES="$SHOWDIR/shownotes.txt"
|
||||
SNORIG="$SHOWDIR/shownotes.txt.orig"
|
||||
ORIGIN="$SHOWDIR/.origin"
|
||||
|
||||
#
|
||||
# Backup the original file
|
||||
#
|
||||
if [[ ! -e $SNORIG ]]; then
|
||||
cp "$SHOWNOTES" "$SNORIG"
|
||||
fi
|
||||
|
||||
upload_dir=$(cat "$ORIGIN")
|
||||
MD5_1=$(md5sum "$SHOWNOTES")
|
||||
|
||||
#
|
||||
# Edit the data from the form
|
||||
#
|
||||
vim "$SHOWNOTES"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "Edited $SHOWNOTES ok"
|
||||
|
||||
MD5_2=$(md5sum "$SHOWNOTES")
|
||||
if [[ $MD5_1 = "$MD5_2" ]]; then
|
||||
echo "The file was not changed"
|
||||
exit
|
||||
else
|
||||
echo "Copying $SHOWNOTES to upload/$upload_dir/shownotes.txt on the HPR server"
|
||||
echo "Copying $SNORIG to upload/$upload_dir/shownotes.txt.orig on the HPR server"
|
||||
scp -P 22074 "$SHOWNOTES" "$SNORIG" "hpr@hackerpublicradio.org:upload/$upload_dir/"
|
||||
fi
|
||||
else
|
||||
echo "Oops! Something went wrong!"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
308
Show_Submission/do_report
Executable file
308
Show_Submission/do_report
Executable file
@@ -0,0 +1,308 @@
|
||||
#!/bin/bash -
|
||||
# shellcheck disable=SC2317
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_report
|
||||
#
|
||||
# USAGE: ./do_report [-h] [-D] [-m] [-s] [-Y] epno path_to_shownotes.json
|
||||
#
|
||||
# DESCRIPTION: Script to be invoked after a show has been processed to make
|
||||
# a Matrix report.
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.8
|
||||
# CREATED: 2022-09-07 15:27:29
|
||||
# REVISION: 2023-06-01 17:58:09
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
VERSION="0.0.8"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#{{{ Functions: --- _usage --- _DEBUG --- _verbose --- _silent ---
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-D] [-m] [-s] [-Y] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Script to create and send a Matrix message about the processing of the show
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-D Run in debug mode where a lot more information is
|
||||
reported
|
||||
-m Monochrome mode - no colours
|
||||
-s Silent mode, output less text about actions
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -m 3112
|
||||
./${SCRIPT} -D 3112
|
||||
./${SCRIPT} 3112
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _DEBUG
|
||||
# DESCRIPTION: Writes one or more messages if in DEBUG mode. Each argument is
|
||||
# seen as a message and is written on a separate line.
|
||||
# References the global variable 'DEBUG' which is expected to be
|
||||
# True if debug output is wanted.
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_DEBUG () {
|
||||
[ "$DEBUG" == 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf 'D> %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _verbose
|
||||
# DESCRIPTION: Writes a message in verbose mode
|
||||
# PARAMETERS: $1 message
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_verbose () {
|
||||
[ "$VERBOSE" -eq 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf '%s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _silent
|
||||
# DESCRIPTION: Writes a message unless in silent mode
|
||||
# PARAMETERS: $1 message
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_silent () {
|
||||
[ "$SILENT" -eq 1 ] && return
|
||||
for msg in "$@"; do
|
||||
printf '%s\n' "$msg"
|
||||
done
|
||||
}
|
||||
#}}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
TPL="$BASENAME/shownotes/hpr%d/%s"
|
||||
Q2CSV="$BASENAME/query2csv"
|
||||
|
||||
[ -e "$Q2CSV" ] || { echo "Unable to find '$Q2CSV'; aborting"; exit 1; }
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
COLOUR=1 # use colours by default
|
||||
SILENT=0 # not silent by default
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :hDmsY opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) _usage;;
|
||||
D) DEBUG=1;;
|
||||
m) COLOUR=0;;
|
||||
s) SILENT=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
DEBUG=${DEBUG:-0}
|
||||
SILENT=${SILENT:-0}
|
||||
|
||||
#
|
||||
# Cancel colours if requested
|
||||
#
|
||||
if [[ $COLOUR -eq 0 ]]; then
|
||||
undefine_colours
|
||||
fi
|
||||
|
||||
#
|
||||
# Check the argument after any options
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "$SCRIPT: ${red}Usage: $SCRIPT shownumber${reset}"
|
||||
exit 1
|
||||
fi
|
||||
show="$1"
|
||||
# json="$2"
|
||||
|
||||
#
|
||||
# Compute paths to show-specific files
|
||||
#
|
||||
# shellcheck disable=SC2059
|
||||
{
|
||||
printf -v json "$TPL" "$show" "shownotes.json"
|
||||
printf -v assetfile "$TPL" "$show" ".assets"
|
||||
printf -v statusfile "$TPL" "$show" ".status"
|
||||
_DEBUG "Path to json = $json"
|
||||
}
|
||||
|
||||
#
|
||||
# Simplify checks
|
||||
#
|
||||
if [[ ! -e $json ]]; then
|
||||
echo "$SCRIPT: ${red}Unable to find $json${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Get the show details
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Extract JSON data and make Bash assignments which are then processed
|
||||
# with 'eval'.
|
||||
# Have to declare variables to avoid upsetting Shellcheck
|
||||
#
|
||||
declare host hostid email format
|
||||
jqscript='host=\(.host.Host_Name) hostid=\(.host.Host_ID) '
|
||||
jqscript+='email=\(.host.Host_Email) format=\(.metadata.POST.shownotes_format)'
|
||||
commands=$(jq -r "@sh \"$jqscript\"" "$json")
|
||||
eval "${commands}"
|
||||
|
||||
#
|
||||
# The zero hostid needs checking
|
||||
#
|
||||
if [ "$hostid" -eq 0 ]; then
|
||||
_silent "${yellow}Checking host id 0 is valid${reset}"
|
||||
# Look up in database
|
||||
hid=$($Q2CSV "select hostid from hosts where host like '%${host}%'")
|
||||
# Use the host id we found if the zero id is wrong
|
||||
if [[ -n $hid ]]; then
|
||||
_silent "${yellow}Found the host name $host with id $hid${reset}"
|
||||
hostid=$hid
|
||||
newhost=""
|
||||
email=" (using $email)"
|
||||
else
|
||||
newhost="new host "
|
||||
email=" ($email)"
|
||||
fi
|
||||
else
|
||||
newhost=""
|
||||
email=""
|
||||
fi
|
||||
|
||||
#
|
||||
# If the hostid is zero the email wasn't known (so maybe a new host) and we
|
||||
# didn't find the name in the database (so treat them as new). We only report
|
||||
# the email if it's a known host (by name) using a new address or if it's
|
||||
# a new host.
|
||||
#
|
||||
# if [ "$hostid" -eq 0 ]; then
|
||||
# newhost="new host "
|
||||
# email=" ($email)"
|
||||
# else
|
||||
# newhost=""
|
||||
# email=""
|
||||
# fi
|
||||
|
||||
#
|
||||
# If there are assets collect their names
|
||||
# NOTE: now not used except as a non-blank string
|
||||
#
|
||||
if [[ -e $assetfile ]]; then
|
||||
# The sed expression confuses ShellCheck
|
||||
# shellcheck disable=SC2016
|
||||
assets="$(sort "$assetfile" | sed -ne 'H;${x;s/\n//;s/\n/, /g;p}')"
|
||||
else
|
||||
assets=
|
||||
fi
|
||||
|
||||
#
|
||||
# Report the settings in debug mode
|
||||
#
|
||||
_DEBUG "Show number = $show" \
|
||||
"Host name = $host" \
|
||||
"Host ID = $hostid" \
|
||||
"Host email = $email" \
|
||||
"Assets = $assets"
|
||||
|
||||
#
|
||||
# Handle backticks in the host string (Rho`n/Roan made me do it!)
|
||||
#
|
||||
if grep -q -E '`' <<<"$host"; then
|
||||
# shellcheck disable=SC2001 disable=SC2016
|
||||
host=$(sed -e 's/^\([0-9A-Za-z_`-]\+\)$/`\1`/' <<<"$host")
|
||||
fi
|
||||
|
||||
#
|
||||
# Generate the message we want to send
|
||||
#
|
||||
# shellcheck disable=SC2016
|
||||
printf -v message 'Processed %s from %s`%s`%s. Format is *%s*.' \
|
||||
"$show" "$newhost" "$host" "$email" "$format"
|
||||
if [[ -n $assets ]]; then
|
||||
# We have assets but were they sent?
|
||||
if grep -q -E '^assets' "$statusfile"; then
|
||||
message+=" Assets uploaded"
|
||||
else
|
||||
_silent "${yellow}Note: assets were found but not uploaded${reset}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Send it, after checking
|
||||
#
|
||||
echo "Will run the following command:"
|
||||
echo "${green}matrix-commander -z -m '$message'${reset}"
|
||||
if yes_no 'OK to proceed? %s ' 'No'; then
|
||||
command="matrix-commander -z -m '$message'"
|
||||
eval "$command" || \
|
||||
{ echo "Failed to invoke the command!"; exit 1; }
|
||||
|
||||
#
|
||||
# Change state/log what we did, but only if we actually did it
|
||||
#
|
||||
echo "reported" >> "$statusfile" || \
|
||||
{ echo "Failed to update $statusfile"; exit 1; }
|
||||
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
1
Show_Submission/do_reserve
Symbolic link
1
Show_Submission/do_reserve
Symbolic link
@@ -0,0 +1 @@
|
||||
do_state_change
|
87
Show_Submission/do_show
Executable file
87
Show_Submission/do_show
Executable file
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_show
|
||||
#
|
||||
# USAGE: ./do_show <epno>
|
||||
#
|
||||
# DESCRIPTION: Displays the raw show details of a given show. To be run after
|
||||
# 'sync_hpr' and 'copy_shownotes'. The resulting file will be
|
||||
# called 'shownotes.json' in a directory called 'hpr${epno}'.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: The target file used to be called 'hpr${epno}_shownotes.txt'
|
||||
# but we simplified it so we can use 'rsync' for copying files.
|
||||
# 2022-12-17: stoped referring to this old file, since now we
|
||||
# only use shownotes.json.
|
||||
# 2023-01-07: Refactored to avoid nested tests (though I don't
|
||||
# find them confusing in this script).
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.6
|
||||
# CREATED: 2016-12-15 09:51:09
|
||||
# REVISION: 2023-01-07 14:51:41
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
VERSION='0.0.6'
|
||||
|
||||
#
|
||||
# Check the argument after any options
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "$SCRIPT ($VERSION); Usage: $SCRIPT shownumber"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${1}"
|
||||
FROM="$SHOWDIR/shownotes.json"
|
||||
PLACEHOLDER="$SHOWDIR/.dummy"
|
||||
|
||||
#
|
||||
# Not a show, just a placeholder
|
||||
#
|
||||
if [[ -e $PLACEHOLDER ]]; then
|
||||
echo "$SCRIPT: This directory contains a placeholder only; aborting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# The JSON file isn't there
|
||||
#
|
||||
if [[ ! -e $FROM ]]; then
|
||||
echo "$SCRIPT: File not found: $FROM"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# File is there but empty!
|
||||
#
|
||||
if [[ ! -s $FROM ]]; then
|
||||
echo "$SCRIPT: File $FROM is empty"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Display a subset of the JSON
|
||||
#
|
||||
jqprog="{ host: .host, episode: .episode, "
|
||||
jqprog+="format: .metadata.POST.shownotes_format, "
|
||||
jqprog+="series: .metadata.POST.series, "
|
||||
jqprog+="media: .metadata.FILES.media_files.name }"
|
||||
jq -C "$jqprog" "$FROM" | less -R
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
||||
|
302
Show_Submission/do_state_change
Executable file
302
Show_Submission/do_state_change
Executable file
@@ -0,0 +1,302 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_state_change
|
||||
#
|
||||
# USAGE: ./do_state_change [-h] [-D] [-m] [-s] [-Y] <epno>
|
||||
#
|
||||
# DESCRIPTION: Script to be invoked via symlinks to perform related tasks
|
||||
# relating to show states.
|
||||
#
|
||||
# - When called as 'do_reserve' toggles a '.reserved' marker.
|
||||
# - When called as 'do_block' creates the directory if necessary
|
||||
# and makes a dummy 'shownotes.json' as well as a file called
|
||||
# '.dummy'. Doesn't delete any of this since other software
|
||||
# will tidy things.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.6
|
||||
# CREATED: 2021-06-05 22:04:26
|
||||
# REVISION: 2024-02-06 15:36:02
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
VERSION="0.0.6"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-D] [-m] [-s] [-Y] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Script to be invoked via symlinks to perform related tasks relating to show states
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-D Run in debug mode where a lot more information is
|
||||
reported
|
||||
-m Monochrome mode - no colours
|
||||
-s Silent mode, output less text about actions
|
||||
-Y Assume 'Yes' in answer to the prompt
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -m 3112
|
||||
./${SCRIPT} -D 3112
|
||||
./${SCRIPT} 3112
|
||||
./${SCRIPT} -Y 3112
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: exists
|
||||
# DESCRIPTION: Determines wheher all paths given as arguments exist
|
||||
# PARAMETERS: List of paths
|
||||
# RETURNS: True if they all exist, otherwise false
|
||||
#===============================================================================
|
||||
exists () {
|
||||
|
||||
for path in "$@"; do
|
||||
if [[ ! -e $path ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _DEBUG
|
||||
# DESCRIPTION: Writes one or more messages if in DEBUG mode. Each argument is
|
||||
# seen as a message and is written on a separate line.
|
||||
# References the global variable 'DEBUG' which is expected to be
|
||||
# True if debug output is wanted.
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_DEBUG () {
|
||||
[ "$DEBUG" == 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf 'D> %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _verbose
|
||||
# DESCRIPTION: Writes a message in verbose mode
|
||||
# PARAMETERS: $1 message
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_verbose () {
|
||||
[ "$VERBOSE" -eq 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf '%s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _silent
|
||||
# DESCRIPTION: Writes a message unless in silent mode
|
||||
# PARAMETERS: $1 message
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_silent () {
|
||||
[ "$SILENT" -eq 1 ] && return
|
||||
for msg in "$@"; do
|
||||
printf '%s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
TPL="$BASENAME/shownotes/hpr%d/%s"
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
COLOUR=1 # use colours by default
|
||||
YES=0 # prompt for yes/no by default
|
||||
TOGGLE=0 # marker can't be removed by default
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :hDmsY opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) _usage;;
|
||||
D) DEBUG=1;;
|
||||
m) COLOUR=0;;
|
||||
s) SILENT=1;;
|
||||
Y) YES=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
DEBUG=${DEBUG:-0}
|
||||
SILENT=${SILENT:-0}
|
||||
|
||||
#
|
||||
# Cancel colours if requested
|
||||
#
|
||||
if [[ $COLOUR -eq 0 ]]; then
|
||||
undefine_colours
|
||||
fi
|
||||
|
||||
#
|
||||
# Determine actions depending on how the script was called. Save filenames in
|
||||
# an array.
|
||||
#
|
||||
declare -a MK MFILES
|
||||
case "${SCRIPT#*/}" in
|
||||
do_reserve)
|
||||
MK+=('.reserved')
|
||||
state='reserved'
|
||||
TOGGLE=1
|
||||
;;
|
||||
do_block)
|
||||
echo "Blocking of pending shows is not needed any more."
|
||||
echo "See Journal for details (2024-02-06)"
|
||||
exit
|
||||
# MK+=('shownotes.json')
|
||||
# MK+=('.dummy')
|
||||
# state='blocked'
|
||||
# TOGGLE=0
|
||||
;;
|
||||
*)
|
||||
echo "Don't call this script directly; use one of its soft links"
|
||||
echo "D> $0 $*"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
#
|
||||
# Check the argument after any options
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "$SCRIPT: ${red}Usage: $SCRIPT shownumber${reset}"
|
||||
exit
|
||||
fi
|
||||
show="$1"
|
||||
|
||||
#
|
||||
# I used 'hpr4065' by mistake today, so we need to check the show specification
|
||||
#
|
||||
if [[ $show =~ ^(hpr)?([0-9]+)$ ]]; then
|
||||
printf -v show '%04d' "${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "$SCRIPT: ${red}Invalid show specification: $show${reset}"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Build the path(s) to the marker(s) in an array
|
||||
#
|
||||
# shellcheck disable=SC2059
|
||||
for fn in "${MK[@]}"; do
|
||||
printf -v path "$TPL" "$show" "$fn"
|
||||
MFILES+=("$path")
|
||||
done
|
||||
|
||||
#
|
||||
# Path to the show directory
|
||||
#
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${show}"
|
||||
|
||||
#
|
||||
# Report the settings in debug mode
|
||||
#
|
||||
_DEBUG "Called as = $0" \
|
||||
"Show number = $show" \
|
||||
"MK = ${MK[*]}" \
|
||||
"state = $state" \
|
||||
"TOGGLE = $TOGGLE" \
|
||||
"MFILES = ${MFILES[*]}" \
|
||||
"SHOWDIR = $SHOWDIR"
|
||||
|
||||
#
|
||||
# We need a show directory. If it doesn't exist then we'll create it because
|
||||
# other scripts will use it.
|
||||
#
|
||||
if [[ ! -d $SHOWDIR ]]; then
|
||||
echo "${red}There is no directory for show $show${reset}"
|
||||
|
||||
#
|
||||
# If the -Y option was not chosen ask with 'yes_no'. It -Y was chosen
|
||||
# we're to go ahead regardless. This relies on the fact that Bash
|
||||
# "short-circuits" logical expressions like this.
|
||||
#
|
||||
if [[ $YES -eq 1 ]] || yes_no 'Create directory? %s ' 'N'; then
|
||||
mkdir "$SHOWDIR"
|
||||
_silent "${green}Directory created for show $show${reset}"
|
||||
else
|
||||
_silent "${yellow}Not changed${reset}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# If the marker exists and we can toggle it, we'll do so. If no toggle, we
|
||||
# report the marker presence or set it as appropriate.
|
||||
#
|
||||
if exists "${MFILES[@]}"; then
|
||||
if [[ $TOGGLE -eq 1 ]]; then
|
||||
_silent "${yellow}Show $show has a '$state' marker${reset}"
|
||||
if [[ $YES -eq 1 ]] || yes_no 'Remove marker? %s ' 'N'; then
|
||||
rm -f "${MFILES[@]}"
|
||||
_silent "${green}Removed '$state' marker for show $show${reset}"
|
||||
else
|
||||
_silent "${yellow}Not changed${reset}"
|
||||
fi
|
||||
else
|
||||
echo "${red}Show $show is already marked '$state'${reset}"
|
||||
fi
|
||||
else
|
||||
_silent "${yellow}Show $show has no '$state' marker${reset}"
|
||||
touch "${MFILES[@]}"
|
||||
_silent "${green}Marked show $show as '$state'${reset}"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
227
Show_Submission/do_update_reservations
Executable file
227
Show_Submission/do_update_reservations
Executable file
@@ -0,0 +1,227 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_update_reservations
|
||||
#
|
||||
# USAGE: ./do_update_reservations <epno>
|
||||
#
|
||||
# DESCRIPTION: Script to update the status in the 'reservations' table after
|
||||
# a show has been processed.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.6
|
||||
# CREATED: 2022-04-11 09:36:21
|
||||
# REVISION: 2023-06-14 23:24:42
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
VERSION="0.0.6"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#{{{ Functions: --- _usage ---
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-d] [-m] shownumber
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Script to update the status in the 'reservations' table after a show has been
|
||||
processed.
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-d Dry-run mode. Reports what it will do but doesn't do it
|
||||
-m Monochrome mode - no colours
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -m 3112
|
||||
./${SCRIPT} -d 3112
|
||||
./${SCRIPT} -dm 3112
|
||||
./${SCRIPT} 3112
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
#}}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
BASECOM='curl -K ./.hpradmin_curlrc -s'
|
||||
URL="https://hub.hackerpublicradio.org/cms/status.php"
|
||||
QUERY="${BASECOM} ${URL}"
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
COLOUR=1 # use colours by default
|
||||
DRYRUN=0 # live mode by default
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :hdm opt
|
||||
do
|
||||
case "${opt}" in
|
||||
h) _usage;;
|
||||
d) DRYRUN=1;;
|
||||
m) COLOUR=0;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
#
|
||||
# Cancel colours if requested
|
||||
#
|
||||
if [[ $COLOUR -eq 0 ]]; then
|
||||
undefine_colours
|
||||
fi
|
||||
|
||||
#
|
||||
# Check the argument after any options
|
||||
#
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "$SCRIPT: ${red}Usage: $SCRIPT shownumber${reset}"
|
||||
exit
|
||||
fi
|
||||
|
||||
epno="$1"
|
||||
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${epno}"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
|
||||
#
|
||||
# Check the show in question exists
|
||||
#
|
||||
if [[ ! -d $SHOWDIR ]]; then
|
||||
echo "$SHOWDIR not found, can't continue"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Check the show is in the correct state of local processing
|
||||
#
|
||||
declare -a states
|
||||
states+=( '+dir' )
|
||||
if [[ -e "$SHOWDIR/shownotes.json" ]]; then
|
||||
states+=( '+shownotes' )
|
||||
fi
|
||||
if [[ -e "$SHOWDIR/hpr${epno}.html" ]]; then
|
||||
states+=( '+processed' )
|
||||
fi
|
||||
if [[ -e "$SHOWDIR/.uploaded" ]]; then
|
||||
states+=( '+uploaded' )
|
||||
fi
|
||||
echo "${green}Current state: ${states[*]}${reset}"
|
||||
|
||||
if ! grep -q -E '\+uploaded' <<<"${states[@]}"; then
|
||||
echo "The show is not in the +uploaded state"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Run the query with 'curl' and filter out this episode
|
||||
#
|
||||
reply="$(${QUERY} | grep -E "^[^,]+,$epno" )"
|
||||
# echo "D> $reply"
|
||||
|
||||
#
|
||||
# If we found the episode in the list we need to test further
|
||||
#
|
||||
if [[ -n $reply ]]; then
|
||||
echo "Found $epno in 'reservations'"
|
||||
|
||||
#
|
||||
# Get the current state in the database by parsing the line returned.
|
||||
# Since Ken changed this out of the blue we now have:
|
||||
# 1. Epoch timestamp
|
||||
# 2. Episode number
|
||||
# 3. Episode date
|
||||
# 4. Key
|
||||
# 5. Status
|
||||
# 6. Email
|
||||
#
|
||||
if [[ $reply =~ ^([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),.*$ ]]; then
|
||||
state="${BASH_REMATCH[5]}"
|
||||
|
||||
#
|
||||
# If it's aready in the desired state we're finished, otherwise we'll
|
||||
# set the new state
|
||||
#
|
||||
if [[ $state == 'METADATA_PROCESSED' ]]; then
|
||||
echo "Already marked ${blue}${state}${reset}"
|
||||
else
|
||||
echo "Ready for marking"
|
||||
command="${BASECOM} ${URL}?ep_num=${epno}&status=METADATA_PROCESSED"
|
||||
if [[ $DRYRUN -eq 1 ]]; then
|
||||
echo -e "Dry-run: would have run\n${yellow}$command${reset}"
|
||||
else
|
||||
echo "${yellow}$command${reset}"
|
||||
$command
|
||||
|
||||
#
|
||||
# Change state/log what we did
|
||||
#
|
||||
echo "database" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
echo "Couldn't parse '$reply'; aborting"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
#
|
||||
# We have no record of this show locally
|
||||
#
|
||||
echo "Not found $epno"
|
||||
fi
|
||||
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
||||
|
390
Show_Submission/do_upload
Executable file
390
Show_Submission/do_upload
Executable file
@@ -0,0 +1,390 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_upload
|
||||
#
|
||||
# USAGE: ./do_upload <epno> [files...]
|
||||
#
|
||||
# DESCRIPTION: Uploads the processed HTML back to the HPR server. Also
|
||||
# capable of uploading supplementary files such as a missed
|
||||
# audio file, pictures, etc.
|
||||
#
|
||||
# There are two main types of uploads:
|
||||
# 1) Extracted and edited show notes to go back to the server as
|
||||
# HTML. Possiblly altered 'shotnotes.txt' as a means of
|
||||
# fixing errors in the title, summary or tags.
|
||||
# 2) Assets collected by 'parse_JSON' and possibly changed by
|
||||
# 'do_pictures' if there are pictures provided and referenced
|
||||
# in the notes. Any archives will have had files extracted so
|
||||
# that there is much less to do on the server.
|
||||
#
|
||||
# Assets are sent to a directory under '~hpr/www/eps/' named
|
||||
# 'hprNNNN'. This is created here and files copied with 'rsync'.
|
||||
# There is a local directory in the show directory which is
|
||||
# called 'uploads'. Unless the host has provided archives to be
|
||||
# downloaded with their show we will not send such files to the
|
||||
# server. We ask that such files be enclosed in an archive when
|
||||
# sent - so we never extract the archives we have extracted from
|
||||
# the sent archives!
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: 2021-03-15: Added code to place the "assets" in the final
|
||||
# directory on the server. This will be 'www/eps/hprNNNN/'.
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.1.2
|
||||
# CREATED: 2017-03-06 19:11:51
|
||||
# REVISION: 2023-06-14 23:12:04
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
# DIR=${0%/*}
|
||||
|
||||
VERSION="0.1.2"
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: ${red}Unable to source functions${reset}"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
# {{{ --- Functions: usage, dryrun ---
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _usage
|
||||
# DESCRIPTION: Report usage
|
||||
# PARAMETERS: None
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_usage () {
|
||||
cat >$STDOUT <<-endusage
|
||||
Usage: ./${SCRIPT} [-h] [-a] [-d] [-D] shownumber [file1 file2...]
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
Uploads the processed HTML back to the HPR server. Also
|
||||
capable of uploading supplementary files such as a missed
|
||||
audio file.
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-a Send any assets to the show sub-directory on the HPR
|
||||
server
|
||||
-d Select dry run mode
|
||||
-D Select debug mode (works the same; more output)
|
||||
|
||||
Arguments:
|
||||
shownumber
|
||||
list of files to be uploaded in addition
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -d 3099
|
||||
./${SCRIPT} -d 3123 otherfile1.txt otherfile2.dat
|
||||
|
||||
endusage
|
||||
exit
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _dryrun
|
||||
# DESCRIPTION: Output a dry run message
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_dryrun () {
|
||||
for msg in "$@"; do
|
||||
printf 'Dry run: %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: trimpath
|
||||
# DESCRIPTION: Trim a file path to its last few components for display
|
||||
# PARAMETERS: $1 - path to trim
|
||||
# $2 - number of elements to retain
|
||||
# RETURNS: Trimmed path
|
||||
#===============================================================================
|
||||
# trimpath () {
|
||||
# local path=${1:?Usage: mpath path elements}
|
||||
# local elements=${2:?Usage: mpath path elements}
|
||||
# local -a arr1 arr2
|
||||
#
|
||||
# # Split the path
|
||||
# # IFS='/' arr1=($path)
|
||||
# IFS='/' mapfile -d'/' -t arr1 <<<"$path"
|
||||
#
|
||||
# if [[ ${#arr1[@]} -gt $elements ]]; then
|
||||
# # Put the last elements in another array
|
||||
# # arr2=(${arr1[@]: -$elements})
|
||||
# mapfile -t arr2 < <(printf '%s\n' "${arr1[@]: -$elements}")
|
||||
#
|
||||
# # return the second array interleaved with '/'
|
||||
# echo "${arr2[*]/#/}"
|
||||
# else
|
||||
# echo "$path"
|
||||
# fi
|
||||
# }
|
||||
|
||||
# }}}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
ASSETUPLOAD=0
|
||||
DEBUG=0
|
||||
DRYRUN=0
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
while getopts :ahdD opt
|
||||
do
|
||||
case "${opt}" in
|
||||
a) ASSETUPLOAD=1;;
|
||||
h) _usage;;
|
||||
d) DRYRUN=1;;
|
||||
D) DEBUG=1;;
|
||||
?) echo "$SCRIPT: Invalid option; aborting"; exit 1;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND - 1))
|
||||
|
||||
#
|
||||
# Check there's at least one argument after removing any options. Abort if not
|
||||
#
|
||||
if [[ $# -eq 0 ]]; then
|
||||
echo "Missing argument(s)"
|
||||
_usage
|
||||
fi
|
||||
|
||||
#
|
||||
# Paths to files
|
||||
#
|
||||
# 2021-02-12 Not using the .format file any more
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
LOCAL_UPLOAD="$BASEDIR/upload"
|
||||
SHOWDIR="$BASEDIR/shownotes/hpr${1}"
|
||||
FROM="$SHOWDIR/hpr${1}.html"
|
||||
# FORMAT="$SHOWDIR/.format"
|
||||
ORIGIN="$SHOWDIR/.origin"
|
||||
UPLOADED="$SHOWDIR/.uploaded"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
|
||||
# If there are HTML errors
|
||||
REPORT="$SHOWDIR/errors.txt"
|
||||
|
||||
# For differences
|
||||
# 2021-02-12 $RE removed since we find differences for all formats
|
||||
RAWNOTES="$SHOWDIR/hpr${1}.orig"
|
||||
PROCESSED="$SHOWDIR/hpr${1}.out"
|
||||
# RE='plain_text|markdown_standard|Markdown_GitHub|Markdown_Pandoc|restructured_text|txt2tags'
|
||||
DIFFFILE="$SHOWDIR/hpr${1}.diff"
|
||||
|
||||
# PORT=22074
|
||||
PORT=22
|
||||
|
||||
#
|
||||
# Asset locations for upload
|
||||
#
|
||||
# If there are supplementary files
|
||||
# SUPPDIR="$SHOWDIR/hpr${1}"
|
||||
TARFILE="$SHOWDIR/hpr${1}.tgz"
|
||||
PICLIST="$SHOWDIR/.pictures"
|
||||
ASSETLIST="$SHOWDIR/.assets"
|
||||
|
||||
# Where any "assets" (pictures, scripts, etc) come from and will go on the server
|
||||
LOCAL_ASSETDIR="$SHOWDIR/uploads"
|
||||
REMOTE_ASSETDIR="www/eps/hpr${1}"
|
||||
CMDTPL='ssh hpr@hackerpublicradio.org -p %d %s'
|
||||
|
||||
# Use to build the rsync command, assuming the tunnel is open:
|
||||
# rsync -a -e 'ssh -p 22' $SHOWDIR/hpr3656/ hpr@hpr:www/eps/hpr3656/
|
||||
#
|
||||
RSYNCTPL="rsync -a -e 'ssh -p %d' %s hpr@hpr:www/eps/%s"
|
||||
|
||||
# Did the following by hand for uploading
|
||||
# ssh -p $PORT hpr@hpr 'mkdir ~/www/eps/hpr3685'
|
||||
# scp -P $PORT shownotes/hpr3685/Budget_sample_2022-9-9.ods hpr@hpr:www/eps/hpr3685/
|
||||
|
||||
EXTRA=0
|
||||
|
||||
#
|
||||
# Is there a marker to indicate the show has already been uploaded? This
|
||||
# isn't an error, but a warning is in order.
|
||||
#
|
||||
if [[ -e $UPLOADED ]]; then
|
||||
echo "$SCRIPT: ${yellow}Warning - the notes have already been uploaded${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check we actually have a file to upload
|
||||
#
|
||||
if [[ ! -e $FROM ]]; then
|
||||
echo "$SCRIPT: ${red}File not found: ${FROM}${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# If there's an error report then add it to the list of supplementary files
|
||||
# (which may be none)
|
||||
#
|
||||
if [[ -e $REPORT ]]; then
|
||||
_DEBUG "Error report being added"
|
||||
set -- "$@" "${REPORT##*/}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Deal with the raw notes extracted by 'parse_shownotes' and saved in
|
||||
# hprXXXX.orig and the edited notes in hprXXXX.out
|
||||
#
|
||||
# 2021-02-12 Now using the same code for all formats
|
||||
#
|
||||
# if [[ -e $RAWNOTES && -e $PROCESSED ]]; then
|
||||
# FMT="$(cat "$FORMAT")"
|
||||
# if [[ $FMT =~ $RE ]]; then
|
||||
# diff "$RAWNOTES" "$PROCESSED" > "$DIFFFILE"
|
||||
# if [[ -s $DIFFFILE ]]; then
|
||||
# set -- "$@" "${DIFFFILE##*/}"
|
||||
# else
|
||||
# echo "$SCRIPT: ${red}No differences found${reset}"
|
||||
# fi
|
||||
# fi
|
||||
# fi
|
||||
|
||||
if [[ -e $RAWNOTES && -e $PROCESSED ]]; then
|
||||
_DEBUG "Differences being determined:" "$RAWNOTES vs $PROCESSED"
|
||||
diff "$RAWNOTES" "$PROCESSED" > "$DIFFFILE"
|
||||
if [[ -s $DIFFFILE ]]; then
|
||||
_DEBUG "Differences found"
|
||||
set -- "$@" "${DIFFFILE##*/}"
|
||||
else
|
||||
_DEBUG "Differences file is empty"
|
||||
echo "$SCRIPT: ${red}No differences found${reset}"
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# If there's a picture list and a tarfile has been made add the latter to the
|
||||
# upload list
|
||||
# TODO: Not needed in next iteration
|
||||
#
|
||||
if [[ -e $PICLIST && -e $TARFILE ]]; then
|
||||
_DEBUG "Tar file being added"
|
||||
set -- "$@" "${TARFILE##*/}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check any supplementary files in the argument list (added by the user or
|
||||
# this script)
|
||||
#
|
||||
if [[ $# -gt 1 ]]; then
|
||||
EXTRA=1
|
||||
shift # Delete argument 1, the show number
|
||||
for arg; do
|
||||
if [[ ! -e "$SHOWDIR/$arg" ]]; then
|
||||
echo "$SCRIPT: ${red}File missing: $SHOWDIR/$arg${reset}"
|
||||
echo "Can't continue"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "$SCRIPT: ${blue}Number of supplementary files to upload: $#${reset}"
|
||||
fi
|
||||
|
||||
#
|
||||
# Check we have a record of where the files are to go
|
||||
#
|
||||
if [[ ! -e $ORIGIN ]]; then
|
||||
echo "$SCRIPT: ${red}Unable to find the .origin file${reset}"
|
||||
echo "(This holds the directory on the server where the files are to be sent)"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Check there's a local copy of the upload directory. If not, then the rsync
|
||||
# run has deleted it because the directory on the server has been deleted.
|
||||
# This implies the show has been processed on the server.
|
||||
#
|
||||
upload_dir="$(cat "$ORIGIN")"
|
||||
_DEBUG "upload_dir = $upload_dir"
|
||||
if [[ ! -e "$LOCAL_UPLOAD/$upload_dir" ]]; then
|
||||
echo "$SCRIPT: ${red}The upload directory seems to have been deleted${reset}"
|
||||
echo "(This happens after the show is processed on the server)"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Upload the processed show notes
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "Copying $FROM to upload/$upload_dir/shownotes.html on the HPR server"
|
||||
scp -P $PORT "$FROM" "hpr@hackerpublicradio.org:upload/$upload_dir/shownotes.html"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "$SCRIPT: ${green}Uploaded successfully${reset}"
|
||||
touch "$UPLOADED"
|
||||
else
|
||||
echo "$SCRIPT: ${red}Oops! Something went wrong!${reset}"
|
||||
echo "$SCRIPT: Aborting now"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
_dryrun "would have copied $FROM to the server"
|
||||
fi
|
||||
|
||||
#
|
||||
# Handle supplementary files if there are any. The remaining arguments are
|
||||
# these file names without any path information. Variable 'EXTRA' is
|
||||
# true/false if there are/are not extra arguments. If there are we have
|
||||
# already deleted the first argument and we've checked the existence of the
|
||||
# file(s).
|
||||
#
|
||||
if [[ $EXTRA -eq 1 ]]; then
|
||||
_DEBUG "Uploading supplementary files"
|
||||
for arg; do
|
||||
FROM="$SHOWDIR/$arg"
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "Copying $FROM to upload/$upload_dir/$arg on the HPR server"
|
||||
scp -P $PORT "$FROM" "hpr@hackerpublicradio.org:upload/$upload_dir/$arg"
|
||||
RES=$?
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "$SCRIPT: ${green}Uploaded ${arg} successfully${reset}"
|
||||
else
|
||||
echo "$SCRIPT: ${red}Oops! Something went wrong with ${arg}!${reset}"
|
||||
echo "$SCRIPT: Aborting now"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
_dryrun "would have copied $FROM to the server"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
#
|
||||
# Update the status file
|
||||
#
|
||||
if [[ $DRYRUN -eq 0 ]]; then
|
||||
echo "uploaded" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21:fdm=marker
|
170
Show_Submission/do_vim
Executable file
170
Show_Submission/do_vim
Executable file
@@ -0,0 +1,170 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: do_vim
|
||||
#
|
||||
# USAGE: ./do_vim <epno>
|
||||
#
|
||||
# DESCRIPTION: Run vim on notes for a show
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: The validate_html script failed because the HTML::Valid module
|
||||
# wasn't visible but the edit went ahead regardless. How to
|
||||
# handle such errors cleanly? Not found an answer yet.
|
||||
# 2022-12-22: Added code to write to the .status file
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.8
|
||||
# CREATED: 2016-05-14 14:21:14
|
||||
# REVISION: 2022-12-22 17:08:22
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
#DIR=${0%/*}
|
||||
VERSION="0.0.8"
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "[${SCRIPT} ${VERSION}] Usage: $SCRIPT shownumber"
|
||||
exit
|
||||
fi
|
||||
|
||||
BASENAME="$HOME/HPR/Show_Submission"
|
||||
SHOWDIR="$BASENAME/shownotes/hpr${1}"
|
||||
EXTRACT="$SHOWDIR/hpr${1}.out"
|
||||
FORMAT="$SHOWDIR/.format"
|
||||
VALIDATE="$BASENAME/validate_html"
|
||||
ERRORS="$SHOWDIR/hpr${1}.err"
|
||||
REPORT="$SHOWDIR/errors.txt"
|
||||
PICTPL="$SHOWDIR/.pictures.tt2"
|
||||
STATUSFILE="$SHOWDIR/.status"
|
||||
|
||||
|
||||
#
|
||||
# Sanity checks
|
||||
#
|
||||
[ -e "$VALIDATE" ] || {
|
||||
echo "$SCRIPT: HTML validator '$VALIDATE' not found"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ ! -e $EXTRACT ]]; then
|
||||
echo "$SCRIPT: File not found: $EXTRACT"
|
||||
exit
|
||||
fi
|
||||
|
||||
fmt=
|
||||
|
||||
#
|
||||
# Set the Vim command from the declared format
|
||||
#
|
||||
if [[ ! -e $FORMAT ]]; then
|
||||
#
|
||||
# Default
|
||||
#
|
||||
vimcom=':set filetype=markdown'
|
||||
else
|
||||
#
|
||||
# Define filetypes that Vim knows based on the names that arrive in the
|
||||
# form. All need work other than 'txt2tags'
|
||||
#
|
||||
fmt="$(cat "$FORMAT")"
|
||||
case $fmt in
|
||||
html5)
|
||||
fmt='html';;
|
||||
Markdown_GitHub | Markdown_Pandoc | markdown_standard | plain_text)
|
||||
fmt='markdown';;
|
||||
restructured_text)
|
||||
fmt='rst';;
|
||||
txt2tags)
|
||||
;; # No action needed
|
||||
*)
|
||||
fmt='markdown';;
|
||||
esac
|
||||
vimcom=":set filetype=$fmt"
|
||||
fi
|
||||
|
||||
#
|
||||
# For html5 (now called 'html') run a validator on it. If this generates
|
||||
# errors run Vim with a Quickfix window on the error file so the errors can be
|
||||
# spotted and fixed.
|
||||
#
|
||||
if [[ $fmt == 'html' ]]; then
|
||||
#
|
||||
# The validator exits with False if there are errors
|
||||
#
|
||||
if ! $VALIDATE "$EXTRACT" > "$ERRORS"; then
|
||||
#
|
||||
# Did the validation script crash?
|
||||
#
|
||||
RES=$?
|
||||
if [[ $RES -ne 0 ]]; then
|
||||
echo "Problem running $VALIDATE; Edit aborted"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# HTML::Valid can put unwanted stuff in the error file. Not sure why.
|
||||
# We remove it with 'sed'. Only lines beginning with the path of the
|
||||
# input file are wanted.
|
||||
#
|
||||
# shellcheck disable=SC1117
|
||||
sed -i -ne "\#^$EXTRACT#p" "$ERRORS"
|
||||
|
||||
#
|
||||
# Make an error file for reporting to the host, but only if it doesn't
|
||||
# already exist. Start with the HTML itself with line numbers and
|
||||
# follow with the error report with the file paths truncated.
|
||||
#
|
||||
if [[ ! -e $REPORT ]]; then
|
||||
nl -ba -w3 -s': ' "$EXTRACT" > "$REPORT"
|
||||
sed -e "s:^$BASENAME/::" "$ERRORS" >> "$REPORT"
|
||||
fi
|
||||
|
||||
#
|
||||
# Run Vim on the errors with the option of running 'make' to
|
||||
# re-validate after correcting. We force Vim to open the quickfix
|
||||
# window so errors and warnings can be seen and edited.
|
||||
#
|
||||
# shellcheck disable=SC1117
|
||||
vim --cmd ":set makeprg=${VALIDATE}\ %" -c "$vimcom" \
|
||||
-c ':setlocal spell' -c:cope -q "$ERRORS"
|
||||
RES=$?
|
||||
else
|
||||
#
|
||||
# No validation errors
|
||||
#
|
||||
vim -c "$vimcom" -c ':setlocal spell' "$EXTRACT"
|
||||
RES=$?
|
||||
fi
|
||||
else
|
||||
#
|
||||
# Not html5. If the picture template exists open it in a vertical split
|
||||
#
|
||||
if [[ -e $PICTPL ]]; then
|
||||
vim -c "$vimcom" -c ':setlocal spell' -O "$EXTRACT" "$PICTPL"
|
||||
RES=$?
|
||||
else
|
||||
vim -c "$vimcom" -c ':setlocal spell' "$EXTRACT"
|
||||
RES=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $RES -eq 0 ]]; then
|
||||
echo "Edited $EXTRACT ok"
|
||||
|
||||
#
|
||||
# Update the status file
|
||||
#
|
||||
echo "edited" >> "$STATUSFILE" || \
|
||||
{ echo "Failed to update $STATUSFILE"; exit 1; }
|
||||
else
|
||||
echo "Oops! Something went wrong!"
|
||||
fi
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
881
Show_Submission/edit_shownotes
Executable file
881
Show_Submission/edit_shownotes
Executable file
@@ -0,0 +1,881 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: edit_shownotes
|
||||
#
|
||||
# USAGE: ./edit_shownotes [-help] [-debug=N] [-field=NAME] -episode=N
|
||||
#
|
||||
# DESCRIPTION: Perform edits on metadata in show notes
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: 2022-12-20: originally written to update the shownotes.txt
|
||||
# file as well as shownotes.json. Now we are phasing out the
|
||||
# former and using just the JSON, so the former file is not
|
||||
# being edited.
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.5
|
||||
# CREATED: 2022-12-07 13:05:40
|
||||
# REVISION: 2024-04-27 22:41:24
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use v5.36;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use feature qw{ postderef say signatures state try };
|
||||
no warnings
|
||||
qw{ experimental::postderef experimental::signatures experimental::try };
|
||||
|
||||
use Getopt::Long;
|
||||
use Pod::Usage qw{pod2usage};
|
||||
|
||||
use Term::ANSIColor;
|
||||
use File::Temp;
|
||||
use File::Slurper qw{ read_text write_text };
|
||||
use File::Copy;
|
||||
|
||||
use JSON;
|
||||
|
||||
use Log::Handler;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
#
|
||||
# Version number (manually incremented)
|
||||
#
|
||||
our $VERSION = '0.0.5';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
my $cache = "$basedir/shownotes";
|
||||
my $logdir = "$basedir/logs";
|
||||
my $logfile = "$logdir/${PROG}.log";
|
||||
|
||||
my ( $fh, $showno, $showid );
|
||||
my ( $jsonfile, $jsonfile_bk, $json_text, $JSON_content );
|
||||
my ( $before, $field_contents );
|
||||
#my ( $txtfile, $txtfile_bk, $txtstring, @txtbuffer );
|
||||
|
||||
#
|
||||
# Text colours
|
||||
#
|
||||
my $red = color('red');
|
||||
my $green = color('green');
|
||||
my $yellow = color('yellow');
|
||||
my $magenta = color('magenta');
|
||||
my $bold = color('bold');
|
||||
my $reset = color('reset');
|
||||
|
||||
#
|
||||
# How to find (and edit) the fields in shownotes.{txt,json}.
|
||||
# The fields are 'tags', 'title' and 'summary'.
|
||||
# If the JSON file is being edited the primary field offered to the editor is
|
||||
# the first in the array (e.g. 'episode.Tags') and the other one simply echoes
|
||||
# it.
|
||||
# NOTE: 2022-12-20 - stopped modifying the shownotes.txt file
|
||||
#
|
||||
# If the TXT file is being updated (from the primary JSON version edited
|
||||
# earlier) we find it in the array holding the text file using the 'regex'
|
||||
# value, and build a new line using the 'label' value.
|
||||
# This will be cleaned up when the TXT variant is dropped.
|
||||
#
|
||||
my %fields = (
|
||||
'tags' => {
|
||||
'json' => [ 'episode.Tags', 'metadata.POST.tags' ],
|
||||
# 'txt' => { regex => qr{^Tags:}, label => 'Tags', },
|
||||
},
|
||||
'title' => {
|
||||
'json' => [ 'episode.Title', 'metadata.POST.title' ],
|
||||
# 'txt' => { regex => qr{^Title:}, label => 'Title', },
|
||||
},
|
||||
'summary' => {
|
||||
'json' => [ 'episode.Summary', 'metadata.POST.summary' ],
|
||||
# 'txt' => { regex => qr{^Summary:}, label => 'Summary', },
|
||||
},
|
||||
);
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
binmode STDOUT, ":encoding(UTF-8)";
|
||||
binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Options and arguments
|
||||
#-------------------------------------------------------------------------------
|
||||
my $DEF_DEBUG = 0;
|
||||
my $DEF_FIELD = 'tags';
|
||||
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
my %options;
|
||||
Options( \%options );
|
||||
|
||||
#
|
||||
# Default help
|
||||
#
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\n",
|
||||
-verbose => 0,
|
||||
-exitval => 1
|
||||
) if ( $options{'help'} );
|
||||
|
||||
#
|
||||
# Detailed help
|
||||
#
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\n",
|
||||
-verbose => 2,
|
||||
-exitval => 1,
|
||||
) if ( $options{'documentation'} );
|
||||
|
||||
#
|
||||
# Collect options
|
||||
#
|
||||
my $DEBUG = ( defined( $options{debug} ) ? $options{debug} : $DEF_DEBUG );
|
||||
my $field = ( defined( $options{field} ) ? $options{field} : $DEF_FIELD );
|
||||
|
||||
my $test_dir = $options{test_dir};
|
||||
|
||||
$showno = $options{episode};
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\nMissing mandatory option -episode\n",
|
||||
-verbose => 0,
|
||||
-exitval => 1
|
||||
) unless $showno;
|
||||
|
||||
#
|
||||
# Make an id in 'hpr1234' format
|
||||
#
|
||||
$showid = sprintf('hpr%04d',$showno);
|
||||
|
||||
#
|
||||
# Check that the -field=FIELD option is valid
|
||||
#
|
||||
die "Invalid field specification: $field\n"
|
||||
unless ($field =~ /^(tags|title|summary)$/);
|
||||
|
||||
#
|
||||
# The files we'll parse and/or edit (and that we'll backup to). Check the
|
||||
# former exist.
|
||||
# If we've received a test directory we'll run in test mode
|
||||
#
|
||||
if ($test_dir) {
|
||||
#
|
||||
# We need a directory here so remove any file component.
|
||||
#
|
||||
die "Missing path $test_dir\n" unless ( -e $test_dir );
|
||||
unless (-d $test_dir) {
|
||||
#
|
||||
# Trim a file path to what is likely to be a directory only, and test
|
||||
# it exists. Add a trailing '/' if none.
|
||||
#
|
||||
$test_dir =~ s|/?[^/]*$||mx;
|
||||
die "Missing directory $test_dir\n" unless ( -d $test_dir );
|
||||
$test_dir .= '/' unless ($test_dir =~ qr{/$});
|
||||
}
|
||||
|
||||
#
|
||||
# Look in the test place
|
||||
#
|
||||
$jsonfile = "$test_dir/shownotes.json";
|
||||
# $txtfile = "$test_dir/shownotes.txt";
|
||||
|
||||
$jsonfile_bk = "$test_dir/shownotes.json.orig";
|
||||
# $txtfile_bk = "$test_dir/shownotes.txt.orig";
|
||||
}
|
||||
else {
|
||||
#
|
||||
# Look in the default place
|
||||
#
|
||||
$jsonfile = "$cache/$showid/shownotes.json";
|
||||
# $txtfile = "$cache/$showid/shownotes.txt";
|
||||
|
||||
$jsonfile_bk = "$cache/$showid/shownotes.json.orig";
|
||||
# $txtfile_bk = "$cache/$showid/shownotes.txt.orig";
|
||||
}
|
||||
|
||||
die colored( "Unable to find JSON file $jsonfile", 'red' ) . "\n"
|
||||
unless ( -e $jsonfile );
|
||||
#die colored( "Unable to find text file $txtfile", 'red' ) . "\n"
|
||||
# unless ( -e $txtfile );
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Set up logging keeping the default log layout except for the date. The format
|
||||
# is "%T [%L] %m" where '%T' is the timestamp, '%L' is the log level and '%m is
|
||||
# the message. We fiddle with this to implement a 'Test' mode.
|
||||
#-------------------------------------------------------------------------------
|
||||
my $log = Log::Handler->new();
|
||||
|
||||
$log->add(
|
||||
file => {
|
||||
timeformat => "%Y/%m/%d %H:%M:%S",
|
||||
message_layout => (defined($test_dir) ? "%T [%L] TEST %m" : "%T [%L] %m"),
|
||||
filename => $logfile,
|
||||
minlevel => 0,
|
||||
maxlevel => 7,
|
||||
}
|
||||
);
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Read the JSON input file and parse it into $JSON_content (hashref)
|
||||
#-------------------------------------------------------------------------------
|
||||
my $json = JSON->new->utf8;
|
||||
open( $fh, '<:encoding(UTF-8)', $jsonfile );
|
||||
$json_text = <$fh>;
|
||||
close($fh);
|
||||
|
||||
#
|
||||
# Careful! Bad JSON can crash the script here!
|
||||
#
|
||||
try {
|
||||
$JSON_content = decode_json($json_text);
|
||||
}
|
||||
catch ($e) {
|
||||
die colored( "Failed to decode the JSON in $jsonfile", 'red' ) . "\n"
|
||||
}
|
||||
|
||||
$log->info( $showno, "Collecting $field from JSON" );
|
||||
|
||||
_debug( $DEBUG > 2, Dumper($JSON_content) );
|
||||
#_debug( $DEBUG > 2, "\$field: $field" );
|
||||
#_debug( $DEBUG > 2, Dumper(\%fields) );
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Get the contents of the primary JSON field. The group will all be the same,
|
||||
# as will the text versions, so we edit the primary and propagate to the
|
||||
# others.
|
||||
#-------------------------------------------------------------------------------
|
||||
$log->info( $showno,
|
||||
"Collecting from JSON with path '$fields{$field}->{json}->[0]'" );
|
||||
|
||||
#
|
||||
# Use the path in the %fields hash to get the prinmary node in the JSON hash.
|
||||
# We are using 'get_JSON' rather than going to the field directly because
|
||||
# we're hunting for different parts of the JSON structure depending on the
|
||||
# -field=NAME option and using a jq-like path stored in %fields.
|
||||
#
|
||||
$field_contents = get_JSON( $JSON_content, $fields{$field}->{json}->[0] );
|
||||
#say( defined($field_contents) ? $field_contents : 'undefined' );
|
||||
die colored( "No contents in field '$field'. Can't continue", 'red' ) . "\n"
|
||||
unless ( defined($field_contents) );
|
||||
|
||||
$log->info( $showno, "Contents of field: $field_contents" );
|
||||
$before = $field_contents;
|
||||
|
||||
#
|
||||
# Run the editor on what we collected
|
||||
#
|
||||
if ( $field eq 'tags' ) {
|
||||
$field_contents
|
||||
= check_field( $field, run_editor($field_contents), 200, qr{(\n)} );
|
||||
}
|
||||
elsif ( $field eq 'title' ) {
|
||||
$field_contents
|
||||
= check_field( $field, run_editor($field_contents), 100, qr{(\n)} );
|
||||
}
|
||||
elsif ( $field eq 'summary' ) {
|
||||
$field_contents
|
||||
= check_field( $field, run_editor($field_contents), 100, qr{(\n)} );
|
||||
}
|
||||
|
||||
die colored( "Nothing was changed. Exiting", 'red' ) . "\n"
|
||||
if ( $field_contents eq $before );
|
||||
|
||||
$log->info( $showno, "New contents of field: $field_contents" );
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Load the text version of the metadata
|
||||
# NOTE: 2022-12-20 - stopped modifying the shownotes.txt file
|
||||
#-------------------------------------------------------------------------------
|
||||
#open( $fh, '<:encoding(UTF-8)', $txtfile );
|
||||
#@txtbuffer = <$fh>;
|
||||
#close($fh);
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Make the changes to all the relevant points in the two data structures.
|
||||
# NOTE: 2022-12-20 - stopped modifying the shownotes.txt file
|
||||
#-------------------------------------------------------------------------------
|
||||
put_JSON( $JSON_content, $fields{$field}->{json}->[0], $field_contents );
|
||||
put_JSON( $JSON_content, $fields{$field}->{json}->[1], $field_contents );
|
||||
#_debug( $DEBUG > 1, Dumper($JSON_content) );
|
||||
|
||||
$log->info( $showno, "Updated JSON '$field' fields" );
|
||||
|
||||
#@txtbuffer = update_txt( \@txtbuffer, $fields{$field}->{txt}->{regex},
|
||||
# $fields{$field}->{txt}->{label} . ":\t$field_contents\n" );
|
||||
#_debug( $DEBUG > 1, "Text: " . Dumper( \@txtbuffer ) );
|
||||
|
||||
#$log->info( $showno, "Updated text '$field' fields" );
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Turn the data structures back into files, backing up the originals and
|
||||
# writing the new.
|
||||
#-------------------------------------------------------------------------------
|
||||
unless ( -e $jsonfile_bk ) {
|
||||
copy ($jsonfile, $jsonfile_bk) or die "Unable to backup $jsonfile\n";
|
||||
$log->info( $showno, "JSON backup created" );
|
||||
}
|
||||
$json_text = encode_json($JSON_content);
|
||||
write_text($jsonfile,$json_text);
|
||||
|
||||
$log->info( $showno, "JSON file updated" );
|
||||
|
||||
#unless ( -e $txtfile_bk ) {
|
||||
# copy ($txtfile, $txtfile_bk) or die "Unable to backup $txtfile\n";
|
||||
# $log->info( $showno, "Text backup created" );
|
||||
#}
|
||||
#$txtstring = join('',@txtbuffer);
|
||||
#write_text($txtfile,$txtstring);
|
||||
#
|
||||
#$log->info( $showno, "Text file updated" );
|
||||
|
||||
exit;
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: get_JSON
|
||||
# PURPOSE: Traverse a data structure using dotted notation and return the
|
||||
# value at the end point
|
||||
# PARAMETERS: $hash hashref to traverse
|
||||
# $path a path in the form of '.key1.key2.[0]' which
|
||||
# should walk to the key 'key1', then 'key2'
|
||||
# within it, and open the array expected to be
|
||||
# there and get element 0.
|
||||
# RETURNS: The value found or undef
|
||||
# DESCRIPTION: Uses 'traverse_JSON' to find the $path in the $hash, returning
|
||||
# a pointer (reference) to it. This can then be de-referenced to
|
||||
# return the item being referenced - unless it's undefined in
|
||||
# which case that value is returned. Being undefined means that
|
||||
# the path did not match the structure of the hash.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub get_JSON {
|
||||
my ( $hash, $path ) = @_;
|
||||
|
||||
my $pointer = traverse_JSON( $hash, $path );
|
||||
|
||||
#
|
||||
# If undef then need to return undef, not try and deref it!
|
||||
#
|
||||
if (defined($pointer)) {
|
||||
return $$pointer;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: put_JSON
|
||||
# PURPOSE: Traverse a data structure using dotted notation and update the
|
||||
# value at the end point
|
||||
# PARAMETERS: $hash hashref to traverse
|
||||
# $path a path in the form of '.key1.key2.[0]' which
|
||||
# should walk to the key 'key1', then 'key2'
|
||||
# within it, and open the array expected to be
|
||||
# there and rewrite element 0.
|
||||
# $new_value the new value to place at the point in the
|
||||
# hash
|
||||
# RETURNS: The previous value if found, or undef
|
||||
# DESCRIPTION: Uses 'traverse_JSON' to find the $path in the $hash, returning
|
||||
# a pointer (reference) to it. This can then be de-referenced to
|
||||
# return the item being referenced - unless it's undefined in
|
||||
# which case that value is returned. Being undefined means that
|
||||
# the path did not match the structure of the hash. Finally, if
|
||||
# the reference is valid then it's used to save the contents of
|
||||
# $new_value.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub put_JSON {
|
||||
my ( $hash, $path, $new_value ) = @_;
|
||||
|
||||
my $pointer = traverse_JSON( $hash, $path );
|
||||
my $old_value;
|
||||
|
||||
#
|
||||
# If $pointer is defined then dereference it as the return value. Also,
|
||||
# use it to write the new value.
|
||||
#
|
||||
if (defined($pointer)) {
|
||||
$old_value = $$pointer;
|
||||
$$pointer = $new_value;
|
||||
}
|
||||
|
||||
return $old_value;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: traverse_JSON
|
||||
# PURPOSE: Traverse a data structure using dotted notation
|
||||
# PARAMETERS: $hash hashref to traverse
|
||||
# $path a path in the form of '.key1.key2.[0]' which
|
||||
# should walk to the key 'key1', then 'key2'
|
||||
# within it, and open the array expected to be
|
||||
# there and return a pointer to element 0.
|
||||
# RETURNS: A reference to the end point of the path, or undef if not
|
||||
# found.
|
||||
# DESCRIPTION: Given a path like '.metadata.POST.title' (where the leading
|
||||
# '.' is optional because it's ignored), this is used to
|
||||
# traverse a Perl version of a JSON data structure to return
|
||||
# a *pointer* (reference) to a node.
|
||||
#
|
||||
# This is done by processing the path step by step and using
|
||||
# 'name' elements as hash keys to get to the next level or
|
||||
# return a terminal hash element. We also cater for '.[0]'
|
||||
# format path elements which means to use the zeroth member of
|
||||
# an array. Thus, if the tags were represented as an array rather
|
||||
# than a scalar CSV string, we'd be able to use a path like:
|
||||
# 'episode.Tags.[0]' to return the first tag.
|
||||
#
|
||||
# The data structure traversal is performed by using a pointer
|
||||
# to a part of it, and since nested hashes are constructed by
|
||||
# using hashrefs as hash element values, we get back references
|
||||
# by default.
|
||||
#
|
||||
# Once the terminal node has been reached it may be a scalar
|
||||
# (very likely in this application), so we make and return
|
||||
# a reference to it so that the caller can use this reference in
|
||||
# a standard way to return or change the contents.
|
||||
#
|
||||
# This function is meant to be more generic than this
|
||||
# application requires. The JSON we're dealing with here doesn't
|
||||
# have arrays (at the moment). This description is
|
||||
# application-specifc however!
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub traverse_JSON {
|
||||
my ( $hash, $path ) = @_;
|
||||
|
||||
my ( $pointer, $index );
|
||||
my @elements = split( '\.', $path );
|
||||
|
||||
#
|
||||
# Because $hash is a hashref we can just copy it
|
||||
#
|
||||
$pointer = $hash;
|
||||
|
||||
#
|
||||
# Traverse the hash using the path
|
||||
#
|
||||
foreach my $element (@elements) {
|
||||
next unless defined($element);
|
||||
|
||||
#
|
||||
# Plain names are keys or scalar end nodes, bracketed things are
|
||||
# arrays (which can be scalars of course)
|
||||
#
|
||||
unless ( ($index) = ( $element =~ /\[([^]])\]/ ) ) {
|
||||
# Hash key
|
||||
if ( exists( $pointer->{$element} ) ) {
|
||||
if ( ref( $pointer->{$element} ) eq '' ) {
|
||||
#
|
||||
# It's not a refererence so make a reference to it
|
||||
#
|
||||
$pointer = \$pointer->{$element};
|
||||
}
|
||||
else {
|
||||
#
|
||||
# It's a reference
|
||||
#
|
||||
$pointer = $pointer->{$element};
|
||||
}
|
||||
}
|
||||
else {
|
||||
#
|
||||
# Doesn't exist!
|
||||
#
|
||||
return; #undef
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Array
|
||||
if ( exists( $pointer->[$index] ) ) {
|
||||
if ( ref( $pointer->[$index] ) eq '' ) {
|
||||
#
|
||||
# It's not a refererence so make a reference to it
|
||||
#
|
||||
$pointer = \$pointer->[$index];
|
||||
}
|
||||
else {
|
||||
#
|
||||
# It's a reference
|
||||
#
|
||||
$pointer = $pointer->[$index];
|
||||
}
|
||||
}
|
||||
else {
|
||||
#
|
||||
# Doesn't exist!
|
||||
#
|
||||
return; # undef
|
||||
}
|
||||
}
|
||||
}
|
||||
return $pointer;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: update_txt
|
||||
# PURPOSE: Update the data structure from 'shownotes.txt' in the light of
|
||||
# requested changes.
|
||||
# PARAMETERS: $array arrayref to the contents of the shownotes.txt
|
||||
# file
|
||||
# $regex regular expression to find the line that needs
|
||||
# to be changed (there's just one main one).
|
||||
# $new_value new value to replace the original line
|
||||
# RETURNS: Modified array
|
||||
# DESCRIPTION: Finds the element in the arrayref ($array) which matches the
|
||||
# regular expression ($regex). When found it is replaced by the
|
||||
# new value ($new_value). The modified buffer is returned as
|
||||
# a list. Uses $result to determine the value of each line since
|
||||
# it is not permitted to change the $_ variable in the 'map'
|
||||
# statement.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub update_txt {
|
||||
my ( $array, $regex, $new_value ) = @_;
|
||||
|
||||
my $result;
|
||||
my @newbuffer
|
||||
= map { $result = ( $_ =~ /$regex/ ? $new_value : $_ ); $result }
|
||||
@$array;
|
||||
|
||||
return @newbuffer;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: run_editor
|
||||
# PURPOSE: Run an interactive vim editor on a string
|
||||
# PARAMETERS: $string String to edit
|
||||
# $options An arrayref containing options for vim
|
||||
# (optional) Example '+set paste'. Each option
|
||||
# (such as '-c startinsert') needs to be
|
||||
# a separate array element.
|
||||
# RETURNS: Edited string
|
||||
# DESCRIPTION: Makes a temporary file with File::Temp ensuring that the file
|
||||
# is in utf8 mode. Writes the edit string to the file and invokes
|
||||
# the 'vim' editor on it. The resulting file is then read back
|
||||
# into a string and returned to the caller, again taking care to
|
||||
# retain utf8 mode.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: File::Slurp and UTF-8 don't go well together. Moved to
|
||||
# File::Slurper instead
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub run_editor {
|
||||
my ( $string, $options ) = @_;
|
||||
|
||||
#
|
||||
# Build an arguments array for 'system'
|
||||
#
|
||||
my @args;
|
||||
push( @args, @$options ) if $options;
|
||||
|
||||
#
|
||||
# Make a temporary file
|
||||
#
|
||||
my $tfh = File::Temp->new;
|
||||
binmode $tfh, ":encoding(UTF-8)";
|
||||
my $tfn = $tfh->filename;
|
||||
print $tfh $string if $string;
|
||||
$tfh->close;
|
||||
|
||||
#
|
||||
# Add the filename to the arguments
|
||||
#
|
||||
push( @args, $tfn );
|
||||
|
||||
die "Edit failed\n"
|
||||
unless ( system( ( 'vim', @args ) ) == 0 );
|
||||
|
||||
return read_text($tfn);
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: check_field
|
||||
# PURPOSE: Checks the a field is not too long and doesn't contain certain
|
||||
# characters
|
||||
# PARAMETERS: $name name of field
|
||||
# $field string to be checked
|
||||
# $maxlen maximum string length
|
||||
# $regex regex containing illegal characters to be removed
|
||||
# RETURNS: The input string truncated and with any illegal characters
|
||||
# removed.
|
||||
# DESCRIPTION: Runs a substitution on the string then truncates the result if
|
||||
# it is too long.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub check_field {
|
||||
my ( $name, $field, $maxlen, $regex ) = @_;
|
||||
|
||||
return unless $field;
|
||||
|
||||
$field =~ s/$regex//g;
|
||||
if ( length($field) > $maxlen ) {
|
||||
warn "Field '$name' too long ("
|
||||
. length($field)
|
||||
. "); truncated to "
|
||||
. $maxlen . "\n";
|
||||
$field = substr( $field, 0, $maxlen );
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: coalesce
|
||||
# PURPOSE: To find the first defined argument and return it
|
||||
# PARAMETERS: Arbitrary number of arguments
|
||||
# RETURNS: The first defined argument or undef if there are none
|
||||
# DESCRIPTION:
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub coalesce {
|
||||
foreach (@_) {
|
||||
return $_ if defined($_);
|
||||
}
|
||||
return undef; ## no critic
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _debug
|
||||
# PURPOSE: Prints debug reports
|
||||
# PARAMETERS: $active Boolean: 1 for print, 0 for no print
|
||||
# $message Message to print
|
||||
# RETURNS: Nothing
|
||||
# DESCRIPTION: Outputs a message if $active is true. It removes any trailing
|
||||
# newline and then adds one in the 'print' to the caller doesn't
|
||||
# have to bother. Prepends the message with 'D> ' to show it's
|
||||
# a debug message.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub _debug {
|
||||
my ( $active, $message ) = @_;
|
||||
|
||||
chomp($message);
|
||||
print STDERR "D> $message\n" if $active;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Options
|
||||
# PURPOSE: Processes command-line options
|
||||
# PARAMETERS: $optref Hash reference to hold the options
|
||||
# RETURNS: Undef
|
||||
# DESCRIPTION:
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Options {
|
||||
my ($optref) = @_;
|
||||
|
||||
my @options = (
|
||||
"help", "documentation|manpage",
|
||||
"debug=i", "field=s",
|
||||
"episode=i", "test_dir=s",
|
||||
);
|
||||
|
||||
if ( !GetOptions( $optref, @options ) ) {
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\n",
|
||||
-verbose => 0,
|
||||
-exitval => 1
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
# Application Documentation
|
||||
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#{{{
|
||||
|
||||
=head1 NAME
|
||||
|
||||
edit_shownotes - edit JSON and text shownote metadata
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
This documentation refers to edit_shownotes version 0.0.5
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
./edit_shownotes [-help] [-documentation|manpage] [-debug=N]
|
||||
[-field=FIELD] -episode=N
|
||||
|
||||
|
||||
./edit_shownotes -field=tags -episode=3754
|
||||
./edit_shownotes -field=summary -episode=3762 \
|
||||
-test_dir=$PWD/tests/shownotes/hpr3762
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-help>
|
||||
|
||||
Prints a brief help message describing the usage of the program, and then exits.
|
||||
|
||||
=item B<-manpage> or B<-documentation>
|
||||
|
||||
Prints the entire documentation for the script.
|
||||
|
||||
=item B<-field=FIELD>
|
||||
|
||||
This optional parameter defaults to B<-field=tags>. The only permitted fields
|
||||
are 'tags', 'title' and 'summary'.
|
||||
|
||||
=item B<-episode=N>
|
||||
|
||||
This mandatory option specifies the number of the HPR episode that is being
|
||||
parsed. It needs to be numeric even though it is often used with an 'hpr'
|
||||
prefix internally. Leading zeroes are not required (when these are
|
||||
appropriate).
|
||||
|
||||
=item B<-test_dir=PATH>
|
||||
|
||||
This option is for testing. Normally the script determines the path to the
|
||||
file(s) it will parse and update. It actually finds the field specified by the
|
||||
B<-field-FIELD> option in the JSON file B<shownotes.json> and calls the editor
|
||||
to change this, then propagates any changes to the other JSON instance and the
|
||||
one in B<shownotes.txt>.
|
||||
|
||||
This option has been provided to make it simpler to make copies of the files
|
||||
relating to an incoming show and use them to test changes to the script.
|
||||
|
||||
The current workflow expects the "live" files in
|
||||
B<$HOME/HPR/Show_Submission/shownotes/hprSHOW>, but there is another area
|
||||
where show files are placed for testing:
|
||||
B<$HOME/HPR/Show_Submission/tests/shownotes/hprSHOW>.
|
||||
|
||||
It is simply a matter of making a copy and of referencing the directory path
|
||||
to this option. Changes will be made to this copy and log records written, but
|
||||
these will contain the word 'TEST' to show that the script is being run in
|
||||
this mode.
|
||||
|
||||
=item B<-debug=N>
|
||||
|
||||
Causes certain debugging information to be displayed.
|
||||
|
||||
0 (the default) no debug output
|
||||
1 N/A
|
||||
2 TBA
|
||||
3 TBA
|
||||
|
||||
=back
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This script is meant to be a component in a workflow dealing with the notes
|
||||
submitted by HPR hosts with the shows they are uploading.
|
||||
|
||||
The data from the web form which is used by hosts submitting shows is received
|
||||
in two formats, with fixed names.
|
||||
|
||||
The file B<shownotes.txt> contains the form data in a label/value format, but
|
||||
also uses PHP dumps to show some of the metadata. It is no longer used by the
|
||||
current workflow, but is retained for historical reasons.
|
||||
|
||||
The alternative file format is JSON, which is stored in B<shownotes.json>.
|
||||
This contains the same data as the other file but in a more standardised
|
||||
format.
|
||||
|
||||
This script is designed to allow the editing of three specific fields in these
|
||||
two files. This is because these fields are not used in the show note
|
||||
preparation workflow (though they are referenced), but any changes can be
|
||||
propagated back to the HPR server to allow workflows there to use the
|
||||
corrected version(s).
|
||||
|
||||
The fields which can be edited are duplicated in the two files. One of these
|
||||
is edited, and if appropriate, is propagated to the other duplicates. This
|
||||
simplifies the editing of the text format, and the JSON format, which is not
|
||||
simple to edit in a conventional way.
|
||||
|
||||
=head1 DIAGNOSTICS
|
||||
|
||||
A list of every error and warning message that the application can generate
|
||||
(even the ones that will "never happen"), with a full explanation of each
|
||||
problem, one or more likely causes, and any suggested remedies. If the
|
||||
application generates exit status codes (e.g. under Unix) then list the exit
|
||||
status associated with each error.
|
||||
|
||||
|
||||
=head1 CONFIGURATION AND ENVIRONMENT
|
||||
|
||||
A full explanation of any configuration system(s) used by the application,
|
||||
including the names and locations of any configuration files, and the
|
||||
meaning of any environment variables or properties that can be set. These
|
||||
descriptions must also include details of any configuration language used
|
||||
|
||||
|
||||
=head1 DEPENDENCIES
|
||||
|
||||
Data::Dumper
|
||||
File::Slurper
|
||||
File::Temp
|
||||
Getopt::Long
|
||||
JSON
|
||||
Log::Handler
|
||||
Pod::Usage
|
||||
Term::ANSIColor
|
||||
|
||||
=head1 BUGS AND LIMITATIONS
|
||||
|
||||
There are no known bugs in this module.
|
||||
Please report problems to Dave Morriss (Dave.Morriss@gmail.com)
|
||||
Patches are welcome.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Dave Morriss (Dave.Morriss@gmail.com)
|
||||
|
||||
=head1 LICENCE AND COPYRIGHT
|
||||
|
||||
Copyright (c) 2022 Dave Morriss (Dave.Morriss@gmail.com). All rights reserved.
|
||||
|
||||
This module is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself. See perldoc perlartistic.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
=cut
|
||||
|
||||
#}}}
|
||||
|
||||
# [zo to open fold, zc to close]
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
|
||||
|
751
Show_Submission/fix_relative_links
Executable file
751
Show_Submission/fix_relative_links
Executable file
@@ -0,0 +1,751 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: fix_relative_links
|
||||
#
|
||||
# USAGE: ./fix_relative_links [options] -episode=N FILE
|
||||
#
|
||||
# DESCRIPTION: Processes an HTML input file, looking for relative URLs. If
|
||||
# any are found these are made absolute using the -baseURL=URL
|
||||
# option or a default. The intention is to make them into
|
||||
# HPR-absolute URLs.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.3
|
||||
# CREATED: 2022-10-14 11:56:03
|
||||
# REVISION: 2022-10-23 22:12:08
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use v5.16;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use feature qw{ postderef say signatures state };
|
||||
no warnings qw{ experimental::postderef experimental::signatures };
|
||||
|
||||
use Carp;
|
||||
use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
|
||||
use File::Basename;
|
||||
|
||||
use IO::HTML;
|
||||
use HTML::TreeBuilder 5 -weak;
|
||||
use URI;
|
||||
|
||||
use Log::Handler;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
#
|
||||
# Version number (manually incremented)
|
||||
#
|
||||
our $VERSION = '0.0.3';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
my $logdir = "$basedir/logs";
|
||||
my $logfile = "$logdir/${PROG}.log";
|
||||
|
||||
#
|
||||
# Variables, arrays and hashes
|
||||
#
|
||||
my ( $DEBUG, $verbose, $silent, $showno, $base_URL, $fragment, $count_only );
|
||||
my ( $outfile, $filename, $showdir, $changes, $html );
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
binmode STDOUT, ":encoding(UTF-8)";
|
||||
binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Options and arguments
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Option defaults
|
||||
#
|
||||
my $DEFDEBUG = 0;
|
||||
|
||||
my %options;
|
||||
Options( \%options );
|
||||
|
||||
#
|
||||
# Default help shows minimal information
|
||||
#
|
||||
pod2usage( -msg => "$PROG version $VERSION\n", -exitval => 1, -verbose => 0 )
|
||||
if ( $options{'help'} );
|
||||
|
||||
#
|
||||
# The -documentation or -man option shows the full POD documentation through
|
||||
# a pager for convenience
|
||||
#
|
||||
pod2usage( -msg => "$PROG version $VERSION\n", -exitval => 1, -verbose => 2 )
|
||||
if ( $options{'documentation'} );
|
||||
|
||||
#
|
||||
# Collect options
|
||||
#
|
||||
$DEBUG = ( defined( $options{debug} ) ? $options{debug} : $DEFDEBUG );
|
||||
$showno = $options{episode};
|
||||
$base_URL = $options{baseURL};
|
||||
$fragment = ( defined( $options{fragment} ) ? $options{fragment} : 0 );
|
||||
$count_only = ( defined( $options{count} ) ? $options{count} : 0 );
|
||||
$outfile = $options{output};
|
||||
|
||||
#
|
||||
# Argument
|
||||
#
|
||||
$filename = shift;
|
||||
|
||||
#
|
||||
# Sanity checks
|
||||
#
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\nShow number missing\n",
|
||||
-exitval => 1,
|
||||
-verbose => 0
|
||||
) unless $showno;
|
||||
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\nInput file name missing\n",
|
||||
-exitval => 1,
|
||||
-verbose => 0
|
||||
) unless $filename;
|
||||
|
||||
#
|
||||
# Add leading zeroes to the show number if necessary
|
||||
#
|
||||
$showno = sprintf( '%04d', $showno );
|
||||
|
||||
#
|
||||
# Directories and files specific to this show
|
||||
#
|
||||
$showdir = "$basedir/shownotes/hpr$showno";
|
||||
|
||||
#
|
||||
# Allow the input filename to be a bare name
|
||||
#
|
||||
if ( !-e $filename ) {
|
||||
$filename = "$showdir/$filename";
|
||||
}
|
||||
die "Unable to find $filename" unless ( -e $filename );
|
||||
|
||||
#
|
||||
# Work on the output file, allowing defaults and substitution points for
|
||||
# convenience. If there's no outfile we'll just process the HTML and nothing
|
||||
# more.
|
||||
#
|
||||
if ( defined($outfile) ) {
|
||||
$outfile = output_file_name( $outfile, $showno, 'hpr%d_new.html' );
|
||||
$outfile = "$showdir/$outfile" if (dirname($outfile) eq '.');
|
||||
}
|
||||
|
||||
#
|
||||
# Default base URL
|
||||
#
|
||||
unless ($base_URL) {
|
||||
$base_URL = "https://hackerpublicradio.org/eps/hpr$showno/";
|
||||
}
|
||||
|
||||
#
|
||||
# Base URL must have a trailing '/'
|
||||
#
|
||||
$base_URL .= '/' unless ( $base_URL =~ qr{/$} );
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Set up logging keeping the default log layout except for the date. The format
|
||||
# is "%T [%L] %m" where '%T' is the timestamp, '%L' is the log level and '%m is
|
||||
# the message.
|
||||
#-------------------------------------------------------------------------------
|
||||
my $log = Log::Handler->new();
|
||||
|
||||
$log->add(
|
||||
file => {
|
||||
timeformat => "%Y/%m/%d %H:%M:%S",
|
||||
filename => $logfile,
|
||||
minlevel => 0,
|
||||
maxlevel => 7,
|
||||
}
|
||||
);
|
||||
|
||||
#
|
||||
# Log preamble
|
||||
#
|
||||
$log->info("Show number: $showno");
|
||||
$log->info("Processing: $filename");
|
||||
$log->info("Base: $base_URL");
|
||||
|
||||
#
|
||||
# Find and change any relative URLs returning the number of changes and the
|
||||
# altered HTML
|
||||
#
|
||||
( $changes, $html )
|
||||
= find_links_in_file( $filename, $base_URL, $fragment, $count_only );
|
||||
|
||||
$log->info("Number of changes: $changes");
|
||||
|
||||
#
|
||||
# Exit without writing if we're just counting
|
||||
#
|
||||
if ($count_only) {
|
||||
$log->info("Count only mode");
|
||||
exit $changes;
|
||||
}
|
||||
|
||||
#
|
||||
# Exit without writing if there were no changes
|
||||
#
|
||||
if ($changes == 0) {
|
||||
$log->info("No output written");
|
||||
exit $changes;
|
||||
}
|
||||
|
||||
#
|
||||
# Write output if an output file was specified
|
||||
#
|
||||
if ($outfile) {
|
||||
write_output( $outfile, $html );
|
||||
$log->info("Changes applied; written to $outfile");
|
||||
}
|
||||
else {
|
||||
$log->info("No output written");
|
||||
}
|
||||
|
||||
exit $changes;
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: find_links_in_file
|
||||
# PURPOSE: Finds relative links in an HTML file
|
||||
# PARAMETERS: $filename the name of the file we're parsing
|
||||
# $base_URL the part of the full URL we'll replace
|
||||
# $fragment Boolean signalling whether to treat the HTML
|
||||
# as a fragment or an entire document
|
||||
# $count_only Boolean signalling that all we want is the
|
||||
# count of relative URLs, no action is to be taken
|
||||
# RETURNS: The number of URLs "repaired".
|
||||
# DESCRIPTION:
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub find_links_in_file {
|
||||
my ( $filename, $base_URL, $fragment, $count_only ) = @_;
|
||||
|
||||
my ( $base_uri, $tree, $uri_orig, $uri_new );
|
||||
my ( $newlink, $linkedits, $result );
|
||||
|
||||
#
|
||||
# Parse the base URL
|
||||
#
|
||||
$base_uri = URI->new($base_URL);
|
||||
|
||||
#
|
||||
# Create a tree object
|
||||
#
|
||||
$tree = HTML::TreeBuilder->new;
|
||||
$tree->ignore_unknown(0);
|
||||
$tree->no_expand_entities(1);
|
||||
$tree->p_strict(1);
|
||||
$tree->store_comments(1);
|
||||
$tree->warn(1);
|
||||
|
||||
#
|
||||
# Parse the file using IO::HTML to grab it. Die if we fail because then we
|
||||
# know this stuff needs some urgent attention.
|
||||
#
|
||||
$tree->parse_file( html_file($filename) )
|
||||
or die "HTML::TreeBuilder failed to process $filename: $!\n";
|
||||
|
||||
$linkedits = 0;
|
||||
|
||||
#
|
||||
# Scan for all anchors and images using the HTML::Element method
|
||||
# 'extract_links'. The technique used here is from the HTML::Element man
|
||||
# page.
|
||||
#
|
||||
for ( @{ $tree->extract_links( 'a', 'img' ) } ) {
|
||||
my ( $link, $element, $attr, $tag ) = @$_;
|
||||
|
||||
#
|
||||
# Parse the link
|
||||
#
|
||||
$uri_orig = URI->new($link);
|
||||
|
||||
#
|
||||
# A relative link (presumably) doesn't have a scheme
|
||||
#
|
||||
unless ( $uri_orig->scheme ) {
|
||||
#
|
||||
# Original link
|
||||
#
|
||||
say "Relative link: $link";
|
||||
|
||||
#
|
||||
# Make the link absolute
|
||||
#
|
||||
$uri_new = make_absolute( $uri_orig, $base_uri );
|
||||
# $uri_new = URI->new_abs( $link, $base_URL );
|
||||
$newlink = sprintf( "%s:%s", $uri_new->scheme, $uri_new->opaque );
|
||||
say "Absolute link: $newlink";
|
||||
|
||||
#
|
||||
# Modify the HTML to make the relative absolute
|
||||
#
|
||||
if ( $uri_orig->fragment ) {
|
||||
# Not sure if we need to cater for URI fragments, but we'll try it
|
||||
$element->attr( $attr, $newlink . '#' . $uri_orig->fragment );
|
||||
}
|
||||
else {
|
||||
$element->attr( $attr, $newlink );
|
||||
}
|
||||
|
||||
$linkedits++;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Exit here if we were just asked to count
|
||||
#
|
||||
return ( $linkedits, undef ) if $count_only;
|
||||
|
||||
#
|
||||
# In 'HTML fragment' mode generate the body part without the <body> tags.
|
||||
#
|
||||
if ($fragment) {
|
||||
my $body = $tree->look_down( _tag => 'body' );
|
||||
( $result = $body->as_HTML( undef, ' ', {} ) )
|
||||
=~ s{(^<body[^>]*>|</body>$)}{}gi;
|
||||
}
|
||||
else {
|
||||
$result = $tree->as_HTML( undef, ' ', {} );
|
||||
}
|
||||
|
||||
return ( $linkedits, $result );
|
||||
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: write_output
|
||||
# PURPOSE: Write the "repaired" HTML
|
||||
# PARAMETERS: $outfile name of the output file
|
||||
# $html the HTML to write out
|
||||
# RETURNS: Nothing
|
||||
# DESCRIPTION:
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub write_output {
|
||||
my ( $outfile, $html ) = @_;
|
||||
|
||||
open( my $out, '>:encoding(UTF-8)', $outfile )
|
||||
or die "Unable to open $outfile for output: $!\n";
|
||||
|
||||
print $out $html;
|
||||
|
||||
close($out);
|
||||
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: make_absolute
|
||||
# PURPOSE: Take a relative URI and a base URI and return the absolute URI
|
||||
# PARAMETERS: $relative relative URL as a URI object
|
||||
# $base base URL as a URI object
|
||||
# RETURNS: Absolute URL as a URI object
|
||||
# DESCRIPTION:
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub make_absolute {
|
||||
my ( $relative, $base ) = @_;
|
||||
|
||||
my ( %base_path, @relative_path, $absolute );
|
||||
|
||||
#
|
||||
# Chop up the path from the base and store in a hash
|
||||
#
|
||||
%base_path = map { $_ => 1 } split( '/', $base->path );
|
||||
|
||||
#
|
||||
# Chop up the relative path
|
||||
#
|
||||
@relative_path = split( '/', $relative->path );
|
||||
|
||||
#
|
||||
# Remove relative path elements if they are in the base
|
||||
#
|
||||
@relative_path = grep { !exists( $base_path{$_} ) } @relative_path;
|
||||
|
||||
#
|
||||
# If the relative path is empty we assume it's referring to the
|
||||
# 'index.html' file.
|
||||
#
|
||||
push( @relative_path, 'index.html' ) unless (@relative_path);
|
||||
|
||||
#
|
||||
# Rebuild the relative path
|
||||
#
|
||||
$relative->path( join( '/', @relative_path ) );
|
||||
|
||||
#
|
||||
# Return the result of joining relative URL and base URL
|
||||
#
|
||||
$absolute = URI->new_abs( $relative->as_string, $base->as_string );
|
||||
|
||||
return $absolute;
|
||||
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: output_file_name
|
||||
# PURPOSE: Generate an output file name with three choices
|
||||
# PARAMETERS: $optarg the argument to the option choosing the filename
|
||||
# $showno the show number to add to certain name types
|
||||
# $template a default 'sprintf' template for the name
|
||||
# RETURNS: The name of the output file
|
||||
# DESCRIPTION: If there's a defined output filename then there are three
|
||||
# options: a null string, a plain filename and a substitution
|
||||
# string with '%d' sequences. The null string means the user used
|
||||
# '-option' without a value, so we want to generate a substitution
|
||||
# string. A string with '%d' requires a check to ensure there's
|
||||
# the right number, just one. The plain filename needs no more
|
||||
# work.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub output_file_name {
|
||||
my ( $optarg, $showno, $template ) = @_;
|
||||
|
||||
my ( $filename, $count );
|
||||
|
||||
#
|
||||
# We shouldn't be called with a null option argument
|
||||
#
|
||||
return unless defined($optarg);
|
||||
|
||||
#
|
||||
# Does the option have an argument?
|
||||
#
|
||||
if ( $optarg =~ /^$/ ) {
|
||||
#
|
||||
# No argument; use the show number from the -episode=N option
|
||||
#
|
||||
$filename = sprintf( $template, $showno );
|
||||
}
|
||||
elsif ( $optarg =~ /%d/ ) {
|
||||
#
|
||||
# There's an argument, does it have a '%d' in it?
|
||||
#
|
||||
$count = () = $optarg =~ /%d/g;
|
||||
die "Invalid - too many '%d' sequences in '$optarg'\n"
|
||||
if ( $count > 1 );
|
||||
$filename = sprintf( $optarg, $showno );
|
||||
}
|
||||
else {
|
||||
#
|
||||
# It's a plain filename, just return it
|
||||
#
|
||||
$filename = $optarg;
|
||||
}
|
||||
|
||||
return $filename;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: coalesce
|
||||
# PURPOSE: To find the first defined argument and return it
|
||||
# PARAMETERS: Arbitrary number of arguments
|
||||
# RETURNS: The first defined argument or undef if there are none
|
||||
# DESCRIPTION: Just a simple way of ensuring an 'undef' value is never
|
||||
# returned when doing so might be a problem.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub coalesce {
|
||||
foreach (@_) {
|
||||
return $_ if defined($_);
|
||||
}
|
||||
return undef; ## no critic
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _debug
|
||||
# PURPOSE: Prints debug reports
|
||||
# PARAMETERS: $active Boolean: 1 for print, 0 for no print
|
||||
# $message Message to print
|
||||
# RETURNS: Nothing
|
||||
# DESCRIPTION: Outputs a message if $active is true. It removes any trailing
|
||||
# newline and then adds one in the 'print' to the caller doesn't
|
||||
# have to bother. Prepends the message with 'D> ' to show it's
|
||||
# a debug message.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub _debug {
|
||||
my ( $active, $message ) = @_;
|
||||
|
||||
chomp($message);
|
||||
print "D> $message\n" if $active;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Options
|
||||
# PURPOSE: Processes command-line options
|
||||
# PARAMETERS: $optref Hash reference to hold the options
|
||||
# RETURNS: Undef
|
||||
# DESCRIPTION: Process the options we want to offer. See the documentation
|
||||
# for details
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Options {
|
||||
my ($optref) = @_;
|
||||
|
||||
my @options = (
|
||||
"help", "documentation|man", "debug=i", "episode=i",
|
||||
"baseURL=s", "fragment!", "count!", "output:s",
|
||||
);
|
||||
|
||||
if ( !GetOptions( $optref, @options ) ) {
|
||||
pod2usage(
|
||||
-msg => "$PROG version $VERSION\n",
|
||||
-exitval => 1,
|
||||
-verbose => 0
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
# Application Documentation
|
||||
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#{{{
|
||||
|
||||
=head1 NAME
|
||||
|
||||
fix_relative_links - Repair relative URLs in HTML shownotes
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
This documentation refers to fix_relative_links version 0.0.3
|
||||
|
||||
=head1 USAGE
|
||||
|
||||
./fix_relative_links -ep=3705 shownotes/hpr3705/hpr3705.html -fragment
|
||||
|
||||
=head1 REQUIRED ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<filename>
|
||||
|
||||
The name of the file containing the HTML to be repaired. If no path is given
|
||||
this will be supplied by the script as:
|
||||
|
||||
~/HPR/Show_Submission/shownotes/hpr${show}/
|
||||
|
||||
It is probably wiser to be explicit about the path to the HTML file to be
|
||||
parsed.
|
||||
|
||||
=back
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-help>
|
||||
|
||||
Prints a brief help message describing the usage of the program, and then exits.
|
||||
|
||||
=item B<-documentation> or B<-man>
|
||||
|
||||
Prints the entire documentation for the script in the form of a manual page.
|
||||
|
||||
=item B<-debug=N>
|
||||
|
||||
Causes certain debugging information to be displayed.
|
||||
|
||||
0 (the default) no debug output
|
||||
1
|
||||
2
|
||||
3
|
||||
|
||||
=item B<-episode=N>
|
||||
|
||||
This option is mandatory and specifies the show number being processed. The
|
||||
number is used to generate default file names and paths as well as the default
|
||||
base URL described below.
|
||||
|
||||
=item B<-baseURL=URL>
|
||||
|
||||
This option will default to the foillowing URL if not provided:
|
||||
|
||||
https://hackerpublicradio.org/eps/hpr${show}/
|
||||
|
||||
It can be used to define a non-standard URL, such as one at a lower level than
|
||||
the example above which might contain thumbnail pictures for example.
|
||||
|
||||
=item B<-[no]fragment>
|
||||
|
||||
This Boolean option defines the HTML being parsed and checked as a fragment or
|
||||
a complete stand-alone document. By default B<-nofragment> is assumed. It is
|
||||
necessary to use B<fragment> for the case where the HTML shownotes are being
|
||||
parsed.
|
||||
|
||||
=item B<-[no]count>
|
||||
|
||||
This Boolean option defines whether to simply count the necessary changes or
|
||||
to apply them to the given HTML file. By default B<-nocount> is assumed, and
|
||||
changes will be applied.
|
||||
|
||||
=item B<-output[=FILE]>
|
||||
|
||||
This option can be omitted or can be given without the B<FILE> name. If
|
||||
omitted entirely no output will be written even though the HTML file has been
|
||||
read and processed. If specified without the output file name the default name
|
||||
will be B<hpr${show}_new.html>. If no path is specified with the file name
|
||||
then a default will be generated as:
|
||||
|
||||
~/HPR/Show_Submission/shownotes/hpr${show}/hpr${show}_new.html
|
||||
|
||||
The output file name can be given in the form of a B<printf> template such as:
|
||||
|
||||
hpr%d_new.html
|
||||
|
||||
and the B<%d> will be replaced by the show number given through the
|
||||
B<-episode=N> option described above.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The script reads a file of HTML which has either been submitted by an HPR host
|
||||
as it is or has been generated from one of the markup languages accepted in
|
||||
the upload form. Most often this file will contain the main notes for a show
|
||||
and will eventually be saved in the HPR database.
|
||||
|
||||
It is also possible to use the script to process other HTML files submitted
|
||||
with an HPR show.
|
||||
|
||||
The purpose of the script is to find relative URLs in the HTML and convert
|
||||
them to absolute ones. The HPR website requests that absolute URLs be used
|
||||
since then they can be used in the various RSS feeds which are available, but
|
||||
many hosts forget to follow this request.
|
||||
|
||||
The HTML is parsed using B<HTML::TreeBuilder> and is searched for B<a> or
|
||||
B<img> tags. These are checked to ensure they contain absolute links, and if
|
||||
not are converted appropriately using a base URL for the HPR website.
|
||||
|
||||
A count of changes is returned by the script and the converted HTML is written
|
||||
out to a file if required. The script can be used to see if any conversions
|
||||
are necessary before making the changes.
|
||||
|
||||
The script is also capable of treating full HTML documents differently from
|
||||
the HTML fragments that are stored in the HPR database. An option is required
|
||||
to specify which type of HTML is being processed.
|
||||
|
||||
=head1 DIAGNOSTICS
|
||||
|
||||
Error and warning messages generated by the script.
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<Unable to find ...>
|
||||
|
||||
Type: fatal
|
||||
|
||||
The script was unable to find the specified input file.
|
||||
|
||||
=item B<HTML::TreeBuilder failed to process ...: ...>
|
||||
|
||||
Type: fatal
|
||||
|
||||
The script attempted to use B<HTML::TreeBuilder> to parse the input file
|
||||
but failed. The message also contains details of the failure.
|
||||
|
||||
=item B<Unable to open ... for output: ...>
|
||||
|
||||
Type: fatal
|
||||
|
||||
The script attempted to open the requested output file but failed. The reason
|
||||
for the failure is included in the error message.
|
||||
|
||||
=item B<Invalid - too many '%d' sequences in '...'>
|
||||
|
||||
Type: fatal
|
||||
|
||||
The script attempted to generate a name for the requested output file using
|
||||
the supplied template, but failed because there were too many B<%d> elements
|
||||
in the template. Only one should be provided, which will be substituted with
|
||||
the show number.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DEPENDENCIES
|
||||
|
||||
Carp
|
||||
Data::Dumper
|
||||
File::Basename
|
||||
Getopt::Long
|
||||
HTML::TreeBuilder
|
||||
IO::HTML
|
||||
Log::Handler
|
||||
Pod::Usage
|
||||
URI
|
||||
|
||||
=head1 BUGS AND LIMITATIONS
|
||||
|
||||
There are no known bugs in this module.
|
||||
Please report problems to Dave Morriss (Dave.Morriss@gmail.com)
|
||||
Patches are welcome.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Dave Morriss (Dave.Morriss@gmail.com)
|
||||
|
||||
=head1 LICENCE AND COPYRIGHT
|
||||
|
||||
Copyright (c) <year> Dave Morriss (Dave.Morriss@gmail.com). All rights reserved.
|
||||
|
||||
This module is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself. See perldoc perlartistic.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
=cut
|
||||
|
||||
#}}}
|
||||
|
||||
# [zo to open fold, zc to close]
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
|
||||
|
393
Show_Submission/make_markdown
Executable file
393
Show_Submission/make_markdown
Executable file
@@ -0,0 +1,393 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: make_markdown
|
||||
#
|
||||
# USAGE: ./make_markdown [-[no]simple] [-[no]entities] [-[no]stamp] file
|
||||
#
|
||||
# DESCRIPTION: Turn plain text to Markdown. Designed to be used as a filter
|
||||
# in vim.
|
||||
# Finds all bare URLs, ignoring lines with HTML or Markdown
|
||||
# links. It checks the path part of the URL to see if it's an
|
||||
# image. If it is it uses an image link, otherwise it uses
|
||||
# a plain link. Links are all to HPR standard where the text
|
||||
# part and the URL part are the same.
|
||||
# Unless the '-simple' option is present all HTML URLs are
|
||||
# accumulated, and if the host hasn't provided a 'Links' section
|
||||
# they are added to one. This happens even if the overall text
|
||||
# is short, but it's easy to remove if not wanted.
|
||||
# By default, in -nosimple mode an HTML comment with details of
|
||||
# this script is added to the output. This can be turned off
|
||||
# with the -nostamp option.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.9
|
||||
# CREATED: 2015-10-07 16:05:21
|
||||
# REVISION: 2024-01-14 15:59:34
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use version 0.77; # Planning to experiment with this new feature
|
||||
|
||||
use open ':encoding(UTF-8)'; # Make all IO UTF-8
|
||||
|
||||
use Getopt::Long;
|
||||
use Regexp::Common qw{URI pattern};
|
||||
use HTML::Entities;
|
||||
#use Encoding::FixLatin qw(fix_latin);
|
||||
use URI::Find;
|
||||
use URI;
|
||||
use List::MoreUtils qw{uniq};
|
||||
|
||||
#
|
||||
# Version number (manually incremented)
|
||||
#
|
||||
our $VERSION = 'v0.0.9';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
|
||||
my @urls;
|
||||
|
||||
my $have_links = 0;
|
||||
my $uri_count;
|
||||
my $new_url;
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
#binmode STDIN, ":encoding(UTF-8)";
|
||||
#binmode STDOUT, ":encoding(UTF-8)";
|
||||
#binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Patterns
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# 1. Look for a line beginning with 'Links:'
|
||||
#
|
||||
pattern
|
||||
name => ['links'],
|
||||
create => '^\s*Links:?\s*$',
|
||||
;
|
||||
|
||||
#
|
||||
# 2. Look for an HTML link (some people embed these in their notes)
|
||||
#
|
||||
pattern
|
||||
name => ['html_link'],
|
||||
create => '<a[^>]*>',
|
||||
;
|
||||
|
||||
#
|
||||
# 3. Look for existing Markdown links
|
||||
#
|
||||
pattern
|
||||
name => ['md_link'],
|
||||
create => '\[([^]]+)\]\(\1\)',
|
||||
;
|
||||
|
||||
#
|
||||
# 4. Look for mail addresses
|
||||
#
|
||||
pattern
|
||||
name => ['mail_link'],
|
||||
create => '(?i)[a-z0-9_+.](?:[a-z0-9_+.]+[a-z0-9_+])?\@[a-z0-9.-]+',
|
||||
;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Options and arguments
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Process options
|
||||
#
|
||||
my %options;
|
||||
Options( \%options );
|
||||
|
||||
#
|
||||
# Collect options
|
||||
#
|
||||
Usage() if ( $options{'help'} );
|
||||
|
||||
my $simple = ( defined( $options{simple} ) ? $options{simple} : 0 );
|
||||
my $entities = ( defined( $options{entities} ) ? $options{entities} : 0 );
|
||||
my $stamp = ( defined( $options{stamp} ) ? $options{stamp} : 0 );
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Process the data on STDIN
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Set up the URI finder to call back to the 'cb_general' routine. We use
|
||||
# a closure to allow the passing of the $simple variable
|
||||
#
|
||||
my $finder = URI::Find->new( sub { cb_general( shift, shift, $simple ) } );
|
||||
|
||||
#
|
||||
# Slurp everything on STDIN
|
||||
#
|
||||
my @text = <>;
|
||||
|
||||
if ($stamp) {
|
||||
printf "<!-- Processed by %s %s -->\n", $PROG, $VERSION unless $simple;
|
||||
}
|
||||
|
||||
#
|
||||
# Process the stuff we got
|
||||
#
|
||||
foreach my $line (@text) {
|
||||
chomp($line);
|
||||
|
||||
#
|
||||
# Look for a user-provided 'Links' section
|
||||
#
|
||||
if ( $line =~ /($RE{links})/ ) {
|
||||
$have_links = 1;
|
||||
$line = "### $1";
|
||||
print "$line\n";
|
||||
next;
|
||||
}
|
||||
|
||||
#
|
||||
# Check whether the line contains some HTML. If it does we don't want to
|
||||
# touch it.
|
||||
#
|
||||
if ( $line =~ /$RE{html_link}/ ) {
|
||||
print "$line\n";
|
||||
next;
|
||||
}
|
||||
|
||||
#
|
||||
# An existing Markdown link means we'll skip the line
|
||||
#
|
||||
if ( $line =~ /$RE{md_link}/ ) {
|
||||
print "$line\n";
|
||||
next;
|
||||
}
|
||||
|
||||
#
|
||||
# Special action for mail addresses.
|
||||
#
|
||||
# TODO: Loop through the line extracting each mail address and checking it
|
||||
# with Email::Valid. If valid turn into a Markdown linkgg of the form
|
||||
# <mailaddr>, otherwise ignore it.
|
||||
#
|
||||
if ( $line =~ /$RE{mail_link}/ ) {
|
||||
$line =~ s/($RE{mail_link})/<$1>/g;
|
||||
}
|
||||
|
||||
#
|
||||
# Look for URLs of any sort and process them in the callback 'cb_general'
|
||||
# defined earlier
|
||||
#
|
||||
$uri_count = $finder->find( \$line );
|
||||
|
||||
#
|
||||
# Print the line. It might have been edited by the URI::Find callback or
|
||||
# might just be as it was.
|
||||
#
|
||||
encode_entities($line) if ($entities);
|
||||
print "$line\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Unless we're in 'simple' mode generate links if there's data and the host
|
||||
# hasn't provided them. Make sure they are unique (since there may have been
|
||||
# multiple references in the notes)
|
||||
#
|
||||
unless ($simple) {
|
||||
if ( @urls && !$have_links ) {
|
||||
@urls = uniq @urls;
|
||||
print "\n### Links\n\n";
|
||||
|
||||
foreach my $url (@urls) {
|
||||
#$new_url = uri_reformat($url); # New format is not accepted
|
||||
print "- [$url]($url)\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: cb_general
|
||||
# PURPOSE: Process a URI found by URI::Find containing a link
|
||||
# PARAMETERS: $uri_obj a URI object
|
||||
# $uri_text the URI text
|
||||
# $simple Boolean that controls what type of Markdown
|
||||
# link is generated. If true (1) we use <URI>
|
||||
# form, otherwise we use [URI](URI) form
|
||||
# RETURNS: The modified URI text
|
||||
# DESCRIPTION: The URI::Find 'find' method calls this callback for every URI
|
||||
# it finds in the text it discovers. We only care about
|
||||
# http/https here (for now anyway). If the text is changed and
|
||||
# returned then the changed item is placed in the original text.
|
||||
# We differentiate between what look like images and plain HTML
|
||||
# URLs and generate different markup. We also save the HTML URL
|
||||
# in a global array for building a list of links later.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub cb_general {
|
||||
my ( $uri_obj, $uri_text, $simple ) = @_;
|
||||
|
||||
my $path;
|
||||
#my $new_uri = uri_reformat($uri_text);
|
||||
|
||||
#
|
||||
# For http: or https:
|
||||
#
|
||||
if ( $uri_obj->scheme =~ /^https?/ ) {
|
||||
$path = $uri_obj->path;
|
||||
if ( $path =~ /(?i:\.(jpg|png|gif)$)/ ) {
|
||||
$uri_text = "";
|
||||
}
|
||||
else {
|
||||
push( @urls, $uri_text );
|
||||
if ($simple) {
|
||||
$uri_text = "<$uri_text>";
|
||||
}
|
||||
else {
|
||||
$uri_text = "[$uri_text]($uri_text)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $uri_text;
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: uri_reformat
|
||||
# PURPOSE: Turns a URI into a form which is better for Markdown
|
||||
# PARAMETERS: $uri_str - the URI string
|
||||
# RETURNS: The URI string reformatted
|
||||
# DESCRIPTION: Places the URI string in an URI object to parse it. Copies
|
||||
# each of the elements to another empty URI object but takes
|
||||
# advantage of the setting of URI::DEFAULT_QUERY_FORM_DELIMITER
|
||||
# which forces the '&' delimiters to ';'. Returns the string
|
||||
# version of this new URI.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub uri_reformat {
|
||||
my ($uri_str) = @_;
|
||||
|
||||
local $URI::DEFAULT_QUERY_FORM_DELIMITER = ';';
|
||||
|
||||
my $u1 = URI->new($uri_str);
|
||||
my $u2 = URI->new;
|
||||
|
||||
$u2->scheme($u1->scheme);
|
||||
$u2->authority($u1->authority);
|
||||
$u2->path($u1->path);
|
||||
$u2->query_form($u1->query_form);
|
||||
$u2->fragment($u1->fragment);
|
||||
|
||||
return $u2->as_string;
|
||||
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: coalesce
|
||||
# PURPOSE: To find the first defined argument and return it
|
||||
# PARAMETERS: Arbitrary number of arguments
|
||||
# RETURNS: The first defined argument or undef if there are none
|
||||
# DESCRIPTION:
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: None
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub coalesce {
|
||||
foreach (@_) {
|
||||
return $_ if defined($_);
|
||||
}
|
||||
return undef; ## no critic
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Usage
|
||||
# PURPOSE: Display a usage message and exit
|
||||
# PARAMETERS: None
|
||||
# RETURNS: To command line level with exit value 1
|
||||
# DESCRIPTION: Builds the usage message using global values
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Usage {
|
||||
print STDERR <<EOD;
|
||||
$PROG v$VERSION
|
||||
|
||||
Usage: $PROG [options]
|
||||
|
||||
Scans STDIN in the assumption that it is plain text or some kind of hybrid
|
||||
Markdown looking for URLs, mail links, HTML and Markdown elements.
|
||||
|
||||
Options:
|
||||
|
||||
-help Display this information
|
||||
-[no]simple Turns 'simple' mode on or off; it is off by default.
|
||||
In 'simple' mode links are not accumulated and written
|
||||
at the end of the data in a 'Links' section. URLs are
|
||||
converted to a Markdown form though.
|
||||
-[no]entities Turns 'entities' mode on and off; it is off by
|
||||
default. When on this mode causes each line to be
|
||||
scanned for characters best represented as HTML
|
||||
entities and to change them appropriately. For example
|
||||
the '<' character becomes '<'.
|
||||
-[no]stamp Turns 'stamp' mode on and off; it is off by default.
|
||||
When this mode is on an HTML comment is written at the
|
||||
start of the output containing the name of the script
|
||||
and its version number.
|
||||
|
||||
|
||||
EOD
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: Options
|
||||
# PURPOSE: Processes command-line options
|
||||
# PARAMETERS: $optref Hash reference to hold the options
|
||||
# RETURNS: Undef
|
||||
# DESCRIPTION:
|
||||
# THROWS: no exceptions
|
||||
# COMMENTS: none
|
||||
# SEE ALSO: n/a
|
||||
#===============================================================================
|
||||
sub Options {
|
||||
my ($optref) = @_;
|
||||
|
||||
my @options = ( "help", "simple!", "entities!", "stamp!", );
|
||||
|
||||
if ( !GetOptions( $optref, @options ) ) {
|
||||
die "Failed to process options\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
|
222
Show_Submission/move_shownotes
Executable file
222
Show_Submission/move_shownotes
Executable file
@@ -0,0 +1,222 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: move_shownotes
|
||||
#
|
||||
# USAGE: ./move_shownotes original_show new_show
|
||||
#
|
||||
# DESCRIPTION: After a show has been moved from one slot to another on the
|
||||
# HPR server this script ensures that the local versions of
|
||||
# processed show notes correspond to the change by moving
|
||||
# directories around and correcting file names and some
|
||||
# contents.
|
||||
#
|
||||
# ** Under development **
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.2
|
||||
# CREATED: 2022-12-02 22:12:20
|
||||
# REVISION: 2022-12-06 23:03:12
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
DIR=${0%/*}
|
||||
|
||||
VERSION='0.0.2'
|
||||
|
||||
STDOUT="/dev/fd/2"
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#=== 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
|
||||
Usage: ./${SCRIPT} [-h] [-d] [-D] original_show new_show
|
||||
|
||||
Version: $VERSION
|
||||
|
||||
When a show has been processed and posted on the server, but needs to be moved
|
||||
to another slot (after getting the host's permission) this script assists with
|
||||
the processes involved in ensuring the local shownote caches reflect the
|
||||
server state.
|
||||
|
||||
The need to move a show is rare, but often follows when a host has forgotten
|
||||
the request to spread their shows out by at least two weeks and has sent them
|
||||
in to clots too close in time to one another.
|
||||
|
||||
Options:
|
||||
-h Print this help
|
||||
-d Select dry run mode
|
||||
-D Turn on debug mode with lots of extra output
|
||||
|
||||
Arguments:
|
||||
original_show
|
||||
new_show
|
||||
|
||||
Both arguments can use either an integer number or a format like 'hpr9999'
|
||||
and also compensate for the use of 'HPR' rather than 'hpr'.
|
||||
|
||||
Examples
|
||||
./${SCRIPT} -h
|
||||
./${SCRIPT} -d 3742 3756
|
||||
./${SCRIPT} -D 3738 3746
|
||||
|
||||
endusage
|
||||
exit "$result"
|
||||
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _DEBUG
|
||||
# DESCRIPTION: Writes one or more message lines if in DEBUG mode
|
||||
# PARAMETERS: List of messages
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
_DEBUG () {
|
||||
[ "$DEBUG" == 0 ] && return
|
||||
for msg in "$@"; do
|
||||
printf 'D> %s\n' "$msg"
|
||||
done
|
||||
}
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: coloured
|
||||
# DESCRIPTION: Write a message with colour codes
|
||||
# PARAMETERS: 1 - colour name
|
||||
# 2 - message
|
||||
# RETURNS: Nothing
|
||||
#===============================================================================
|
||||
coloured () {
|
||||
local colour="${1:-green}"
|
||||
local message="${2:-no message}"
|
||||
|
||||
printf '%s%s%s\n' "${!colour}" "$message" "${reset}"
|
||||
}
|
||||
|
||||
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
RES="$BASEDIR/reservations"
|
||||
SN="$BASEDIR/shownotes"
|
||||
|
||||
#
|
||||
# Check arguments
|
||||
#
|
||||
if [[ $# -ne 2 ]]; then
|
||||
_usage 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Check the arguments and standardise them
|
||||
#
|
||||
declare -a ARGS
|
||||
re="^(hpr|HPR)?([0-9]{1,4})$"
|
||||
for arg; do
|
||||
if [[ $arg =~ $re ]]; then
|
||||
printf -v n '%04d' "${BASH_REMATCH[2]}"
|
||||
ARGS+=("hpr$n")
|
||||
else
|
||||
coloured 'red' "Invalid show specification: $arg"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#ARGS[@]} -ne 2 ]]; then
|
||||
coloured 'red' "Unable to continue with invalid arguments"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Save the parsed show details
|
||||
#
|
||||
original_show="${ARGS[0]}"
|
||||
new_show="${ARGS[1]}"
|
||||
coloured 'blue' "Moving from $original_show to $new_show"
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Consistency checks
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# We expect the original show to have been moved into the reservations/
|
||||
# directory
|
||||
#
|
||||
if [[ ! -e "$RES/$original_show" ]]; then
|
||||
coloured 'red' "Did not find the moved original show as $RES/$original_show."
|
||||
|
||||
#
|
||||
# Perhaps the original show hasn't been moved yet, otherwise there's an
|
||||
# error - the wrong show has been specified.
|
||||
#
|
||||
if [[ -e "$SN/$original_show" ]]; then
|
||||
coloured 'red' "Found the original show as $SN/$original_show."
|
||||
coloured 'yellow' "Double check that this show has been moved on the HPR server."
|
||||
coloured 'yellow' "If so, wait for 'scan_HPR' to move it locally."
|
||||
coloured 'yellow' "If not, the show numbers you used are wrong."
|
||||
else
|
||||
coloured 'red' "Did not find the original show as $SN/$original_show."
|
||||
coloured 'yellow' "It looks as if the show numbers you used are wrong."
|
||||
fi
|
||||
|
||||
coloured 'red' "Unable to continue"
|
||||
exit
|
||||
fi
|
||||
|
||||
#
|
||||
# Is the destination free? It may have been filled with a dummy show by
|
||||
# 'scrape_HPR' or there may have been a mistake in the arguments.
|
||||
#
|
||||
if [[ -e "$SN/$new_show" ]]; then
|
||||
coloured 'yellow' "Found a directory at $SN/$new_show"
|
||||
|
||||
#
|
||||
# A dummy show directory will only contain 'shownotes.txt', 'hpr1234.out'
|
||||
# and 'hpr1234.html' to keep other scripts happy and a file called .dummy
|
||||
# to be detected by this script. So look for this signature, and if not
|
||||
# found halt with an error.
|
||||
#
|
||||
if [[ ! -e "$SN/$new_show/.dummy" ]]; then
|
||||
coloured 'red' "The directory seems to hold a live show!"
|
||||
coloured 'red' "Cannot continue; please check the situation"
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# Now we should have found the original show has been placed in the
|
||||
# reservations/ directory and the new slot should have had a dummy show placed
|
||||
# in it. We now need to move the reserved show into the destination slot after
|
||||
# removing the dummy show. Once done we need to rename files and change the
|
||||
# contents of some files.
|
||||
#
|
||||
|
||||
exit
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
||||
|
2348
Show_Submission/parse_JSON
Executable file
2348
Show_Submission/parse_JSON
Executable file
File diff suppressed because it is too large
Load Diff
23
Show_Submission/pic_definitions.tpl
Normal file
23
Show_Submission/pic_definitions.tpl
Normal file
@@ -0,0 +1,23 @@
|
||||
[%# Template for generating index.html via Markdown. -%]
|
||||
[%# Last updated: |2022-12-04 12:53:26| -%]
|
||||
[% USE piclist = datafile(piclist) -%]
|
||||
[%# >> Single picture, no thumbnail -%]
|
||||
[% MACRO pic1(prefix,title,fn1) BLOCK -%]
|
||||
[%# SET fn1 = "$prefix" _ fn1.split('/').slice(-1).join('/') -%]
|
||||
[% SET fn1 = "$prefix" _ fn1.remove('^.+/uploads/') -%]
|
||||
[%title%]\
|
||||
![[%title%]]([%fn1%])
|
||||
[% END -%]
|
||||
[%# >> Thumbnail, linking to full-sized picture -%]
|
||||
[% MACRO pic2(prefix,title,fn1,fn2) BLOCK -%]
|
||||
[%# SET fn1 = "$prefix" _ fn1.split('/').slice(-1).join('/') -%]
|
||||
[%# SET fn2 = "$prefix" _ fn2.split('/').slice(-1).join('/') -%]
|
||||
[% SET fn1 = "$prefix" _ fn1.remove('^.+/uploads/') -%]
|
||||
[% SET fn2 = "$prefix" _ fn2.remove('^.+/uploads/') -%]
|
||||
[%title%]\
|
||||
[![[%title%]]([%fn1%])]([%fn2%])
|
||||
<br/><small><small><em>Click the thumbnail to see the full-sized image</em></small></small>
|
||||
[% END -%]
|
||||
[%#
|
||||
# vim: syntax=tt2:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
||||
-%]
|
1
Show_Submission/query2csv
Symbolic link
1
Show_Submission/query2csv
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/cendjm/HPR/Database/query2csv
|
1
Show_Submission/query2json
Symbolic link
1
Show_Submission/query2json
Symbolic link
@@ -0,0 +1 @@
|
||||
/home/cendjm/HPR/Database/query2json
|
316
Show_Submission/resume_workflow
Executable file
316
Show_Submission/resume_workflow
Executable file
@@ -0,0 +1,316 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: resume_workflow
|
||||
#
|
||||
# USAGE: ./resume_workflow epno
|
||||
#
|
||||
# DESCRIPTION: For use with an HPR show that may not be fully processed.
|
||||
# Determines which workflow step is the next that needs to be
|
||||
# run, displays what it is and the script needed to perform it,
|
||||
# and passes the script name to the caller.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.2
|
||||
# CREATED: 2024-02-10 17:53:09
|
||||
# REVISION: 2024-03-10 19:15:14
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use v5.16;
|
||||
use strict;
|
||||
use warnings;
|
||||
use feature qw{ postderef say signatures state try };
|
||||
no warnings
|
||||
qw{ experimental::postderef experimental::signatures experimental::try };
|
||||
|
||||
use Config::General;
|
||||
|
||||
use List::Util qw( maxstr minstr );
|
||||
use List::MoreUtils qw( uniq );
|
||||
use File::Slurper qw( read_text read_lines );
|
||||
use JSON;
|
||||
|
||||
use Log::Handler;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
#
|
||||
# Version number (Incremented by Vim)
|
||||
#
|
||||
our $VERSION = '0.0.2';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
my $cache = "$basedir/shownotes";
|
||||
my $logs = "$basedir/logs";
|
||||
my $logfile = "$logs/$PROG.log";
|
||||
my $j_shownotes = 'shownotes.json';
|
||||
|
||||
my $formatfile = '.format';
|
||||
my $statusfile = '.status';
|
||||
my $assetfile = '.assets';
|
||||
my $picturefile = '.pictures';
|
||||
|
||||
#
|
||||
# Setting the environment variable 'resume_workflow_DEBUG' to greater than
|
||||
# 0 enables debug output. Different values control different output
|
||||
#
|
||||
my $DEBUG = 0;
|
||||
my $DEBUG_env = "${PROG}_DEBUG";
|
||||
if ( defined($ENV{"$DEBUG_env"})) {
|
||||
$DEBUG = $ENV{"$DEBUG_env"};
|
||||
}
|
||||
|
||||
my ($showno, $showid, $missed);
|
||||
|
||||
my %showdata;
|
||||
my @statustags = qw(
|
||||
copied
|
||||
parsed
|
||||
format
|
||||
metadata
|
||||
pictures
|
||||
assets
|
||||
edited
|
||||
converted
|
||||
rendered
|
||||
uploaded
|
||||
database
|
||||
reported
|
||||
);
|
||||
|
||||
#
|
||||
# Set up the tag hash
|
||||
#
|
||||
# {{{
|
||||
my %taghash = (
|
||||
'copied' => {
|
||||
'description' => 'Copy notes',
|
||||
'script' => 'copy_shownotes',
|
||||
'level' => 1,
|
||||
},
|
||||
'parsed' => {
|
||||
'description' => 'Parse raw',
|
||||
'script' => 'do_parse',
|
||||
'level' => 1,
|
||||
},
|
||||
'format' => {
|
||||
'description' => 'Change format',
|
||||
'script' => 'do_change_format',
|
||||
'level' => 2,
|
||||
},
|
||||
'metadata' => {
|
||||
'description' => 'Edit metadata',
|
||||
'script' => 'do_edit_shownotes',
|
||||
'level' => 2,
|
||||
},
|
||||
'pictures' => {
|
||||
'description' => 'Process pictures',
|
||||
'script' => 'do_pictures',
|
||||
'level' => 2,
|
||||
},
|
||||
'assets' => {
|
||||
'description' => 'Upload assets',
|
||||
'script' => 'do_asset_upload',
|
||||
'level' => 2,
|
||||
},
|
||||
'edited' => {
|
||||
'description' => 'Edit notes',
|
||||
'script' => 'do_vim',
|
||||
'level' => 1,
|
||||
},
|
||||
'converted' => {
|
||||
'description' => 'Run Pandoc',
|
||||
'script' => 'do_pandoc',
|
||||
'level' => 1,
|
||||
},
|
||||
'rendered' => {
|
||||
'description' => 'Run browser',
|
||||
'script' => 'do_browse',
|
||||
'level' => 1,
|
||||
},
|
||||
'uploaded' => {
|
||||
'description' => 'Upload HTML',
|
||||
'script' => 'do_upload',
|
||||
'level' => 1,
|
||||
},
|
||||
'database' => {
|
||||
'description' => 'Change database status',
|
||||
'script' => 'do_update_reservations',
|
||||
'level' => 1,
|
||||
},
|
||||
'reported' => {
|
||||
'description' => 'Report change to Matrix',
|
||||
'script' => 'do_report',
|
||||
'level' => 1,
|
||||
},
|
||||
);
|
||||
# }}}
|
||||
|
||||
_debug($DEBUG == 3, '%taghash: ' . Dumper(\%taghash));
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
binmode STDOUT, ":encoding(UTF-8)";
|
||||
binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Argument 1 must be the episode number in '1234' or 'hpr1234' form
|
||||
#-------------------------------------------------------------------------------
|
||||
$showno = shift;
|
||||
die "Usage: $PROG epno\n" unless $showno;
|
||||
if (($showno) =~ /^(?:hpr)?(\d+)$/) {
|
||||
#
|
||||
# Make an id in 'hpr1234' format
|
||||
#
|
||||
$showid = sprintf('hpr%04d',$showno);
|
||||
}
|
||||
else {
|
||||
die "Invalid episode format: $showno\n";
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Set up logging keeping the default log layout except for the date. The format
|
||||
# is "%T [%L] %m" where '%T' is the timestamp, '%L' is the log level and '%m is
|
||||
# the message.
|
||||
#-------------------------------------------------------------------------------
|
||||
my $log = Log::Handler->new();
|
||||
|
||||
$log->add(
|
||||
file => {
|
||||
timeformat => "%Y/%m/%d %H:%M:%S",
|
||||
filename => $logfile,
|
||||
minlevel => 0,
|
||||
maxlevel => 7,
|
||||
}
|
||||
);
|
||||
|
||||
#
|
||||
# Check the existence of the requested show directory
|
||||
#
|
||||
unless (-d "$cache/$showid") {
|
||||
die "Directory $cache/$showid not found\n";
|
||||
}
|
||||
|
||||
$log->info("Processing show $showid");
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Collect show data
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Declared format
|
||||
#
|
||||
if ( -e "$cache/$showid/$formatfile" ) {
|
||||
chomp($showdata{format} = read_text("$cache/$showid/$formatfile"));
|
||||
}
|
||||
else {
|
||||
$showdata{format} = undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Current status
|
||||
#
|
||||
if ( -e "$cache/$showid/$statusfile" ) {
|
||||
$showdata{statuslist} = [];
|
||||
push(@{$showdata{statuslist}}, read_lines("$cache/$showid/$statusfile"));
|
||||
}
|
||||
else {
|
||||
$showdata{statuslist} = undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Assets
|
||||
#
|
||||
if ( -e "$cache/$showid/$assetfile" ) {
|
||||
$showdata{assets} = [];
|
||||
push(@{$showdata{assets}}, read_lines("$cache/$showid/$assetfile"));
|
||||
$taghash{assets}->{level} = 1;
|
||||
}
|
||||
else {
|
||||
$showdata{assets} = undef;
|
||||
}
|
||||
|
||||
#
|
||||
# Pictures (a subset of assets)
|
||||
#
|
||||
if ( -e "$cache/$showid/$picturefile" ) {
|
||||
$showdata{pictures} = [];
|
||||
push(@{$showdata{pictures}}, read_lines("$cache/$showid/$picturefile"));
|
||||
$taghash{pictures}->{level} = 1;
|
||||
}
|
||||
else {
|
||||
$showdata{pictures} = undef;
|
||||
}
|
||||
|
||||
_debug($DEBUG == 3, '%showdata: ' . Dumper(\%showdata));
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Determine the incomplete steps in the workflow
|
||||
#-------------------------------------------------------------------------------
|
||||
$missed = 0;
|
||||
for my $tag (@statustags) {
|
||||
my $th = $taghash{$tag};
|
||||
|
||||
if ( $th->{level} == 1
|
||||
&& scalar( grep( /$tag/, @{ $showdata{statuslist} } ) ) == 0 )
|
||||
{
|
||||
printf "%-40s (./%s %d)\n",
|
||||
"Missing '$th->{description}' step",
|
||||
$th->{script}, $showno;
|
||||
$missed++;
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# Nothing missed, so say so
|
||||
#
|
||||
say "Nothing to do for show $showno" if ($missed == 0);
|
||||
|
||||
exit;
|
||||
|
||||
#=== FUNCTION ================================================================
|
||||
# NAME: _debug
|
||||
# PURPOSE: Prints debug reports
|
||||
# PARAMETERS: $active Boolean: 1 for print, 0 for no print
|
||||
# $messages... Arbitrary list of messages to print
|
||||
# RETURNS: Nothing
|
||||
# DESCRIPTION: Outputs messages if $active is true. It removes any trailing
|
||||
# newline from each one and then adds one in the 'print' to the
|
||||
# caller doesn't have to bother. Prepends each message with 'D>'
|
||||
# to show it's a debug message.
|
||||
# THROWS: No exceptions
|
||||
# COMMENTS: Differs from other functions of the same name
|
||||
# SEE ALSO: N/A
|
||||
#===============================================================================
|
||||
sub _debug {
|
||||
my $active = shift;
|
||||
|
||||
my $message;
|
||||
return unless $active;
|
||||
|
||||
while ($message = shift) {
|
||||
chomp($message);
|
||||
print STDERR "D> $message\n";
|
||||
}
|
||||
}
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
|
||||
|
75
Show_Submission/sync_hpr
Executable file
75
Show_Submission/sync_hpr
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash -
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: sync_hpr
|
||||
#
|
||||
# USAGE: ./sync_hpr
|
||||
#
|
||||
# DESCRIPTION: Runs rsync to pull the contents of the 'upload' directory from
|
||||
# the HPR server. Uses a filter in the file '.rsync_hpr_upload'
|
||||
# so that it only copies the files relevant to managing
|
||||
# submitted shows. Files and directories deleted on the HPR
|
||||
# server are also deleted here.
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: ---
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.7
|
||||
# CREATED: 2020-01-03 23:18:58
|
||||
# REVISION: 2023-06-14 18:06:06
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
set -o nounset # Treat unset variables as an error
|
||||
|
||||
SCRIPT=${0##*/}
|
||||
# DIR=${0%/*}
|
||||
|
||||
#
|
||||
# Load library functions
|
||||
#
|
||||
LIB="$HOME/bin/function_lib.sh"
|
||||
[ -e "$LIB" ] || { echo "$SCRIPT: Unable to source functions"; exit 1; }
|
||||
# shellcheck source=/home/cendjm/bin/function_lib.sh
|
||||
source "$LIB"
|
||||
|
||||
#
|
||||
# Colour codes
|
||||
#
|
||||
define_colours
|
||||
|
||||
#
|
||||
# Directories
|
||||
#
|
||||
BASEDIR="$HOME/HPR/Show_Submission"
|
||||
HPRUPLOAD='hpr@hackerpublicradio.org:upload/'
|
||||
UPLOAD="$BASEDIR/upload"
|
||||
|
||||
#
|
||||
# Settings
|
||||
#
|
||||
# PORT=22074
|
||||
PORT=22
|
||||
|
||||
#
|
||||
# Change directory
|
||||
#
|
||||
cd "$BASEDIR" || { echo "$SCRIPT: Failed to change directory to $BASENAME"; exit 1; }
|
||||
|
||||
#
|
||||
# Check the tunnel is open
|
||||
#
|
||||
if ! tunnel_is_open; then
|
||||
echo "$SCRIPT: Open the tunnel before running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Use 'rsync' to collect relevant data from the HPR server's 'upload'
|
||||
# directory.
|
||||
#
|
||||
rsync -vaP -e "ssh -p $PORT" --delete --filter=". .rsync_hpr_upload" "$HPRUPLOAD" "$UPLOAD"
|
||||
|
||||
# vim: syntax=sh:ts=8:sw=4:ai:et:tw=78:fo=tcrqn21
|
96
Show_Submission/validate_html
Executable file
96
Show_Submission/validate_html
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env perl
|
||||
#===============================================================================
|
||||
#
|
||||
# FILE: validate_html
|
||||
#
|
||||
# USAGE: ./validate_html file
|
||||
#
|
||||
# DESCRIPTION: Validate HTML show notes using HTML::Valid
|
||||
#
|
||||
# OPTIONS: ---
|
||||
# REQUIREMENTS: ---
|
||||
# BUGS: ---
|
||||
# NOTES: Much of this code is as seen in 'htmlok' because the
|
||||
# documentation with HTML::Valid is poor.
|
||||
# AUTHOR: Dave Morriss (djm), Dave.Morriss@gmail.com
|
||||
# VERSION: 0.0.3
|
||||
# CREATED: 2018-06-01 16:25:27
|
||||
# REVISION: 2019-11-10 21:25:06
|
||||
#
|
||||
#===============================================================================
|
||||
|
||||
use 5.010;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
# In the POD, without explanation
|
||||
use FindBin '$Bin';
|
||||
|
||||
# Found in 'htmlok', not documented
|
||||
use HTML::Valid 'sanitize_errors';
|
||||
use Path::Tiny;
|
||||
|
||||
#
|
||||
# Version number (manually incremented)
|
||||
#
|
||||
our $VERSION = '0.0.3';
|
||||
|
||||
#
|
||||
# Script and directory names
|
||||
#
|
||||
( my $PROG = $0 ) =~ s|.*/||mx;
|
||||
( my $DIR = $0 ) =~ s|/?[^/]*$||mx;
|
||||
$DIR = '.' unless $DIR;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Declarations
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
# Constants and other declarations
|
||||
#
|
||||
my $basedir = "$ENV{HOME}/HPR/Show_Submission";
|
||||
|
||||
#
|
||||
# Enable Unicode mode
|
||||
#
|
||||
binmode STDOUT, ":encoding(UTF-8)";
|
||||
binmode STDERR, ":encoding(UTF-8)";
|
||||
|
||||
#
|
||||
# Create the object
|
||||
#
|
||||
my $htv = HTML::Valid->new(
|
||||
quiet => 1, # omit summary, etc
|
||||
doctype => 'omit',
|
||||
show_body_only => 1, # print only the contents of the body tag as an HTML fragment
|
||||
show_info => 1, # test; omit info-level messages
|
||||
show_warnings => 1, # include warnings if set
|
||||
);
|
||||
|
||||
#
|
||||
# We expect a file as an argument
|
||||
#
|
||||
my $file = shift @ARGV;
|
||||
die "Usage: $PROG filename\n" unless $file;
|
||||
my $content;
|
||||
if ( -f $file ) {
|
||||
$content = path($file)->slurp_utf8();
|
||||
$htv->set_filename($file);
|
||||
}
|
||||
else {
|
||||
die "$PROG: Cannot find '$file'.\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Largely undocumented but seen in 'htmlok'
|
||||
#
|
||||
my ( undef, $errors ) = $htv->run($content);
|
||||
if ($errors) {
|
||||
print sanitize_errors ($errors);
|
||||
exit 1;
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
# vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker
|
Reference in New Issue
Block a user