# Blosxom Plugin: rss20 # Author(s): Gavin Carr # Version: 0.003000 # Requires: storydate # Suggests: absolute, storytags, geo # Follows: storydate package rss20; use strict; use vars qw( $flavour $author_email $author_name $webmaster_email $permalink $trackback_link $copyright $generator $category_list $georss ); # --- Configuration variables ----- # What flavour string to you want to use for your feed? $flavour = 'rss'; #$flavour = 'rss20'; # What email address should be used as the default author email? # Recommended format is 'email (name)', but bare emails or mailto emails are ok too $author_email = 'author@example.com (A. U. Thor)'; # What name should be used as the default author name? # Define this only if you don't want to disclose an email address in $author_email. # It will be ignored if $author_email is set. $author_name = ''; # What email address should feed errors be reported to? # Recommended format is 'email (name)', but bare emails or mailto emails are ok too $webmaster_email = ''; #$webmaster_email = 'webmaster@example.com (Web Master)'; # What do your story permalinks look like? # This must be single-quoted, to defer evaluation; blosxom namespace applies $permalink = '$url$path/$fn.$default_flavour'; # What link should be used for trackbacks on a story? # This must be single-quoted, to defer evaluation; blosxom namespace applies $trackback_link = ''; # $trackback_link = '$url$path/$fn.writeback'; # $trackback_link = '$url$path/$fn.$feedback::trackback_flavour'; # Copyright statement; leave blank to omit. $copyright = ''; # Generator that produced this feed $generator = "blosxom $blosxom::version"; # -------------------------------- # __END_CONFIG__ $webmaster_email ||= $author_email; my $channel_indent = 8; my $item_indent = 12; # Escape <, >, and & to hex-encoded entities for max compatibility in text elements # See http://www.rssboard.org/rss-profile#data-types-characterdata my %escape_text = ( '<' => '<', '>' => '>', '&' => '&', ); my $escape_text_re = join '|' => keys %escape_text; # Escape <, >, and & to standard html-encoded entities for in html elements my %escape_html = ( '<' => '<', '>' => '>', '&' => '&', ); my $escape_html_re = join '|' => keys %escape_html; sub start { _load_templates(); } my $do_encode = 0; sub story { my ($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_; # Ignore flavours other than ours return unless $blosxom::flavour eq $flavour; # Don't double-encode if someone else has already done it return unless $do_encode || $blosxom::encode_xml_entities; # Because we're inside a loop, we set $do_encode for runs after the first unless ($do_encode) { $do_encode = 1; $blosxom::encode_xml_entities = 0; } # Encode and reset encode_xml_entities flag $$title_ref = _escape_text( $$title_ref ); $$body_ref = _escape_html( $$body_ref ); $category_list = ''; if ($blosxom::plugins{storytags}) { for (@storytags::taglist) { $category_list .= qq($_\n) . ' ' x $item_indent; } } $georss = ''; if ($blosxom::plugins{geo} && $geo::latitude && $geo::longitude) { $georss = qq($geo::latitude $geo::longitude\n) . ' ' x $item_indent; } return 1; } # --- Private subroutines sub _escape_text { my ($text) = @_; $text =~ s/($escape_text_re)/$escape_text{$1}/g; return $text; } sub _escape_html { my ($html) = @_; $html =~ s/($escape_html_re)/$escape_html{$1}/g; return $html; } sub _load_templates { $blosxom::template{$flavour}{'content_type'} = 'text/xml; charset=$blog_encoding'; $blosxom::template{$flavour}{'date'} = "\n"; $blosxom::template{$flavour}{'head'} = < $blosxom::blog_title $blosxom::url/ HEAD if ($blosxom::path_info) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($blosxom::path_info\n); } if ($blosxom::blog_description) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($blosxom::blog_description\n); } if ($rss20::author_email) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($rss20::author_email\n); } elsif ($rss20::author_name) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($rss20::author_name\n); } if ($rss20::webmaster_email) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($rss20::webmaster_email\n); } if ($rss20::copyright) { $blosxom::template{$flavour}{'head'} .= ' ' x $channel_indent . qq($rss20::copyright\n); } my $path_info_full = $blosxom::path_info_full || "$blosxom::path_info/index.rss"; $blosxom::template{$flavour}{'head'} .= <\$storydate::latest_rfc822 $blosxom::blog_language $rss20::generator hourly 1 2000-01-01T12:00+00:00 HEAD $blosxom::template{$flavour}{'story'} = < \$title $rss20::permalink $rss20::permalink \$storydate::story_rfc822 STORY if ($rss20::trackback_link) { $blosxom::template{$flavour}{'story'} .= ' ' x $item_indent . qq($rss20::trackback_link\n); } $blosxom::template{$flavour}{'story'} .= ' ' x $item_indent . '$rss20::category_list'; # GeoRSS support if ($blosxom::plugins{geo}) { $blosxom::template{$flavour}{'story'} .= '$rss20::georss'; } $blosxom::template{$flavour}{'story'} .= <<'STORY'; $body STORY $blosxom::template{$flavour}{'foot'} = <<'FOOT'; FOOT 1; } 1; __END__ =head1 NAME rss20 - blosxom plugin to generate an RSS 2.0 feed of your blog =head1 DESCRIPTION rss20 is a blosxom plugin to generate an RSS 2.0 feed of your blog. It is self-contained, including the required flavours, and has a bunch of configuration variables to allow for configuration. If you're using the L plugin, rss20 will also add georss:point entries for any items with latitude and longitude metadata set (see L). =head2 CONFIGURATION The following package variables can be configured: =over 4 =item $flavour Flavour string to use for your feed (typically 'rss' or 'rss20'). =item $author_email Default author email address for posts. =item $webmaster_email Email address to use for webmaster responsible for the feed (defaults to $author_email). =item $permalink Story permalink. Default is '$url$path/$fn.$default_flavour'. Note that this value should probably be single quoted to defer variable evaluation until rendering time. =item $trackback_link Story trackback or comment link. Default is ''. Useful if you are using a comments plugin like C or C, and the format you want will be plugin-dependant. Like $permalink, this value should be single quoted to defer variable evaluation till rendering time. =item $copyright Default copyright clause for posts, if any. =back =head1 USAGE rss20 should be loaded relatively late, since you'll typically want plugins that manipulate your story content to have run already. It also should be run after the 'story' or 'prefs' plugins if you want to use those to customise your configuration variables. Requires the L plugin for setting up story dates in the right formats, and recommends the L plugin for absolutising URLs. =head1 SEE ALSO L, L, L Blosxom: http://blosxom.sourceforge.net/ rss20 is based on the 'atomfeed' and 'rss10' plugins, by Rael Dornfest and contributors. =head1 BUGS Please report bugs either directly to the author or to the blosxom development mailing list: . =head1 AUTHOR Gavin Carr , http://www.openfusion.net/ =head1 LICENSE Copyright 2007 Gavin Carr. This plugin is licensed under the same terms as blosxom itself i.e. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =cut # vim:ft=perl