752 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			752 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								#!/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
							 | 
						||
| 
								 | 
							
								
							 |