Merge pull request 'Fixing issue #140' (#155) from I140_Convert_the_RSS_feeds_from_php_to_the_static_site into main
Reviewed-on: #155
This commit is contained in:
commit
c263646cf2
570
site-generator
570
site-generator
@ -1,88 +1,92 @@
|
|||||||
#!/usr/bin/perl
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# {{{ POD documentation
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
site-generator - HPR Site Generator
|
site-generator - HPR Site Generator
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=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
|
-a, --all generate all pages defined in configuration file
|
||||||
-c, --configuration path to configuration file
|
-c, --configuration path to configuration file
|
||||||
-l, --list print list of configured pages
|
-l, --list print list of configured pages
|
||||||
-p, --preview print generated pages to standard out
|
-p, --preview print generated pages to standard out
|
||||||
-q, --quiet suppress progress information while generating pages
|
-q, --quiet suppress progress information while generating pages
|
||||||
-v, --verbose print extended progress information while generating pages
|
-v, --verbose print extended progress information while generating pages
|
||||||
--help print this help message
|
--help print this help message
|
||||||
|
|
||||||
Where I<PAGE> is a file name of a web page
|
Where I<PAGE> is a file name of a web page
|
||||||
or the special I<ALL> (to generate all pages).
|
or the special I<ALL> (to generate all pages).
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
Generate two specific pages:
|
Generate two specific pages:
|
||||||
site-generator index about
|
site-generator index about
|
||||||
|
|
||||||
Generate the whole site:
|
Generate the whole site:
|
||||||
site-generator --all
|
site-generator --all
|
||||||
|
|
||||||
Generate pages based on the same template:
|
Generate pages based on the same template:
|
||||||
site-generator correspondent=1,3,5..10
|
site-generator correspondent=1,3,5..10
|
||||||
|
|
||||||
Generate two specific pages with a different configuration:
|
Generate two specific pages with a different configuration:
|
||||||
site-generator --configuration=site_sqlite.cfg index about
|
site-generator --configuration=site_sqlite.cfg index about
|
||||||
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=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
|
=head1 INSTALLATION
|
||||||
|
|
||||||
With SQLite
|
With SQLite
|
||||||
* Create the sqlite3 database from the hpr.sql MySQL dump file available on
|
* 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"
|
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
|
and should be located in the root of the project directory. The name and
|
||||||
location can be set in the site.cfg file.
|
location can be set in the site.cfg file.
|
||||||
* An "update-hpr.sh" helper script is available in the utils directory. This
|
* 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,
|
script will download the hpr.sql file, convert it to the SQLite hpr.db file,
|
||||||
and regenerate the website using the site-generator.
|
and regenerate the website using the site-generator.
|
||||||
1. `cd` into the root of the project directory
|
1. `cd` into the root of the project directory
|
||||||
2. Run `./utils/update-hpr.sh`
|
2. Run `./utils/update-hpr.sh`
|
||||||
* SQLite v3.8.3 or greater is recommended. CTE WITH clauses are used in some template queries.
|
* 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.
|
Must convert WITH clauses to sub-queries when using earlier versions of SQLite.
|
||||||
|
|
||||||
With MySQL
|
With MySQL
|
||||||
* Create database hpr_hpr in the MySQL server from HPR dump file.
|
* Create database hpr_hpr in the MySQL server from HPR dump file.
|
||||||
- sudo mysql --host=localhost < hpr.sql
|
- sudo mysql --host=localhost < hpr.sql
|
||||||
* Create a user that will be used by the site-generator.
|
* Create a user that will be used by the site-generator.
|
||||||
- Suggested username: hpr-generator
|
- Suggested username: hpr-generator
|
||||||
- CREATE USER 'hpr-generator'@'localhost' IDENTIFIED BY '<password>';
|
- CREATE USER 'hpr-generator'@'localhost' IDENTIFIED BY '<password>';
|
||||||
* Limit the user's privileges to EXECUTE and SELECT
|
* Limit the user's privileges to EXECUTE and SELECT
|
||||||
- GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost';
|
- GRANT SELECT ON hpr_hpr.* TO 'hpr-generator'@'localhost';
|
||||||
- GRANT EXECUTE 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.)
|
Install the needed Perl modules using preferred method (distribution packages, CPAN, etc.)
|
||||||
* GetOpt
|
* GetOpt
|
||||||
* Pod::Usage
|
* Pod::Usage
|
||||||
* Config::Std
|
* Config::Std
|
||||||
* Template
|
* Template
|
||||||
* Template::Plugin::File
|
* Template::Plugin::File
|
||||||
* Template::Plugin::DBI
|
* Template::Plugin::DBI
|
||||||
* DBI
|
* DBI
|
||||||
* Tie::DBI
|
* Tie::DBI
|
||||||
* DBD::SQLite or DBD:mysql
|
* DBD::SQLite or DBD:mysql
|
||||||
* Date::Calc
|
* Date::Calc
|
||||||
|
* Text::CSV_XS
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
|
||||||
Roan Horning <roan.horning@no-spam.gmail.com>
|
Roan Horning <roan.horning@no-spam.gmail.com>
|
||||||
|
|
||||||
=head1 LICENSE
|
=head1 LICENSE
|
||||||
|
|
||||||
site-generator -- a static website generator for HPR
|
site-generator -- a static website generator for HPR
|
||||||
Copyright (C) 2022 Roan Horning
|
Copyright (C) 2022 Roan Horning
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
@ -99,249 +103,319 @@ This is a site generator for the Hacker Public Radio website based upon the Perl
|
|||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Getopt::Long qw(:config auto_help);
|
use Getopt::Long qw(:config auto_help);
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use Config::Std;
|
use Config::Std;
|
||||||
|
use Text::CSV_XS;
|
||||||
|
use HTML::Entities qw(encode_entities_numeric);
|
||||||
use Template;
|
use Template;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
||||||
|
binmode STDOUT, ":encoding(UTF-8)";
|
||||||
|
binmode STDERR, ":encoding(UTF-8)";
|
||||||
|
|
||||||
exit main();
|
exit main();
|
||||||
|
|
||||||
sub main {
|
sub main {
|
||||||
|
|
||||||
# Argument parsing
|
# Argument parsing
|
||||||
my $all;
|
my $all;
|
||||||
my $configuration_path;
|
my $configuration_path;
|
||||||
my $preview;
|
my $preview;
|
||||||
my $verbose;
|
my $verbose;
|
||||||
my $quiet;
|
my $quiet;
|
||||||
GetOptions(
|
GetOptions(
|
||||||
'all' => \$all,
|
'all' => \$all,
|
||||||
'configuration=s' => \$configuration_path,
|
'configuration=s' => \$configuration_path,
|
||||||
'list' => \&print_available_pages,
|
'list' => \&print_available_pages,
|
||||||
'preview' => \$preview,
|
'preview' => \$preview,
|
||||||
'verbose' => \$verbose,
|
'verbose' => \$verbose,
|
||||||
'quiet' => \$quiet,
|
'quiet' => \$quiet,
|
||||||
) or pod2usage(1);
|
) or pod2usage(1);
|
||||||
pod2usage(1) unless @ARGV || $all;
|
pod2usage(1) unless @ARGV || $all;
|
||||||
my (@page_args) = @ARGV;
|
my (@page_args) = @ARGV;
|
||||||
|
|
||||||
if ($quiet) {
|
if ($quiet) {
|
||||||
$verbose = 'quiet';
|
$verbose = 'quiet';
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!$configuration_path) {
|
if (!$configuration_path) {
|
||||||
$configuration_path = "site.cfg";
|
$configuration_path = "site.cfg";
|
||||||
}
|
}
|
||||||
|
|
||||||
my %config;
|
my %config;
|
||||||
if ( -f $configuration_path ) {
|
if ( -f $configuration_path ) {
|
||||||
# Load config file
|
# Load config file
|
||||||
read_config $configuration_path => %config;
|
read_config $configuration_path => %config;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print STDOUT "Could not read configuration file: $configuration_path\n";
|
print STDOUT "Could not read configuration file: $configuration_path\n";
|
||||||
exit 1;
|
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
|
# Define a TT² vmethod called 'csv_parse', it takes a scalar value and
|
||||||
if ($all) {
|
# returns an arrayref. Also define a filter called 'xml_entity' which
|
||||||
@page_args = keys %config;
|
# 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
|
# If command line option all is set, parse configuration file
|
||||||
# from the generated list of pages.
|
# for all pages
|
||||||
@page_args= grep { $_ ne 'DBI' } @page_args;
|
if ($all) {
|
||||||
@page_args= grep { $_ ne 'root_template' } @page_args;
|
@page_args = keys %config;
|
||||||
@page_args= grep { $_ ne 'app_paths' } @page_args;
|
|
||||||
|
|
||||||
};
|
# Remove non page sections of the configuration file
|
||||||
foreach my $page_arg (@page_args) {
|
# from the generated list of pages.
|
||||||
my %parsed_arg = parse_page_arg($page_arg);
|
@page_args= grep { $_ ne 'DBI' } @page_args;
|
||||||
if (exists($config{$parsed_arg{'page'}})) {
|
@page_args= grep { $_ ne 'root_template' } @page_args;
|
||||||
my $page_config = $config{$parsed_arg{'page'}};
|
@page_args= grep { $_ ne 'app_paths' } @page_args;
|
||||||
$page_config->{'page'} = $parsed_arg{'page'};
|
|
||||||
|
|
||||||
# Set page's root_template to the default root_template if the
|
};
|
||||||
# page root_template property is not set in the configuration file.
|
foreach my $page_arg (@page_args) {
|
||||||
if (exists $page_config->{'root_template'} == 0) {
|
my %parsed_arg = parse_page_arg($page_arg);
|
||||||
$page_config->{'root_template'} = $config{root_template}{content};
|
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
|
# Set page's root_template to the default root_template if the
|
||||||
# except the previously set root_template content property
|
# page root_template property is not set in the configuration file.
|
||||||
my @root_args = grep { $_ ne 'content' } keys %{$config{root_template}};
|
if (exists $page_config->{'root_template'} == 0) {
|
||||||
foreach my $root_arg (@root_args) {
|
$page_config->{'root_template'} = $config{root_template}{content};
|
||||||
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') {
|
# Set all config root_template properties as default page config properties
|
||||||
# Empty arrayref bug fixed, so count is reduced by 1
|
# except the previously set root_template content property
|
||||||
# if (scalar @{$parsed_arg{'ids'}} == 1) {
|
my @root_args = grep { $_ ne 'content' } keys %{$config{root_template}};
|
||||||
if (scalar @{$parsed_arg{'ids'}} == 0) {
|
foreach my $root_arg (@root_args) {
|
||||||
@{$parsed_arg{'ids'}} = get_ids_from_db($tt, \$page_config);
|
if (exists $page_config->{$root_arg} == 0) {
|
||||||
}
|
$page_config->{$root_arg} = $config{root_template}{$root_arg};
|
||||||
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);
|
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) {
|
||||||
else {
|
if (scalar @{$parsed_arg{'ids'}} == 0) {
|
||||||
verbose ($verbose, "Generating page: $page_config->{'page'}");
|
@{$parsed_arg{'ids'}} = get_ids_from_db($tt, \$page_config);
|
||||||
generate_page($tt, \$page_config, $preview);
|
}
|
||||||
}
|
foreach my $id (@{$parsed_arg{'ids'}}) {
|
||||||
}
|
$page_config->{'id'} = $id;
|
||||||
else {
|
verbose ($verbose, "Generating page: $page_config->{'page'} with id: $id");
|
||||||
verbose (1, "\nWarning: Page $parsed_arg{'page'} is not defined in the configuration file.");
|
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.");
|
verbose (1, "\nFinished processing the files.");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_template_html (\%@) {
|
sub get_template_html (\%@) {
|
||||||
# For an HTML based Template file, define the
|
# For an HTML based Template file, define the
|
||||||
# template start and end tags to also function as
|
# template start and end tags to also function as
|
||||||
# HTML comments to make the template file valid HTML.
|
# HTML comments to make the template file valid HTML.
|
||||||
#
|
#
|
||||||
return Template->new({
|
return Template->new(
|
||||||
INCLUDE_PATH => $_[1]{templates_path},
|
{ INCLUDE_PATH => $_[1]{templates_path},
|
||||||
OUTPUT_PATH => $_[1]{output_path},
|
OUTPUT_PATH => $_[1]{output_path},
|
||||||
EVAL_PERL => 1,
|
ENCODING => 'utf8',
|
||||||
START_TAG => '<!--%',
|
EVAL_PERL => 1,
|
||||||
END_TAG => '%-->',
|
START_TAG => '<!--%',
|
||||||
PRE_CHOMP => 1,
|
END_TAG => '%-->',
|
||||||
POST_CHOMP => 1,
|
PRE_CHOMP => 1,
|
||||||
CONSTANTS => {
|
POST_CHOMP => 1,
|
||||||
database => $_[0]{database},
|
CONSTANTS => {
|
||||||
driver => $_[0]{driver},
|
database => $_[0]{database},
|
||||||
user => $_[0]{user},
|
driver => $_[0]{driver},
|
||||||
password => $_[0]{password},
|
user => $_[0]{user},
|
||||||
}
|
password => $_[0]{password},
|
||||||
}) || die $Template::ERROR, "\n";
|
}
|
||||||
|
}
|
||||||
|
) || die $Template::ERROR, "\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub generate_page {
|
sub generate_page {
|
||||||
my ($tt, $config, $preview) = @_;
|
my ( $tt, $config, $preview ) = @_;
|
||||||
my $html;
|
my $html;
|
||||||
if (!$preview) {
|
if ( !$preview ) {
|
||||||
$html = get_filename($$config);
|
$html = get_filename($$config);
|
||||||
}
|
}
|
||||||
$tt->process($$config->{root_template}, $$config, $html)
|
$tt->process( $$config->{root_template},
|
||||||
|| die $tt->error(), "\n";
|
$$config, $html, { binmode => ':utf8' } )
|
||||||
|
|| die $tt->error(), "\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub verbose {
|
sub verbose {
|
||||||
my ($verbose, $message) = @_;
|
my ($verbose, $message) = @_;
|
||||||
if ($verbose) {
|
if ($verbose) {
|
||||||
if ($verbose ne 'quiet') {
|
if ($verbose ne 'quiet') {
|
||||||
print STDOUT "$message\n";
|
print STDOUT "$message\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
STDOUT->autoflush(1);
|
STDOUT->autoflush(1);
|
||||||
print STDOUT ".";
|
print STDOUT ".";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub parse_page_arg {
|
sub parse_page_arg {
|
||||||
my ($page_arg) = @_;
|
my ($page_arg) = @_;
|
||||||
# Split page name from page ids if available.
|
# Split page name from page ids if available.
|
||||||
my ($page, $ids) = split(/=/, $page_arg);
|
my ($page, $ids) = split(/=/, $page_arg);
|
||||||
#my @ids = [];
|
my @ids;
|
||||||
my @ids;
|
|
||||||
|
|
||||||
if(!$ids) {
|
if(!$ids) {
|
||||||
$ids = "";
|
$ids = "";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# Parse the page ids and push them onto @ids array
|
# Parse the page ids and push them onto @ids array
|
||||||
my @ids_by_comma = split(/\,/, $ids);
|
my @ids_by_comma = split(/\,/, $ids);
|
||||||
foreach my $id_by_comma (@ids_by_comma) {
|
foreach my $id_by_comma (@ids_by_comma) {
|
||||||
my @ids_for_range = split(/\.\./, $id_by_comma);
|
my @ids_for_range = split(/\.\./, $id_by_comma);
|
||||||
if ((scalar @ids_for_range) == 2) {
|
if ((scalar @ids_for_range) == 2) {
|
||||||
push @ids, $ids_for_range[0]..$ids_for_range[1];
|
push @ids, $ids_for_range[0]..$ids_for_range[1];
|
||||||
}
|
}
|
||||||
elsif ((scalar @ids_for_range) == 1) {
|
elsif ((scalar @ids_for_range) == 1) {
|
||||||
push @ids, $ids_for_range[0];
|
push @ids, $ids_for_range[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
verbose (1, "\nWarning: Page $page id range $id_by_comma could not be parsed.");
|
verbose (1, "\nWarning: Page $page id range $id_by_comma could not be parsed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ('page' => $page, 'ids' => [@ids]);
|
return ('page' => $page, 'ids' => [@ids]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_ids_from_db {
|
sub get_ids_from_db {
|
||||||
# Use a template to generate a string of page identifiers.
|
# Use a template to generate a string of page identifiers.
|
||||||
# The template should return the string in the form of
|
# The template should return the string in the form of
|
||||||
# <comma><identifier><comma><identifier>...
|
# <comma><identifier><comma><identifier>...
|
||||||
#
|
#
|
||||||
my ($tt, $config) = @_;
|
my ($tt, $config) = @_;
|
||||||
my $selected_ids = "";
|
my $selected_ids = "";
|
||||||
my $id_template = "ids-$$config->{'page'}.tpl.html";
|
my $id_template = "ids-$$config->{'page'}.tpl.html";
|
||||||
|
|
||||||
$tt->process($id_template, $$config, \$selected_ids)
|
$tt->process($id_template, $$config, \$selected_ids)
|
||||||
|| die $tt->error(), "\n";
|
|| die $tt->error(), "\n";
|
||||||
|
|
||||||
# Starts with a newline and comma
|
# Starts with a newline and comma
|
||||||
return split(/,/, substr($selected_ids, 2));
|
return split(/,/, substr($selected_ids, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_filename {
|
sub get_filename {
|
||||||
my ($config) = @_;
|
my ($config) = @_;
|
||||||
my $filename = "output.html";
|
my $filename = "output.html";
|
||||||
my $base_path = "";
|
my $base_path = "";
|
||||||
|
|
||||||
if ($$config{'filename'}) {
|
if ($$config{'filename'}) {
|
||||||
if (substr($$config{'filename'}, -1) eq '/') {
|
if (substr($$config{'filename'}, -1) eq '/') {
|
||||||
$base_path = $$config{'filename'};
|
$base_path = $$config{'filename'};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$filename = $$config{'filename'};
|
$filename = $$config{'filename'};
|
||||||
my $padded_index = "";
|
my $padded_index = "";
|
||||||
if (exists $$config{'id'} && $$config{'id'} ne "") {
|
if (exists $$config{'id'} && $$config{'id'} ne "") {
|
||||||
$padded_index = sprintf("%04d", $$config{'id'});
|
$padded_index = sprintf("%04d", $$config{'id'});
|
||||||
}
|
}
|
||||||
$filename =~ s/\[id\]/$padded_index/;
|
$filename =~ s/\[id\]/$padded_index/;
|
||||||
return $filename;
|
return $filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Default naming if full filename configuration is not supplied.
|
# Default naming if full filename configuration is not supplied.
|
||||||
if ($$config{'multipage'} && $$config{'multipage'} eq 'true') {
|
if ($$config{'multipage'} && $$config{'multipage'} eq 'true') {
|
||||||
my $padded_index = sprintf("%04d", $$config{'id'});
|
my $padded_index = sprintf("%04d", $$config{'id'});
|
||||||
$filename = "$base_path$$config{'page'}${padded_index}.html";
|
$filename = "$base_path$$config{'page'}${padded_index}.html";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$filename = "$base_path$$config{'page'}.html";
|
$filename = "$base_path$$config{'page'}.html";
|
||||||
}
|
}
|
||||||
return $filename;
|
return $filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub print_available_pages {
|
sub print_available_pages {
|
||||||
# Load config file
|
# Load config file
|
||||||
read_config "site.cfg" => my %config;
|
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
|
# Remove non page sections of the configuration file
|
||||||
# from the generated list of pages.
|
# from the generated list of pages.
|
||||||
@page_args= grep { $_ ne 'DBI' } @page_args;
|
@page_args = grep { $_ ne 'DBI' } @page_args;
|
||||||
@page_args= grep { $_ ne 'root_template' } @page_args;
|
@page_args = grep { $_ ne 'root_template' } @page_args;
|
||||||
|
|
||||||
foreach my $page_arg (@page_args) {
|
foreach my $page_arg (@page_args) {
|
||||||
print "$page_arg\n";
|
print "$page_arg\n";
|
||||||
}
|
}
|
||||||
exit;
|
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
|
||||||
|
@ -2,14 +2,14 @@
|
|||||||
eps.id,
|
eps.id,
|
||||||
eps.explicit,
|
eps.explicit,
|
||||||
eps.date, eps.license, eps.title, eps.summary,
|
eps.date, eps.license, eps.title, eps.summary,
|
||||||
eps.duration, eps.notes, eps.tags,
|
eps.duration, eps.notes, eps.tags,
|
||||||
hosts.hostid,
|
hosts.hostid,
|
||||||
hosts.host, hosts.email, hosts.local_image,
|
hosts.host, hosts.email, hosts.local_image,
|
||||||
miniseries.name AS series, miniseries.id AS seriesid
|
miniseries.name AS series, miniseries.id AS seriesid
|
||||||
FROM eps
|
FROM eps
|
||||||
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
||||||
INNER JOIN miniseries ON eps.series = miniseries.id
|
INNER JOIN miniseries ON eps.series = miniseries.id
|
||||||
WHERE eps.date <= date(\'now\')
|
WHERE eps.date <= date(\'now\')
|
||||||
ORDER BY eps.id + 0 DESC'
|
ORDER BY eps.id + 0 DESC'
|
||||||
%-->
|
%-->
|
||||||
|
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
||||||
<!--% query_hpr_feed = DBI.prepare('
|
<!--% query_hpr_feed = DBI.prepare('
|
||||||
SELECT
|
SELECT
|
||||||
eps.id,
|
eps.id,
|
||||||
eps.explicit,
|
eps.explicit,
|
||||||
DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\',
|
DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\',
|
||||||
eps.license, eps.duration,
|
eps.license, eps.duration,
|
||||||
eps.title, eps.summary, eps.tags,
|
eps.title, eps.summary, eps.tags,
|
||||||
eps.notes,
|
eps.notes,
|
||||||
hosts.local_image,
|
hosts.local_image,
|
||||||
hosts.hostid,
|
hosts.hostid,
|
||||||
hosts.host, hosts.email,
|
hosts.host, hosts.email,
|
||||||
miniseries.name AS series, miniseries.id AS seriesid
|
miniseries.name AS series, miniseries.id AS seriesid,
|
||||||
FROM eps
|
assets.size AS length
|
||||||
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
FROM eps
|
||||||
INNER JOIN miniseries ON eps.series = miniseries.id
|
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
||||||
WHERE eps.date < DATE_ADD(NOW(), INTERVAL 1 DAY)
|
INNER JOIN miniseries ON eps.series = miniseries.id
|
||||||
ORDER BY eps.date DESC
|
INNER JOIN assets ON eps.id = assets.episode_id
|
||||||
LIMIT 10
|
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) %-->
|
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
||||||
<!--% query_hpr_feed = DBI.prepare('
|
<!--% query_hpr_feed = DBI.prepare('
|
||||||
SELECT
|
SELECT
|
||||||
eps.id,
|
eps.id,
|
||||||
eps.explicit,
|
eps.explicit,
|
||||||
strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date,
|
strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date,
|
||||||
eps.license, eps.duration,
|
eps.license, eps.duration,
|
||||||
eps.title, eps.summary, eps.tags,
|
eps.title, eps.summary, eps.tags,
|
||||||
eps.notes,
|
eps.notes,
|
||||||
hosts.local_image,
|
hosts.local_image,
|
||||||
hosts.hostid,
|
hosts.hostid,
|
||||||
hosts.host, hosts.email,
|
hosts.host, hosts.email,
|
||||||
miniseries.name AS series, miniseries.id AS seriesid
|
miniseries.name AS series, miniseries.id AS seriesid,
|
||||||
FROM eps
|
assets.size AS length
|
||||||
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
FROM eps
|
||||||
INNER JOIN miniseries ON eps.series = miniseries.id
|
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
||||||
WHERE eps.date < date(\'now\', \'+1 days\')
|
INNER JOIN miniseries ON eps.series = miniseries.id
|
||||||
ORDER BY eps.date DESC
|
INNER JOIN assets ON eps.id = assets.episode_id
|
||||||
LIMIT 10
|
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) %-->
|
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
||||||
<!--% query_hpr_feed = DBI.prepare('
|
<!--% query_hpr_feed = DBI.prepare('
|
||||||
SELECT
|
SELECT
|
||||||
eps.id,
|
eps.id,
|
||||||
eps.explicit,
|
eps.explicit,
|
||||||
DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\',
|
DATE_FORMAT(eps.date, \'%H:%i:%S %d:%m:%Y\') AS \'date\',
|
||||||
eps.license, eps.duration,
|
eps.license, eps.duration,
|
||||||
eps.title, eps.summary, eps.tags,
|
eps.title, eps.summary, eps.tags,
|
||||||
eps.notes,
|
eps.notes,
|
||||||
hosts.local_image,
|
hosts.local_image,
|
||||||
hosts.hostid,
|
hosts.hostid,
|
||||||
hosts.host, hosts.email,
|
hosts.host, hosts.email,
|
||||||
miniseries.name AS series, miniseries.id AS seriesid
|
miniseries.name AS series, miniseries.id AS seriesid,
|
||||||
FROM eps
|
assets.size AS length
|
||||||
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
FROM eps
|
||||||
INNER JOIN miniseries ON eps.series = miniseries.id
|
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
||||||
WHERE eps.date < DATE_ADD(NOW(), INTERVAL 1 DAY)
|
INNER JOIN miniseries ON eps.series = miniseries.id
|
||||||
ORDER BY eps.date DESC
|
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) %-->
|
<!--% USE DBI(constants.driver, constants.user, constants.password) %-->
|
||||||
<!--% query_hpr_feed = DBI.prepare('
|
<!--% query_hpr_feed = DBI.prepare('
|
||||||
SELECT
|
SELECT
|
||||||
eps.id,
|
eps.id,
|
||||||
eps.explicit,
|
eps.explicit,
|
||||||
strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date,
|
strftime(\'%H:%M:%S %d:%m:%Y\', date(eps.date)) AS date,
|
||||||
eps.license, eps.duration,
|
eps.license, eps.duration,
|
||||||
eps.title, eps.summary, eps.tags,
|
eps.title, eps.summary, eps.tags,
|
||||||
eps.notes,
|
eps.notes,
|
||||||
hosts.local_image,
|
hosts.local_image,
|
||||||
hosts.hostid,
|
hosts.hostid,
|
||||||
hosts.host, hosts.email,
|
hosts.host, hosts.email,
|
||||||
miniseries.name AS series, miniseries.id AS seriesid
|
miniseries.name AS series, miniseries.id AS seriesid,
|
||||||
FROM eps
|
assets.size AS length
|
||||||
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
FROM eps
|
||||||
INNER JOIN miniseries ON eps.series = miniseries.id
|
INNER JOIN hosts ON eps.hostid = hosts.hostid
|
||||||
WHERE eps.date < date(\'now\', \'+1 days\')
|
INNER JOIN miniseries ON eps.series = miniseries.id
|
||||||
ORDER BY eps.date DESC
|
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) %-->
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<image>
|
<image>
|
||||||
<url>https://www.hackerpublicradio.org/images/hpr_feed_small.png</url>
|
<url>https://www.hackerpublicradio.org/images/hpr_feed_small.png</url>
|
||||||
<title>Hacker Public Radio</title>
|
<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>
|
<description>The Hacker Public Radio Old Microphone Logo</description>
|
||||||
<height>164</height>
|
<height>164</height>
|
||||||
<width>144</width>
|
<width>144</width>
|
||||||
|
@ -12,7 +12,11 @@ from the series <em><a href="<!--% baseurl %-->series/<!--% zero_pad_left(series
|
|||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO display_tags(tags) BLOCK %-->
|
<!--% 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 %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO display_listen_in(eps_id, episode_type) BLOCK %-->
|
<!--% MACRO display_listen_in(eps_id, episode_type) BLOCK %-->
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
<!--% PROCESS 'shared-utils.tpl.html' %-->
|
<!--% PROCESS 'shared-utils.tpl.html' %-->
|
||||||
<!--% MACRO display_item(episode, file_extension, audio_mime_type) BLOCK %-->
|
<!--% MACRO display_item(episode, file_extension, audio_mime_type) BLOCK %-->
|
||||||
|
<!--% USE HTML.Strip %-->
|
||||||
<!--% IF audio_mime_type == "" %-->
|
<!--% IF audio_mime_type == "" %-->
|
||||||
<!--% audio_mime_type = 'ogg' %-->
|
<!--% audio_mime_type = 'ogg' %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<item>
|
<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>
|
<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>
|
<author><!--% episode.email %--> (<!--% episode.host %-->)</author>
|
||||||
<googleplay:author><!--% episode.email %--> (<!--% episode.host %-->)</googleplay:author>
|
<googleplay:author><!--% episode.email %--> (<!--% episode.host %-->)</googleplay:author>
|
||||||
<itunes:author><!--% episode.email %--> (<!--% episode.host %-->)</itunes:author>
|
<itunes:author><!--% episode.email %--> (<!--% episode.host %-->)</itunes:author>
|
||||||
<googleplay:image href="https://www.hackerpublicradio.org/images/hpr_feed_itunes.png"/>
|
<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><![CDATA[<!--% episode.notes %-->]]>
|
||||||
</description>
|
</description>
|
||||||
<itunes:summary><![CDATA[<!--% episode.notes %-->]]>
|
<itunes:summary><![CDATA[<!--% episode.notes.substr(0, 4000) | html_strip | xml_entity %-->]]>
|
||||||
</itunes:summary>
|
</itunes:summary>
|
||||||
<pubDate><!--% format_feed_date(episode.date) %--></pubDate>
|
<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 %-->"/>
|
<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>
|
<guid>http://hackerpublicradio.org/eps/hpr<!--% zero_pad_left(episode.id) %-->.<!--% file_extension %--></guid>
|
||||||
</item>
|
</item>
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<!--% MACRO zero_pad_left(word, pad_length) BLOCK %-->
|
<!--% MACRO zero_pad_left(word, pad_length) BLOCK %-->
|
||||||
<!--% IF pad_length %-->
|
<!--% IF pad_length %-->
|
||||||
<!--% zero_pad_format = "%0${pad_length}s" %-->
|
<!--% zero_pad_format = "%0${pad_length}s" %-->
|
||||||
<!--% ELSE %-->
|
<!--% ELSE %-->
|
||||||
<!--% zero_pad_format = "%04s" %-->
|
<!--% zero_pad_format = "%04s" %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<!--% USE String(word) %-->
|
<!--% USE String(word) %-->
|
||||||
<!--% String.format(zero_pad_format) %-->
|
<!--% String.format(zero_pad_format) %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO display_choice(choice, display_when_true, display_when_false) BLOCK %-->
|
<!--% MACRO display_choice(choice, display_when_true, display_when_false) BLOCK %-->
|
||||||
@ -17,7 +17,7 @@
|
|||||||
<!--% seconds = duration_sec % 60 %-->
|
<!--% seconds = duration_sec % 60 %-->
|
||||||
<!--% USE format %-->
|
<!--% USE format %-->
|
||||||
<!--% minutes_only = format("%d") %-->
|
<!--% minutes_only = format("%d") %-->
|
||||||
<!--% minutes = minutes_only(duration_sec / 60) %-->
|
<!--% minutes = minutes_only(duration_sec / 60) %-->
|
||||||
<!--% hours_only = format("%d") %-->
|
<!--% hours_only = format("%d") %-->
|
||||||
<!--% hours = hours_only(minutes / 60) %-->
|
<!--% hours = hours_only(minutes / 60) %-->
|
||||||
<!--% IF hours >= 1 %-->
|
<!--% IF hours >= 1 %-->
|
||||||
@ -57,23 +57,23 @@
|
|||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO media_path(episode_id, episode_type, media_type, baseurl, media_baseurl) BLOCK %-->
|
<!--% MACRO media_path(episode_id, episode_type, media_type, baseurl, media_baseurl) BLOCK %-->
|
||||||
<!--% IF episode_type == "twat" %-->
|
<!--% IF episode_type == "twat" %-->
|
||||||
<!--% padding = 3 %-->
|
<!--% padding = 3 %-->
|
||||||
<!--% media_folder = "eps/"; padding = 3 %-->
|
<!--% media_folder = "eps/"; padding = 3 %-->
|
||||||
<!--% ELSE %-->
|
<!--% ELSE %-->
|
||||||
<!--% media_folder = "local/" %-->
|
<!--% media_folder = "local/" %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<!--% IF media_baseurl %-->
|
<!--% IF media_baseurl %-->
|
||||||
<!--% transcription_types = "txt srt vtt" %-->
|
<!--% transcription_types = "txt srt vtt" %-->
|
||||||
<!--% USE String(transcription_types) %-->
|
<!--% USE String(transcription_types) %-->
|
||||||
<!--% USE String(media_baseurl) %-->
|
<!--% USE String(media_baseurl) %-->
|
||||||
<!--% IF transcription_types.search(media_type) && media_baseurl.search('archive.org') %-->
|
<!--% IF transcription_types.search(media_type) && media_baseurl.search('archive.org') %-->
|
||||||
<!--% media_baseurl = "${media_baseurl}hpr\$eps_id/" %-->
|
<!--% media_baseurl = "${media_baseurl}hpr\$eps_id/" %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<!--% media_folder = "" %-->
|
<!--% media_folder = "" %-->
|
||||||
<!--% media_baseurl = media_baseurl.replace('\$eps_id', zero_pad_left(episode_id)) %-->
|
<!--% media_baseurl = media_baseurl.replace('\$eps_id', zero_pad_left(episode_id)) %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<!--% media_basepath(baseurl, media_baseurl) %--><!--% media_folder %--><!--% episode_type %--><!--% zero_pad_left(episode_id, padding) %-->.<!--% media_type %-->
|
<!--% media_basepath(baseurl, media_baseurl) %--><!--% media_folder %--><!--% episode_type %--><!--% zero_pad_left(episode_id, padding) %-->.<!--% media_type %-->
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--% MACRO step_navigation(baseurl, links, folder) BLOCK %-->
|
<!--% MACRO step_navigation(baseurl, links, folder) BLOCK %-->
|
||||||
@ -93,7 +93,3 @@
|
|||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
<a href="<!--% absolute_path(baseurl) %-->eps/<!--% folder %--><!--% zero_pad_left(links.latest) %-->/index.html" rel="last">Latest >></a></small>
|
<a href="<!--% absolute_path(baseurl) %-->eps/<!--% folder %--><!--% zero_pad_left(links.latest) %-->/index.html" rel="last">Latest >></a></small>
|
||||||
<!--% END %-->
|
<!--% END %-->
|
||||||
|
|
||||||
<!--
|
|
||||||
vim: syntax=html:ts=8:sw=4:tw=78:et:ai:
|
|
||||||
-->
|
|
||||||
|
Reference in New Issue
Block a user