forked from rho_n/hpr_generator
		
	Merge pull request 'Fixing issue #140' (#155) from I140_Convert_the_RSS_feeds_from_php_to_the_static_site into main
Reviewed-on: rho_n/hpr_generator#155
This commit is contained in:
		
							
								
								
									
										572
									
								
								site-generator
									
									
									
									
									
								
							
							
						
						
									
										572
									
								
								site-generator
									
									
									
									
									
								
							| @@ -1,88 +1,92 @@ | ||||
| #!/usr/bin/perl | ||||
|  | ||||
| # {{{ POD documentation | ||||
|  | ||||
| =head1 NAME | ||||
|  | ||||
| 	site-generator - HPR Site Generator | ||||
|         site-generator - HPR Site Generator | ||||
|  | ||||
| =head1 SYNOPSIS | ||||
|  | ||||
| 	site-generator [OPTION]... PAGE|PAGE=<comma separated list of ids>... | ||||
|         site-generator [OPTION]... PAGE|PAGE=<comma separated list of ids>... | ||||
|  | ||||
| 	-a, --all           generate all pages defined in configuration file | ||||
| 	-c, --configuration path to configuration file | ||||
| 	-l, --list          print list of configured pages | ||||
| 	-p, --preview       print generated pages to standard out | ||||
| 	-q, --quiet         suppress progress information while generating pages | ||||
| 	-v, --verbose       print extended progress information while generating pages | ||||
| 	--help              print this help message | ||||
|         -a, --all           generate all pages defined in configuration file | ||||
|         -c, --configuration path to configuration file | ||||
|         -l, --list          print list of configured pages | ||||
|         -p, --preview       print generated pages to standard out | ||||
|         -q, --quiet         suppress progress information while generating pages | ||||
|         -v, --verbose       print extended progress information while generating pages | ||||
|         --help              print this help message | ||||
|  | ||||
| 	Where I<PAGE> is a file name of a web page  | ||||
| 	or the special I<ALL> (to generate all pages). | ||||
|         Where I<PAGE> is a file name of a web page | ||||
|         or the special I<ALL> (to generate all pages). | ||||
|  | ||||
| 	Examples: | ||||
|         Examples: | ||||
|  | ||||
| 		Generate two specific pages: | ||||
| 		site-generator index about | ||||
|                 Generate two specific pages: | ||||
|                 site-generator index about | ||||
|  | ||||
| 		Generate the whole site: | ||||
| 		site-generator --all | ||||
|                 Generate the whole site: | ||||
|                 site-generator --all | ||||
|  | ||||
| 		Generate pages based on the same template: | ||||
| 		site-generator correspondent=1,3,5..10 | ||||
|                 Generate pages based on the same template: | ||||
|                 site-generator correspondent=1,3,5..10 | ||||
|  | ||||
| 		Generate two specific pages with a different configuration: | ||||
| 		site-generator --configuration=site_sqlite.cfg index about | ||||
|                 Generate two specific pages with a different configuration: | ||||
|                 site-generator --configuration=site_sqlite.cfg index about | ||||
|  | ||||
|  | ||||
| =head1 DESCRIPTION | ||||
|  | ||||
| This is a site generator for the Hacker Public Radio website based upon the Perl Templates Toolkit. | ||||
| This is a site generator for the Hacker Public Radio website based upon the | ||||
| Perl Template Toolkit. | ||||
|  | ||||
| =head1 INSTALLATION | ||||
|  | ||||
| 	With SQLite | ||||
| 	* Create the sqlite3 database from the hpr.sql MySQL dump file available on  | ||||
| 	  hackerpublicradio.org. The default name for the database file is "hpr.db"  | ||||
| 	  and should be located in the root of the project directory. The name and  | ||||
| 	  location can be set in the site.cfg file. | ||||
| 	* An "update-hpr.sh" helper script is available in the utils directory. This  | ||||
| 	  script will download the hpr.sql file, convert it to the SQLite hpr.db file,  | ||||
| 	  and regenerate the website using the site-generator.  | ||||
| 		1. `cd` into the root of the project directory | ||||
| 		2.  Run `./utils/update-hpr.sh` | ||||
| 	* SQLite v3.8.3 or greater is recommended. CTE WITH clauses are used in some template queries.  | ||||
| 	  Must convert WITH clauses to sub-queries when using earlier versions of SQLite. | ||||
|         With SQLite | ||||
|         * Create the sqlite3 database from the hpr.sql MySQL dump file available on | ||||
|           hackerpublicradio.org. The default name for the database file is "hpr.db" | ||||
|           and should be located in the root of the project directory. The name and | ||||
|           location can be set in the site.cfg file. | ||||
|         * An "update-hpr.sh" helper script is available in the utils directory. This | ||||
|           script will download the hpr.sql file, convert it to the SQLite hpr.db file, | ||||
|           and regenerate the website using the site-generator. | ||||
|                 1. `cd` into the root of the project directory | ||||
|                 2.  Run `./utils/update-hpr.sh` | ||||
|         * SQLite v3.8.3 or greater is recommended. CTE WITH clauses are used in some template queries. | ||||
|           Must convert WITH clauses to sub-queries when using earlier versions of SQLite. | ||||
|  | ||||
| 	With MySQL | ||||
| 	* Create database hpr_hpr in the MySQL server from HPR dump file. | ||||
| 		- sudo mysql --host=localhost < hpr.sql | ||||
| 	* Create a user that will be used by the site-generator. | ||||
| 		- Suggested username: hpr-generator | ||||
| 		- CREATE USER 'hpr-generator'@'localhost' IDENTIFIED BY '<password>'; | ||||
| 	* Limit the user's privileges to EXECUTE and SELECT | ||||
| 		- GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost'; | ||||
| 		- GRANT EXECUTE ON `hpr_hpr`.* TO 'hpr-generator'@'localhost'; | ||||
|         With MySQL | ||||
|         * Create database hpr_hpr in the MySQL server from HPR dump file. | ||||
|                 - sudo mysql --host=localhost < hpr.sql | ||||
|         * Create a user that will be used by the site-generator. | ||||
|                 - Suggested username: hpr-generator | ||||
|                 - CREATE USER 'hpr-generator'@'localhost' IDENTIFIED BY '<password>'; | ||||
|         * Limit the user's privileges to EXECUTE and SELECT | ||||
|                 - GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost'; | ||||
|                 - GRANT EXECUTE ON `hpr_hpr`.* TO 'hpr-generator'@'localhost'; | ||||
|  | ||||
| 	Install the needed Perl modules using preferred method (distribution packages, CPAN, etc.) | ||||
| 		* GetOpt | ||||
| 		* Pod::Usage | ||||
| 		* Config::Std | ||||
| 		* Template | ||||
| 		* Template::Plugin::File | ||||
| 		* Template::Plugin::DBI | ||||
| 		* DBI | ||||
| 		* Tie::DBI | ||||
| 		* DBD::SQLite or DBD:mysql | ||||
| 		* Date::Calc | ||||
|         Install the needed Perl modules using preferred method (distribution packages, CPAN, etc.) | ||||
|                 * GetOpt | ||||
|                 * Pod::Usage | ||||
|                 * Config::Std | ||||
|                 * Template | ||||
|                 * Template::Plugin::File | ||||
|                 * Template::Plugin::DBI | ||||
|                 * DBI | ||||
|                 * Tie::DBI | ||||
|                 * DBD::SQLite or DBD:mysql | ||||
|                 * Date::Calc | ||||
|                 * Text::CSV_XS | ||||
|  | ||||
| =head1 AUTHOR | ||||
|  | ||||
| 	Roan Horning <roan.horning@no-spam.gmail.com> | ||||
|         Roan Horning <roan.horning@no-spam.gmail.com> | ||||
|  | ||||
| =head1 LICENSE | ||||
|  | ||||
| 	site-generator -- a static website generator for HPR | ||||
| 	Copyright (C) 2022 Roan Horning | ||||
|         site-generator -- a static website generator for HPR | ||||
|         Copyright (C) 2022 Roan Horning | ||||
|  | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Affero General Public License as published by | ||||
| @@ -95,253 +99,323 @@ This is a site generator for the Hacker Public Radio website based upon the Perl | ||||
|     GNU Affero General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Affero General Public License | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>.	 | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| =cut | ||||
|  | ||||
| # }}} | ||||
|  | ||||
| use strict; | ||||
| use warnings; | ||||
|  | ||||
| use Getopt::Long qw(:config auto_help); | ||||
| use Pod::Usage; | ||||
| use Config::Std; | ||||
| use Text::CSV_XS; | ||||
| use HTML::Entities qw(encode_entities_numeric); | ||||
| use Template; | ||||
| use Data::Dumper; | ||||
|  | ||||
| binmode STDOUT, ":encoding(UTF-8)"; | ||||
| binmode STDERR, ":encoding(UTF-8)"; | ||||
|  | ||||
| exit main(); | ||||
|  | ||||
| sub main { | ||||
|  | ||||
| 	# Argument parsing | ||||
| 	my $all; | ||||
| 	my $configuration_path; | ||||
| 	my $preview; | ||||
| 	my $verbose; | ||||
| 	my $quiet; | ||||
| 	GetOptions( | ||||
| 		'all'             => \$all, | ||||
| 		'configuration=s' => \$configuration_path, | ||||
| 		'list'            => \&print_available_pages, | ||||
| 		'preview'         => \$preview, | ||||
| 		'verbose'         => \$verbose, | ||||
| 		'quiet'           => \$quiet, | ||||
| 	) or pod2usage(1); | ||||
| 	pod2usage(1) unless @ARGV || $all; | ||||
| 	my (@page_args) = @ARGV; | ||||
|     # Argument parsing | ||||
|     my $all; | ||||
|     my $configuration_path; | ||||
|     my $preview; | ||||
|     my $verbose; | ||||
|     my $quiet; | ||||
|     GetOptions( | ||||
|         'all'             => \$all, | ||||
|         'configuration=s' => \$configuration_path, | ||||
|         'list'            => \&print_available_pages, | ||||
|         'preview'         => \$preview, | ||||
|         'verbose'         => \$verbose, | ||||
|         'quiet'           => \$quiet, | ||||
|     ) or pod2usage(1); | ||||
|     pod2usage(1) unless @ARGV || $all; | ||||
|     my (@page_args) = @ARGV; | ||||
|  | ||||
| 	if ($quiet) { | ||||
| 		$verbose = 'quiet'; | ||||
| 	}; | ||||
|     if ($quiet) { | ||||
|         $verbose = 'quiet'; | ||||
|     }; | ||||
|  | ||||
| 	if (!$configuration_path) { | ||||
| 		$configuration_path = "site.cfg"; | ||||
| 	} | ||||
|     if (!$configuration_path) { | ||||
|         $configuration_path = "site.cfg"; | ||||
|     } | ||||
|  | ||||
| 	my %config; | ||||
| 	if ( -f $configuration_path ) { | ||||
| 		# Load config file | ||||
| 		read_config $configuration_path => %config; | ||||
| 	} | ||||
| 	else { | ||||
| 		print STDOUT "Could not read configuration file: $configuration_path\n";  | ||||
| 		exit 1; | ||||
| 	} | ||||
|     my %config; | ||||
|     if ( -f $configuration_path ) { | ||||
|         # Load config file | ||||
|         read_config $configuration_path => %config; | ||||
|     } | ||||
|     else { | ||||
|         print STDOUT "Could not read configuration file: $configuration_path\n"; | ||||
|         exit 1; | ||||
|     } | ||||
|  | ||||
| 	my $tt = get_template_html($config{DBI}, $config{app_paths}); | ||||
|     my $tt = get_template_html($config{DBI}, $config{app_paths}); | ||||
|  | ||||
| 	# If command line option all is set, parse configuration file  | ||||
| 	# for all pages | ||||
| 	if ($all) { | ||||
| 		@page_args = keys %config; | ||||
|     # | ||||
|     # Define a TT² vmethod called 'csv_parse', it takes a scalar value and | ||||
|     # returns an arrayref. Also define a filter called 'xml_entity' which | ||||
|     # numerically encodes non-ASCII characters. | ||||
|     # | ||||
|     $tt->context->define_vmethod( 'scalar', 'csv_parse', \&parse_csv ); | ||||
|     $tt->context->define_filter( 'xml_entity', \&xml_entity ); | ||||
|  | ||||
| 		# Remove non page sections of the configuration file | ||||
| 		# from the generated list of pages. | ||||
| 		@page_args= grep { $_ ne 'DBI' } @page_args; | ||||
| 		@page_args= grep { $_ ne 'root_template' } @page_args; | ||||
| 		@page_args= grep { $_ ne 'app_paths' } @page_args; | ||||
|     # If command line option all is set, parse configuration file | ||||
|     # for all pages | ||||
|     if ($all) { | ||||
|         @page_args = keys %config; | ||||
|  | ||||
| 	}; | ||||
| 	foreach my $page_arg (@page_args) { | ||||
| 		my %parsed_arg = parse_page_arg($page_arg); | ||||
| 		if (exists($config{$parsed_arg{'page'}})) { | ||||
| 			my $page_config = $config{$parsed_arg{'page'}};  | ||||
| 			$page_config->{'page'} = $parsed_arg{'page'}; | ||||
|         # Remove non page sections of the configuration file | ||||
|         # from the generated list of pages. | ||||
|         @page_args= grep { $_ ne 'DBI' } @page_args; | ||||
|         @page_args= grep { $_ ne 'root_template' } @page_args; | ||||
|         @page_args= grep { $_ ne 'app_paths' } @page_args; | ||||
|  | ||||
| 			# Set page's root_template to the default root_template if the  | ||||
| 			# page root_template property is not set in the configuration file. | ||||
| 			if (exists $page_config->{'root_template'} == 0) { | ||||
| 				$page_config->{'root_template'} = $config{root_template}{content}; | ||||
| 			} | ||||
|     }; | ||||
|     foreach my $page_arg (@page_args) { | ||||
|         my %parsed_arg = parse_page_arg($page_arg); | ||||
|         if (exists($config{$parsed_arg{'page'}})) { | ||||
|             my $page_config = $config{$parsed_arg{'page'}}; | ||||
|             $page_config->{'page'} = $parsed_arg{'page'}; | ||||
|  | ||||
| 			# Set all config root_template properties as default page config properties | ||||
| 			# except the previously set root_template content property | ||||
| 			my @root_args = grep { $_ ne 'content' } keys %{$config{root_template}}; | ||||
| 			foreach my $root_arg (@root_args) { | ||||
| 				if (exists $page_config->{$root_arg} == 0) { | ||||
| 					$page_config->{$root_arg} = $config{root_template}{$root_arg}; | ||||
| 				} | ||||
| 			} | ||||
|             # Set page's root_template to the default root_template if the | ||||
|             # page root_template property is not set in the configuration file. | ||||
|             if (exists $page_config->{'root_template'} == 0) { | ||||
|                 $page_config->{'root_template'} = $config{root_template}{content}; | ||||
|             } | ||||
|  | ||||
| 			if ($page_config->{'multipage'} && $page_config->{'multipage'} eq 'true') { | ||||
| 				# Empty arrayref bug fixed, so count is reduced by 1 | ||||
| #				if (scalar @{$parsed_arg{'ids'}} == 1) { | ||||
| 				if (scalar @{$parsed_arg{'ids'}} == 0) { | ||||
| 				  @{$parsed_arg{'ids'}} = get_ids_from_db($tt, \$page_config); | ||||
| 				} | ||||
| 				foreach my $id (@{$parsed_arg{'ids'}}) { | ||||
| 					$page_config->{'id'} = $id; | ||||
| 					verbose ($verbose, "Generating page: $page_config->{'page'} with id: $id"); | ||||
| 					generate_page($tt, \$page_config, $preview); | ||||
| 				} | ||||
| 			} | ||||
| 			else { | ||||
| 				verbose ($verbose, "Generating page: $page_config->{'page'}"); | ||||
| 				generate_page($tt, \$page_config, $preview); | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
| 			verbose (1, "\nWarning: Page $parsed_arg{'page'} is not defined in the configuration file."); | ||||
| 		} | ||||
| 	} | ||||
|             # Set all config root_template properties as default page config properties | ||||
|             # except the previously set root_template content property | ||||
|             my @root_args = grep { $_ ne 'content' } keys %{$config{root_template}}; | ||||
|             foreach my $root_arg (@root_args) { | ||||
|                 if (exists $page_config->{$root_arg} == 0) { | ||||
|                     $page_config->{$root_arg} = $config{root_template}{$root_arg}; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if ($page_config->{'multipage'} && $page_config->{'multipage'} eq 'true') { | ||||
|                 # Empty arrayref bug fixed, so count is reduced by 1 | ||||
|                 # was: if (scalar @{$parsed_arg{'ids'}} == 1) { | ||||
|                 if (scalar @{$parsed_arg{'ids'}} == 0) { | ||||
|                     @{$parsed_arg{'ids'}} = get_ids_from_db($tt, \$page_config); | ||||
|                 } | ||||
|                 foreach my $id (@{$parsed_arg{'ids'}}) { | ||||
|                     $page_config->{'id'} = $id; | ||||
|                     verbose ($verbose, "Generating page: $page_config->{'page'} with id: $id"); | ||||
|                     generate_page($tt, \$page_config, $preview); | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 verbose ($verbose, "Generating page: $page_config->{'page'}"); | ||||
|                 generate_page($tt, \$page_config, $preview); | ||||
|             } | ||||
|         } | ||||
|         else { | ||||
|             verbose (1, "\nWarning: Page $parsed_arg{'page'} is not defined in the configuration file."); | ||||
|         } | ||||
|     } | ||||
|     verbose (1, "\nFinished processing the files."); | ||||
| 	return 0; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| sub get_template_html (\%@)  { | ||||
| 	# For an HTML based Template file, define the  | ||||
| 	# template start and end tags to also function as  | ||||
| 	# HTML comments to make the template file valid HTML. | ||||
| 	# | ||||
| 	return Template->new({ | ||||
| 			INCLUDE_PATH => $_[1]{templates_path}, | ||||
| 			OUTPUT_PATH	 => $_[1]{output_path}, | ||||
| 			EVAL_PERL    => 1, | ||||
| 			START_TAG	 => '<!--%', | ||||
| 			END_TAG		 => '%-->', | ||||
| 			PRE_CHOMP  => 1, | ||||
| 			POST_CHOMP => 1, | ||||
| 			CONSTANTS    => { | ||||
| 				database => $_[0]{database}, | ||||
| 				driver   => $_[0]{driver}, | ||||
| 				user     => $_[0]{user}, | ||||
| 				password => $_[0]{password}, | ||||
| 			} | ||||
| 		}) || die $Template::ERROR, "\n"; | ||||
|     # For an HTML based Template file, define the | ||||
|     # template start and end tags to also function as | ||||
|     # HTML comments to make the template file valid HTML. | ||||
|     # | ||||
|     return Template->new( | ||||
|         {   INCLUDE_PATH => $_[1]{templates_path}, | ||||
|             OUTPUT_PATH  => $_[1]{output_path}, | ||||
|             ENCODING     => 'utf8', | ||||
|             EVAL_PERL    => 1, | ||||
|             START_TAG    => '<!--%', | ||||
|             END_TAG      => '%-->', | ||||
|             PRE_CHOMP    => 1, | ||||
|             POST_CHOMP   => 1, | ||||
|             CONSTANTS    => { | ||||
|                 database => $_[0]{database}, | ||||
|                 driver   => $_[0]{driver}, | ||||
|                 user     => $_[0]{user}, | ||||
|                 password => $_[0]{password}, | ||||
|             } | ||||
|         } | ||||
|     ) || die $Template::ERROR, "\n"; | ||||
|  | ||||
| } | ||||
|  | ||||
| sub generate_page  { | ||||
| 	my ($tt, $config, $preview) = @_; | ||||
| 	my $html; | ||||
| 	if (!$preview) { | ||||
| 		$html = get_filename($$config);  | ||||
| 	} | ||||
| 	$tt->process($$config->{root_template}, $$config, $html) | ||||
| 	|| die $tt->error(), "\n"; | ||||
| sub generate_page { | ||||
|     my ( $tt, $config, $preview ) = @_; | ||||
|     my $html; | ||||
|     if ( !$preview ) { | ||||
|         $html = get_filename($$config); | ||||
|     } | ||||
|     $tt->process( $$config->{root_template}, | ||||
|         $$config, $html, { binmode => ':utf8' } ) | ||||
|         || die $tt->error(), "\n"; | ||||
|  | ||||
| } | ||||
|  | ||||
| sub verbose { | ||||
| 	my ($verbose, $message) = @_; | ||||
| 	if ($verbose) { | ||||
| 		if ($verbose ne 'quiet') {  | ||||
| 			print STDOUT "$message\n"; | ||||
| 		} | ||||
| 	} | ||||
| 	else { | ||||
| 		STDOUT->autoflush(1); | ||||
| 		print STDOUT "."; | ||||
| 	}; | ||||
|         my ($verbose, $message) = @_; | ||||
|         if ($verbose) { | ||||
|                 if ($verbose ne 'quiet') { | ||||
|                         print STDOUT "$message\n"; | ||||
|                 } | ||||
|         } | ||||
|         else { | ||||
|                 STDOUT->autoflush(1); | ||||
|                 print STDOUT "."; | ||||
|         }; | ||||
| } | ||||
|  | ||||
| sub parse_page_arg { | ||||
| 	my ($page_arg) =  @_; | ||||
| 	# Split page name from page ids if available. | ||||
| 	my ($page, $ids) = split(/=/, $page_arg); | ||||
| 	#my @ids = []; | ||||
| 	my @ids; | ||||
|     my ($page_arg) =  @_; | ||||
|     # Split page name from page ids if available. | ||||
|     my ($page, $ids) = split(/=/, $page_arg); | ||||
|     my @ids; | ||||
|  | ||||
| 	if(!$ids) { | ||||
| 		$ids = ""; | ||||
| 	} | ||||
| 	else { | ||||
| 		# Parse the page ids and push them onto @ids array  | ||||
| 		my @ids_by_comma = split(/\,/, $ids); | ||||
| 		foreach my $id_by_comma (@ids_by_comma) { | ||||
| 			my @ids_for_range = split(/\.\./, $id_by_comma); | ||||
| 			if ((scalar @ids_for_range) == 2) { | ||||
| 				push @ids, $ids_for_range[0]..$ids_for_range[1];  | ||||
| 			} | ||||
| 			elsif ((scalar @ids_for_range) == 1) { | ||||
| 				push @ids, $ids_for_range[0]; | ||||
| 			} | ||||
| 			else { | ||||
| 				verbose (1, "\nWarning: Page $page id range $id_by_comma could not be parsed."); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return ('page' => $page, 'ids' => [@ids]); | ||||
|     if(!$ids) { | ||||
|         $ids = ""; | ||||
|     } | ||||
|     else { | ||||
|         # Parse the page ids and push them onto @ids array | ||||
|         my @ids_by_comma = split(/\,/, $ids); | ||||
|         foreach my $id_by_comma (@ids_by_comma) { | ||||
|             my @ids_for_range = split(/\.\./, $id_by_comma); | ||||
|             if ((scalar @ids_for_range) == 2) { | ||||
|                 push @ids, $ids_for_range[0]..$ids_for_range[1]; | ||||
|             } | ||||
|             elsif ((scalar @ids_for_range) == 1) { | ||||
|                 push @ids, $ids_for_range[0]; | ||||
|             } | ||||
|             else { | ||||
|                 verbose (1, "\nWarning: Page $page id range $id_by_comma could not be parsed."); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return ('page' => $page, 'ids' => [@ids]); | ||||
| } | ||||
|  | ||||
| sub get_ids_from_db { | ||||
| 	# Use a template to generate a string of page identifiers. | ||||
| 	# The template should return the string in the form of  | ||||
| 	# <comma><identifier><comma><identifier>... | ||||
| 	# | ||||
| 	my ($tt, $config)  = @_; | ||||
| 	my $selected_ids = ""; | ||||
| 	my $id_template = "ids-$$config->{'page'}.tpl.html"; | ||||
|         # Use a template to generate a string of page identifiers. | ||||
|         # The template should return the string in the form of | ||||
|         # <comma><identifier><comma><identifier>... | ||||
|         # | ||||
|         my ($tt, $config)  = @_; | ||||
|         my $selected_ids = ""; | ||||
|         my $id_template = "ids-$$config->{'page'}.tpl.html"; | ||||
|  | ||||
| 	$tt->process($id_template, $$config, \$selected_ids) | ||||
| 	|| die $tt->error(), "\n"; | ||||
|         $tt->process($id_template, $$config, \$selected_ids) | ||||
|         || die $tt->error(), "\n"; | ||||
|  | ||||
| 	# Starts with a newline and comma | ||||
| 	return split(/,/, substr($selected_ids, 2)); | ||||
|         # Starts with a newline and comma | ||||
|         return split(/,/, substr($selected_ids, 2)); | ||||
| } | ||||
|  | ||||
| sub get_filename { | ||||
| 	my ($config) = @_; | ||||
| 	my $filename = "output.html"; | ||||
| 	my $base_path = ""; | ||||
|         my ($config) = @_; | ||||
|         my $filename = "output.html"; | ||||
|         my $base_path = ""; | ||||
|  | ||||
| 	if ($$config{'filename'}) { | ||||
| 		if (substr($$config{'filename'}, -1) eq '/') { | ||||
| 			$base_path = $$config{'filename'}; | ||||
| 		} | ||||
| 		else { | ||||
| 			$filename = $$config{'filename'}; | ||||
| 			my $padded_index = ""; | ||||
| 			if (exists $$config{'id'} && $$config{'id'} ne "") { | ||||
| 				$padded_index = sprintf("%04d", $$config{'id'}); | ||||
| 			} | ||||
| 			$filename =~ s/\[id\]/$padded_index/; | ||||
| 		    return $filename; | ||||
| 		} | ||||
| 	} | ||||
| 	# Default naming if full filename configuration is not supplied. | ||||
| 	if ($$config{'multipage'} && $$config{'multipage'} eq 'true') { | ||||
| 		my $padded_index = sprintf("%04d", $$config{'id'}); | ||||
| 		$filename = "$base_path$$config{'page'}${padded_index}.html"; | ||||
| 	} | ||||
| 	else { | ||||
| 		$filename = "$base_path$$config{'page'}.html"; | ||||
| 	} | ||||
| 	return $filename; | ||||
|         if ($$config{'filename'}) { | ||||
|                 if (substr($$config{'filename'}, -1) eq '/') { | ||||
|                         $base_path = $$config{'filename'}; | ||||
|                 } | ||||
|                 else { | ||||
|                         $filename = $$config{'filename'}; | ||||
|                         my $padded_index = ""; | ||||
|                         if (exists $$config{'id'} && $$config{'id'} ne "") { | ||||
|                                 $padded_index = sprintf("%04d", $$config{'id'}); | ||||
|                         } | ||||
|                         $filename =~ s/\[id\]/$padded_index/; | ||||
|                     return $filename; | ||||
|                 } | ||||
|         } | ||||
|         # Default naming if full filename configuration is not supplied. | ||||
|         if ($$config{'multipage'} && $$config{'multipage'} eq 'true') { | ||||
|                 my $padded_index = sprintf("%04d", $$config{'id'}); | ||||
|                 $filename = "$base_path$$config{'page'}${padded_index}.html"; | ||||
|         } | ||||
|         else { | ||||
|                 $filename = "$base_path$$config{'page'}.html"; | ||||
|         } | ||||
|         return $filename; | ||||
| } | ||||
|  | ||||
| sub print_available_pages { | ||||
| 	# Load config file | ||||
| 	read_config "site.cfg" => my %config; | ||||
|     # Load config file | ||||
|     read_config "site.cfg" => my %config; | ||||
|  | ||||
| 	my @page_args = sort (keys %config); | ||||
|     my @page_args = sort ( keys %config ); | ||||
|  | ||||
| 	# Remove non page sections of the configuration file | ||||
| 	# from the generated list of pages. | ||||
| 	@page_args= grep { $_ ne 'DBI' } @page_args; | ||||
| 	@page_args= grep { $_ ne 'root_template' } @page_args; | ||||
|     # Remove non page sections of the configuration file | ||||
|     # from the generated list of pages. | ||||
|     @page_args = grep { $_ ne 'DBI' } @page_args; | ||||
|     @page_args = grep { $_ ne 'root_template' } @page_args; | ||||
|  | ||||
| 	foreach my $page_arg (@page_args) { | ||||
| 		print "$page_arg\n"; | ||||
| 	} | ||||
| 	exit; | ||||
|     foreach my $page_arg (@page_args) { | ||||
|         print "$page_arg\n"; | ||||
|     } | ||||
|     exit; | ||||
| } | ||||
|  | ||||
| #===  FUNCTION  ================================================================ | ||||
| #         NAME: parse_csv | ||||
| #      PURPOSE: Parses a simple string containing CSV data | ||||
| #   PARAMETERS: $csv_in         CSV string | ||||
| #      RETURNS: An arrayref containing the parsed CSV elements | ||||
| #  DESCRIPTION: The Text::CSV_XS module instance is created with the option | ||||
| #               'allow_whitespace' to be forgiving of any spaces around the | ||||
| #               CSV elements and to strip them. Also, 'allow_loose_quotes' is | ||||
| #               forgiving of really messed up CSV. | ||||
| #       THROWS: No exceptions | ||||
| #     COMMENTS: None | ||||
| #     SEE ALSO: N/A | ||||
| #=============================================================================== | ||||
| sub parse_csv { | ||||
|     my ($csv_in) = @_; | ||||
|  | ||||
|     my $csv = Text::CSV_XS->new( | ||||
|         {   binary             => 1, | ||||
|             auto_diag          => 1, | ||||
|             allow_whitespace   => 1, | ||||
|             allow_loose_quotes => 1 | ||||
|         } | ||||
|     ); | ||||
|     my $status = $csv->parse($csv_in); | ||||
|     unless ( $status ) { | ||||
|         warn "Failed to parse '$csv_in'\n" ; | ||||
|         return; | ||||
|     } | ||||
|     my @fields = $csv->fields(); | ||||
|  | ||||
|     return \@fields; | ||||
| } | ||||
|  | ||||
| #===  FUNCTION  ================================================================ | ||||
| #         NAME: xml_entity | ||||
| #      PURPOSE: Static filter to encode Unicode for XML | ||||
| #   PARAMETERS: $text           String to be processed | ||||
| #      RETURNS: Processed text | ||||
| #  DESCRIPTION: | ||||
| #       THROWS: No exceptions | ||||
| #     COMMENTS: None | ||||
| #     SEE ALSO: N/A | ||||
| #=============================================================================== | ||||
| sub xml_entity { | ||||
|     my ($text) = @_; | ||||
|  | ||||
|     encode_entities_numeric( $text ); | ||||
|  | ||||
|     return $text; | ||||
| } | ||||
|  | ||||
| # vim: syntax=perl:ts=8:sw=4:et:ai:tw=78:fo=tcrqn21:fdm=marker | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| <!--% query_episodes = 'SELECT  | ||||
|         eps.id,  | ||||
|         eps.explicit,  | ||||
|         eps.date, eps.license, eps.title, eps.summary,  | ||||
| 		eps.duration, eps.notes, eps.tags, | ||||
|         hosts.hostid,  | ||||
|         hosts.host, hosts.email, hosts.local_image,  | ||||
| 		miniseries.name AS series, miniseries.id AS seriesid | ||||
|     FROM eps  | ||||
| 	INNER JOIN hosts ON eps.hostid = hosts.hostid  | ||||
| 	INNER JOIN miniseries ON eps.series = miniseries.id | ||||
| 	WHERE eps.date <= date(\'now\') | ||||
| 	ORDER BY eps.id + 0 DESC' | ||||
| <!--% query_episodes = 'SELECT | ||||
|         eps.id, | ||||
|         eps.explicit, | ||||
|         eps.date, eps.license, eps.title, eps.summary, | ||||
|         eps.duration, eps.notes, eps.tags, | ||||
|         hosts.hostid, | ||||
|         hosts.host, hosts.email, hosts.local_image, | ||||
|         miniseries.name AS series, miniseries.id AS seriesid | ||||
|     FROM eps | ||||
|         INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
|         INNER JOIN miniseries ON eps.series = miniseries.id | ||||
|         WHERE eps.date <= date(\'now\') | ||||
|         ORDER BY eps.id + 0 DESC' | ||||
| %--> | ||||
|  | ||||
|   | ||||
| @@ -1,23 +1,26 @@ | ||||
| <!--% USE DBI(constants.driver, constants.user, constants.password) %--> | ||||
| <!--% query_hpr_feed = DBI.prepare(' | ||||
| 	SELECT  | ||||
| 	eps.id,  | ||||
| 	eps.explicit,  | ||||
| 	DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\',	 | ||||
| 	eps.license, eps.duration, | ||||
| 	eps.title, eps.summary, eps.tags,  | ||||
| 	eps.notes, | ||||
| 	hosts.local_image, | ||||
| 	hosts.hostid,  | ||||
| 	hosts.host, hosts.email, | ||||
| 	miniseries.name AS series, miniseries.id AS seriesid | ||||
| 	FROM eps  | ||||
| 	INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
| 	INNER JOIN miniseries ON eps.series = miniseries.id | ||||
| 	WHERE eps.date < DATE_ADD(NOW(), INTERVAL 1 DAY) | ||||
| 	ORDER BY eps.date DESC  | ||||
| 	LIMIT 10 | ||||
|         SELECT | ||||
|             eps.id, | ||||
|             eps.explicit, | ||||
|             DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\', | ||||
|             eps.license, eps.duration, | ||||
|             eps.title, eps.summary, eps.tags, | ||||
|             eps.notes, | ||||
|             hosts.local_image, | ||||
|             hosts.hostid, | ||||
|             hosts.host, hosts.email, | ||||
|             miniseries.name AS series, miniseries.id AS seriesid, | ||||
|             assets.size AS length | ||||
|         FROM eps | ||||
|         INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
|         INNER JOIN miniseries ON eps.series = miniseries.id | ||||
|         INNER JOIN assets ON eps.id = assets.episode_id | ||||
|         WHERE eps.date <= UTC_DATE() | ||||
|         AND assets.extension = ? | ||||
|         ORDER BY eps.date DESC | ||||
|         LIMIT 10 | ||||
| ') | ||||
| %--> | ||||
| <!--% feed_result = query_hpr_feed.execute() %--> | ||||
| <!--% feed_result = query_hpr_feed.execute(media_file_extension) %--> | ||||
|  | ||||
|   | ||||
| @@ -1,23 +1,26 @@ | ||||
| <!--% USE DBI(constants.driver, constants.user, constants.password) %--> | ||||
| <!--% query_hpr_feed = DBI.prepare(' | ||||
| 	SELECT  | ||||
| 	eps.id,  | ||||
| 	eps.explicit,  | ||||
| 	strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date, | ||||
| 	eps.license, eps.duration, | ||||
| 	eps.title, eps.summary, eps.tags,  | ||||
| 	eps.notes, | ||||
| 	hosts.local_image, | ||||
| 	hosts.hostid,  | ||||
| 	hosts.host, hosts.email, | ||||
| 	miniseries.name AS series, miniseries.id AS seriesid | ||||
| 	FROM eps  | ||||
| 	INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
| 	INNER JOIN miniseries ON eps.series = miniseries.id | ||||
| 	WHERE eps.date < date(\'now\', \'+1 days\') | ||||
| 	ORDER BY eps.date DESC  | ||||
| 	LIMIT 10 | ||||
|         SELECT | ||||
|             eps.id, | ||||
|             eps.explicit, | ||||
|             strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date, | ||||
|             eps.license, eps.duration, | ||||
|             eps.title, eps.summary, eps.tags, | ||||
|             eps.notes, | ||||
|             hosts.local_image, | ||||
|             hosts.hostid, | ||||
|             hosts.host, hosts.email, | ||||
|             miniseries.name AS series, miniseries.id AS seriesid, | ||||
|             assets.size AS length | ||||
|         FROM eps | ||||
|         INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
|         INNER JOIN miniseries ON eps.series = miniseries.id | ||||
|         INNER JOIN assets ON eps.id = assets.episode_id | ||||
|         WHERE eps.date <= date(\'now\') | ||||
|         AND assets.extension = ? | ||||
|         ORDER BY eps.date DESC | ||||
|         LIMIT 10 | ||||
| ') | ||||
| %--> | ||||
| <!--% feed_result = query_hpr_feed.execute() %--> | ||||
| <!--% feed_result = query_hpr_feed.execute(media_file_extension) %--> | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,25 @@ | ||||
| <!--% USE DBI(constants.driver, constants.user, constants.password) %--> | ||||
| <!--% query_hpr_feed = DBI.prepare(' | ||||
| 	SELECT  | ||||
| 	eps.id,  | ||||
| 	eps.explicit,  | ||||
| 	DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\', | ||||
| 	eps.license, eps.duration, | ||||
| 	eps.title, eps.summary, eps.tags,  | ||||
| 	eps.notes, | ||||
| 	hosts.local_image, | ||||
| 	hosts.hostid,  | ||||
| 	hosts.host, hosts.email, | ||||
| 	miniseries.name AS series, miniseries.id AS seriesid | ||||
| 	FROM eps  | ||||
| 	INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
| 	INNER JOIN miniseries ON eps.series = miniseries.id | ||||
| 	WHERE eps.date < DATE_ADD(NOW(), INTERVAL 1 DAY) | ||||
| 	ORDER BY eps.date DESC  | ||||
|         SELECT | ||||
|             eps.id, | ||||
|             eps.explicit, | ||||
|             DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\', | ||||
|             eps.license, eps.duration, | ||||
|             eps.title, eps.summary, eps.tags, | ||||
|             eps.notes, | ||||
|             hosts.local_image, | ||||
|             hosts.hostid, | ||||
|             hosts.host, hosts.email, | ||||
|             miniseries.name AS series, miniseries.id AS seriesid, | ||||
|             assets.size AS length | ||||
|         FROM eps | ||||
|         INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
|         INNER JOIN miniseries ON eps.series = miniseries.id | ||||
|         INNER JOIN assets ON eps.id = assets.episode_id | ||||
|         WHERE eps.date < UTC_DATE() | ||||
|         AND assets.extension = ? | ||||
|         ORDER BY eps.date DESC | ||||
| ') | ||||
| %--> | ||||
| <!--% feed_result = query_hpr_feed.execute() %--> | ||||
| <!--% feed_result = query_hpr_feed.execute(media_file_extension) %--> | ||||
|  | ||||
|   | ||||
| @@ -1,22 +1,25 @@ | ||||
| <!--% USE DBI(constants.driver, constants.user, constants.password) %--> | ||||
| <!--% query_hpr_feed = DBI.prepare(' | ||||
| 	SELECT  | ||||
| 	eps.id,  | ||||
| 	eps.explicit,  | ||||
| 	strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date, | ||||
| 	eps.license, eps.duration, | ||||
| 	eps.title, eps.summary, eps.tags,  | ||||
| 	eps.notes, | ||||
| 	hosts.local_image, | ||||
| 	hosts.hostid,  | ||||
| 	hosts.host, hosts.email, | ||||
| 	miniseries.name AS series, miniseries.id AS seriesid | ||||
| 	FROM eps  | ||||
| 	INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
| 	INNER JOIN miniseries ON eps.series = miniseries.id | ||||
| 	WHERE eps.date < date(\'now\', \'+1 days\') | ||||
| 	ORDER BY eps.date DESC  | ||||
|         SELECT | ||||
|             eps.id, | ||||
|             eps.explicit, | ||||
|             strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date, | ||||
|             eps.license, eps.duration, | ||||
|             eps.title, eps.summary, eps.tags, | ||||
|             eps.notes, | ||||
|             hosts.local_image, | ||||
|             hosts.hostid, | ||||
|             hosts.host, hosts.email, | ||||
|             miniseries.name AS series, miniseries.id AS seriesid, | ||||
|             assets.size AS length | ||||
|         FROM eps | ||||
|         INNER JOIN hosts ON eps.hostid = hosts.hostid | ||||
|         INNER JOIN miniseries ON eps.series = miniseries.id | ||||
|         INNER JOIN assets ON eps.id = assets.episode_id | ||||
|         WHERE eps.date <= date(\'now\') | ||||
|         AND assets.extension = ? | ||||
|         ORDER BY eps.date DESC | ||||
| ') | ||||
| %--> | ||||
| <!--% feed_result = query_hpr_feed.execute() %--> | ||||
| <!--% feed_result = query_hpr_feed.execute(media_file_extension) %--> | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| <!--% USE date %--> | ||||
| <!--% PROCESS 'shared-utils.tpl.html' %--> | ||||
| <?xml version="1.0" encoding="UTF-8" ?> | ||||
| <rss version="2.0"  | ||||
| 	xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"  | ||||
| 	xmlns:atom="http://www.w3.org/2005/Atom"  | ||||
| <rss version="2.0" | ||||
| 	xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0" | ||||
| 	xmlns:atom="http://www.w3.org/2005/Atom" | ||||
| 	xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" > | ||||
| <channel> | ||||
|   <title>Hacker Public Radio</title> | ||||
| @@ -22,14 +22,14 @@ | ||||
|   <itunes:author>Hacker Public Radio</itunes:author> | ||||
|   <itunes:keywords>Community Radio, Tech Interviews, Linux, Open, Hobby, Software Freedom</itunes:keywords> | ||||
|   <copyright>Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) License</copyright> | ||||
|   <managingEditor>feedback@NOSPAM-hackerpublicradio.org (HPR Feedback)</managingEditor>  | ||||
|   <managingEditor>feedback@NOSPAM-hackerpublicradio.org (HPR Feedback)</managingEditor> | ||||
| <!--   <author>feedback@NOSPAM-hackerpublicradio.org (HPR Feedback)</author> --> | ||||
|   <itunes:owner>     | ||||
|   <itunes:owner> | ||||
|     <itunes:name>HPR Volunteer</itunes:name> | ||||
|     <itunes:email>admin@hackerpublicradio.org</itunes:email> | ||||
|   </itunes:owner> | ||||
|   <webMaster>admin@hackerpublicradio.org (HPR Volunteer)</webMaster>  | ||||
|   <generator>site-generator</generator>  | ||||
|   <webMaster>admin@hackerpublicradio.org (HPR Volunteer)</webMaster> | ||||
|   <generator>site-generator</generator> | ||||
|   <docs>http://www.rssboard.org/rss-specification</docs> | ||||
|   <ttl>43200</ttl> | ||||
|   <skipDays> | ||||
| @@ -39,7 +39,7 @@ | ||||
|   <image> | ||||
|     <url>https://www.hackerpublicradio.org/images/hpr_feed_small.png</url> | ||||
|     <title>Hacker Public Radio</title> | ||||
|     <link>https://www.hackerpublicradio.org/about.php</link> | ||||
|     <link>https://www.hackerpublicradio.org/about.html</link> | ||||
|     <description>The Hacker Public Radio Old Microphone Logo</description> | ||||
|     <height>164</height> | ||||
|     <width>144</width> | ||||
| @@ -51,7 +51,7 @@ | ||||
|   <googleplay:category text="Technology"/> | ||||
|   <atom:link href="https://www.hackerpublicradio.org/<!--% filename %-->" rel="self" type="application/rss+xml" /> | ||||
|   <pubDate><!--% format_feed_date(date.now) %--></pubDate> | ||||
|    | ||||
|  | ||||
|   <!--% INCLUDE $content %--> | ||||
|   </channel> | ||||
| </rss> | ||||
|   | ||||
| @@ -12,7 +12,11 @@ from the series <em><a href="<!--% baseurl %-->series/<!--% zero_pad_left(series | ||||
| <!--% END %--> | ||||
|  | ||||
| <!--% MACRO display_tags(tags) BLOCK %--> | ||||
| 	<span><label>Tags:</label> <em><!--% tags %--></em>.</span> | ||||
|     <span><label>Tags:</label> <em> | ||||
|         <!--% FOREACH tag IN tags.csv_parse %--> | ||||
|         <a href="<!--% absolute_path(baseurl) %-->tags.html#<!--% tag.lower %-->"><!--% tag %--></a><!--% IF loop.count == loop.size %-->.<!--% ELSE %-->,<!--% END %--> | ||||
|         <!--% END %--></em> | ||||
|     </span> | ||||
| <!--% END %--> | ||||
|  | ||||
| <!--% MACRO display_listen_in(eps_id, episode_type) BLOCK %--> | ||||
|   | ||||
| @@ -1,23 +1,24 @@ | ||||
| <!--% PROCESS 'shared-utils.tpl.html' %--> | ||||
| <!--% MACRO display_item(episode, file_extension, audio_mime_type) BLOCK %--> | ||||
| <!--% USE HTML.Strip %--> | ||||
| <!--% IF audio_mime_type == ""  %--> | ||||
| <!--% audio_mime_type = 'ogg' %--> | ||||
| <!--% END %--> | ||||
| <item> | ||||
| 	  <itunes:explicit><!--% display_explicit_feed(episode.explicit) %--></itunes:explicit> | ||||
|     <itunes:explicit><!--% display_explicit_feed(episode.explicit) %--></itunes:explicit> | ||||
|     <googleplay:explicit><!--% display_explicit_feed(episode.explicit) %--></googleplay:explicit> | ||||
| 	<title>HPR<!--% zero_pad_left(episode.id) %-->: <!--% episode.title %--></title> | ||||
|     <title>HPR<!--% zero_pad_left(episode.id) %-->: <!--% episode.title %--></title> | ||||
|     <author><!--% episode.email %--> (<!--% episode.host %-->)</author> | ||||
|     <googleplay:author><!--% episode.email %--> (<!--% episode.host %-->)</googleplay:author> | ||||
|     <itunes:author><!--% episode.email %--> (<!--% episode.host %-->)</itunes:author> | ||||
|     <googleplay:image href="https://www.hackerpublicradio.org/images/hpr_feed_itunes.png"/> | ||||
| 	<link>https://www.hackerpublicradio.org/eps/hpr/<!--% zero_pad_left(episode.id) %-->/index.html</link> | ||||
|     <link>https://www.hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->/index.html</link> | ||||
|     <description><![CDATA[<!--% episode.notes %-->]]> | ||||
| </description> | ||||
|     <itunes:summary><![CDATA[<!--% episode.notes %-->]]> | ||||
|     <itunes:summary><![CDATA[<!--% episode.notes.substr(0, 4000) | html_strip | xml_entity %-->]]> | ||||
| </itunes:summary> | ||||
|     <pubDate><!--% format_feed_date(episode.date) %--></pubDate> | ||||
|     <enclosure url="http://hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->.<!--% file_extension %-->" length="<!--% episode.duration * 1000 %-->" type="audio/<!--% audio_mime_type %-->"/> | ||||
| 	<guid>http://hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->.<!--% file_extension %--></guid> | ||||
|     <enclosure url="http://hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->.<!--% file_extension %-->" length="<!--% episode.length %-->" type="audio/<!--% audio_mime_type %-->"/> | ||||
|     <guid>http://hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->.<!--% file_extension %--></guid> | ||||
|   </item> | ||||
| <!--% END %--> | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| <!--% MACRO zero_pad_left(word, pad_length) BLOCK %--> | ||||
| 	<!--% IF pad_length %--> | ||||
| 		<!--% zero_pad_format = "%0${pad_length}s" %--> | ||||
| 	<!--% ELSE %--> | ||||
| 		<!--% zero_pad_format = "%04s" %--> | ||||
| 	<!--% END %--> | ||||
| 	<!--% USE String(word) %--> | ||||
| 	<!--% String.format(zero_pad_format) %--> | ||||
|         <!--% IF pad_length %--> | ||||
|                 <!--% zero_pad_format = "%0${pad_length}s" %--> | ||||
|         <!--% ELSE %--> | ||||
|                 <!--% zero_pad_format = "%04s" %--> | ||||
|         <!--% END %--> | ||||
|         <!--% USE String(word) %--> | ||||
|         <!--% String.format(zero_pad_format) %--> | ||||
| <!--% END %--> | ||||
|  | ||||
| <!--% MACRO display_choice(choice, display_when_true, display_when_false) BLOCK %--> | ||||
| @@ -17,7 +17,7 @@ | ||||
| <!--% seconds = duration_sec % 60 %--> | ||||
| <!--% USE format %--> | ||||
| <!--% minutes_only = format("%d") %--> | ||||
| <!--% minutes =	minutes_only(duration_sec / 60) %--> | ||||
| <!--% minutes = minutes_only(duration_sec / 60) %--> | ||||
| <!--% hours_only = format("%d") %--> | ||||
| <!--% hours = hours_only(minutes / 60) %--> | ||||
| <!--% IF hours >= 1 %--> | ||||
| @@ -57,23 +57,23 @@ | ||||
| <!--% END %--> | ||||
|  | ||||
| <!--% MACRO media_path(episode_id, episode_type, media_type, baseurl, media_baseurl) BLOCK %--> | ||||
| 	<!--% IF episode_type == "twat" %--> | ||||
| 		<!--% padding = 3 %--> | ||||
| 		<!--% media_folder = "eps/"; padding = 3 %--> | ||||
| 	<!--% ELSE %--> | ||||
| 		<!--% media_folder = "local/" %--> | ||||
| 	<!--% END %--> | ||||
| 	<!--% IF media_baseurl %--> | ||||
| 		<!--% transcription_types = "txt srt vtt" %--> | ||||
| 		<!--% USE String(transcription_types) %--> | ||||
| 		<!--% USE String(media_baseurl) %--> | ||||
| 			<!--% IF transcription_types.search(media_type) && media_baseurl.search('archive.org') %--> | ||||
| 			<!--% media_baseurl = "${media_baseurl}hpr\$eps_id/" %--> | ||||
| 		<!--% END %--> | ||||
| 		<!--% media_folder = "" %--> | ||||
| 		<!--% media_baseurl = media_baseurl.replace('\$eps_id', zero_pad_left(episode_id)) %--> | ||||
| 	<!--% END %--> | ||||
| 	<!--% media_basepath(baseurl, media_baseurl) %--><!--% media_folder %--><!--% episode_type %--><!--% zero_pad_left(episode_id, padding) %-->.<!--% media_type %--> | ||||
|         <!--% IF episode_type == "twat" %--> | ||||
|                 <!--% padding = 3 %--> | ||||
|                 <!--% media_folder = "eps/"; padding = 3 %--> | ||||
|         <!--% ELSE %--> | ||||
|                 <!--% media_folder = "local/" %--> | ||||
|         <!--% END %--> | ||||
|         <!--% IF media_baseurl %--> | ||||
|                 <!--% transcription_types = "txt srt vtt" %--> | ||||
|                 <!--% USE String(transcription_types) %--> | ||||
|                 <!--% USE String(media_baseurl) %--> | ||||
|                         <!--% IF transcription_types.search(media_type) && media_baseurl.search('archive.org') %--> | ||||
|                         <!--% media_baseurl = "${media_baseurl}hpr\$eps_id/" %--> | ||||
|                 <!--% END %--> | ||||
|                 <!--% media_folder = "" %--> | ||||
|                 <!--% media_baseurl = media_baseurl.replace('\$eps_id', zero_pad_left(episode_id)) %--> | ||||
|         <!--% END %--> | ||||
|         <!--% media_basepath(baseurl, media_baseurl) %--><!--% media_folder %--><!--% episode_type %--><!--% zero_pad_left(episode_id, padding) %-->.<!--% media_type %--> | ||||
| <!--% END %--> | ||||
|  | ||||
| <!--% MACRO step_navigation(baseurl, links, folder) BLOCK %--> | ||||
| @@ -93,7 +93,3 @@ | ||||
|     <!--% END %--> | ||||
|     <a href="<!--% absolute_path(baseurl) %-->eps/<!--% folder %--><!--% zero_pad_left(links.latest) %-->/index.html" rel="last">Latest >></a></small> | ||||
| <!--% END %--> | ||||
|  | ||||
| <!-- | ||||
|     vim: syntax=html:ts=8:sw=4:tw=78:et:ai: | ||||
| --> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user