Browse Source

add JSON Feed support; make Atom feed use caches; decode utf-8 output

Uses JSON::Feed, for the moment, although it might be worth just rolling
my own to avoid the dependency.

Adds:

  - feed_print_json_recent()
  - feed_print_json()

Also puts a decode() call around feed_print() output and adds open()
pragmas to a couple of utilities.
master
Brennen Bearnes 1 year ago
parent
commit
7d9ff8fcba
6 changed files with 117 additions and 9 deletions
  1. +1
    -0
      Build.PL
  2. +2
    -0
      bin/wrt-feed
  3. +2
    -0
      bin/wrt-repl
  4. +80
    -4
      lib/App/WRT.pm
  5. +6
    -3
      lib/App/WRT/Renderer.pm
  6. +26
    -2
      t/wrt.t

+ 1
- 0
Build.PL View File

@ -16,6 +16,7 @@ my $build = Module::Build->new(
'HTML::Entities' => '3.69',
'Image::Size' => '3.300',
'JSON' => '4.02',
'JSON::Feed' => '0.001',
'Mojo::DOM' => '0',
'POSIX' => '1.84',
'Text::Markdown::Discount' => '0.11',


+ 2
- 0
bin/wrt-feed View File

@ -37,6 +37,8 @@ use 5.14.0;
use strict;
use warnings;
no warnings 'uninitialized';
use utf8;
use open qw(:std :utf8);
# use Data::Dumper;
use App::WRT;


+ 2
- 0
bin/wrt-repl View File

@ -37,6 +37,8 @@ use 5.10.0;
use strict;
use warnings;
use utf8;
use open qw(:std :utf8);
use Getopt::Long qw(GetOptionsFromArray);
use Pod::Usage;


+ 80
- 4
lib/App/WRT.pm View File

@ -32,6 +32,7 @@ use Encode qw(decode encode);
use File::Spec;
use HTML::Entities;
use JSON;
use JSON::Feed;
use Mojo::DOM;
use XML::Atom::SimpleFeed;
@ -1109,6 +1110,23 @@ sub feed_print_recent {
);
}
=item feed_print_json_recent($count)
Print $count recent entries in JSON, falling back to the configured
$feed_length.
=cut
sub feed_print_json_recent {
my ($self, $count) = @_;
$count //= $self->{feed_length};
return $self->feed_print_json(
$self->{entries}->recent_days($count)
);
}
=item feed_print(@entries)
Return an Atom feed for the given list of entries.
@ -1149,7 +1167,7 @@ sub feed_print {
my $feed = XML::Atom::SimpleFeed->new(
-encoding => 'UTF-8',
title => $self->{title_prefix} . '::' . $self->{title},
title => $self->{title_prefix} . "::" . $self->{feed_alias},
subtitle => $self->{description},
link => $self->{url_root},
link => { rel => 'self', href => $feed_url, },
@ -1161,7 +1179,12 @@ sub feed_print {
);
foreach my $entry (@entries) {
my $content = $self->entry($entry) . "\n" . $self->datestamp($entry);
my $content = $self->{html_cache}{$entry};
if ( $self->{metadata_html_cache}{$entry} ) {
$content .= '<div class=entry-metadata>'
. $self->{metadata_html_cache}{$entry}
. '</div>';
}
my ($entry_file, $entry_url) = $self->root_locations($entry);
@ -1174,8 +1197,61 @@ sub feed_print {
);
}
# return "Content-type: application/atom+xml\n\n" . $feed->as_string;
return $feed->as_string;
# Note: This output should be served with
# Content-type: application/atom+xml
#
# I'm not, to be frank, entirely clear on why the decode() call here is
# necessary:
return decode('UTF-8', $feed->as_string);
}
=item feed_print_json
Like feed_print(), but for JSON Feed.
L<https://jsonfeed.org/>
=cut
sub feed_print_json {
my ($self, @entries) = @_;
my ($first_entry_file, $first_entry_url) = $self->root_locations($entries[0]);
my $json_feed_url = $self->{url_root} . $self->{feed_alias} . '.json';
my $user_comment = "This feed allows you to read the posts from this site in"
. " any feed reader that supports the JSON Feed format. To "
. "add this feed to your reader, copy the following URL — "
. "$json_feed_url — and add it your reader.";
my $feed = JSON::Feed->new(
user_comment => $user_comment,
title => $self->{title_prefix} . "::" . $self->{feed_alias},
feed_url => $json_feed_url,
description => $self->{description},
author => +{ name => $self->{author}, },
);
foreach my $entry (@entries) {
my $content = $self->{html_cache}{$entry};
if ($self->{metadata_html_cache}{$entry}) {
$content .= '<div class=entry-metadata>'
. $self->{metadata_html_cache}{$entry}
. '</div>';
}
my ($entry_file, $entry_url) = $self->root_locations($entry);
$feed->add_item(
id => $entry_url,
title => $self->get_title($entry),
content_html => $content,
date_modified => iso_date(get_mtime($entry_file)),
);
}
# Output
return $feed->to_string;
}
=back


+ 6
- 3
lib/App/WRT/Renderer.pm View File

@ -96,10 +96,13 @@ sub render {
# Handle the front page and Atom feed:
$self->write("${publish_dir}/index.html", $self->{wrt}->display('new'));
# Handle feed formats:
my $feed_alias = $self->{wrt}->{feed_alias};
my $feed_content = $self->{wrt}->feed_print_recent();
$self->write("${publish_dir}/${feed_alias}", $feed_content);
$self->write("${publish_dir}/${feed_alias}.xml", $feed_content);
my $xml_feed_content = $self->{wrt}->feed_print_recent();
my $json_feed_content = $self->{wrt}->feed_print_json_recent();
$self->write("${publish_dir}/${feed_alias}", $xml_feed_content);
$self->write("${publish_dir}/${feed_alias}.xml", $xml_feed_content);
$self->write("${publish_dir}/${feed_alias}.json", $json_feed_content);
# Handle any other paths that aren't derived directly from files:
my @meta_paths = qw(all);


+ 26
- 2
t/wrt.t View File

@ -3,11 +3,13 @@
use strict;
use warnings;
use utf8;
use open qw(:std :utf8);
use lib 'lib';
use Encode;
use Test::More tests => 16;
use JSON;
use Test::More tests => 19;
# Does the module load?
@ -70,7 +72,15 @@ chdir 'example';
# feed rendering
my $feed = decode('UTF-8', $w->feed_print_recent());
my $with_stars = $w->display('2014/1/2');
like(
$with_stars,
qr/✨/s,
'2014/1/2 contains some stars which we also expect to show up in the feed'
);
my $feed = $w->feed_print_recent();
like(
$feed,
@ -78,6 +88,20 @@ chdir 'example';
'feed contains some stars'
) or diag($feed);
my $json_feed = $w->feed_print_json();
my $JSON = JSON->new->utf8->pretty;
my $feed_hashref = $JSON->decode(encode('UTF-8', $json_feed));
ok(
length $json_feed,
'got some sort of a JSON Feed'
) or diag($json_feed);
ok(
defined $feed_hashref->{title},
'got a JSON Feed with a title'
) or diag($feed_hashref);
# not expanding entries with wrt-noexpand
my $with_noexpand = $w->display('noexpand_test');


Loading…
Cancel
Save