App-news
view release on metacpan or search on metacpan
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"DateTime::Format::Mail" : "0",
"Modern::Perl" : "1.20180701",
"Mojolicious" : "9",
"perl" : "5.026000"
}
}
},
"release_status" : "stable",
"resources" : {
"repository" : {
"type" : "git",
license: open_source
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: App-news
no_index:
directory:
- t
- inc
requires:
DateTime::Format::Mail: '0'
Modern::Perl: '1.20180701'
Mojolicious: '9'
perl: '5.026000'
resources:
repository: https://alexschroeder.ch/cgit/news
version: 1.09
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
Makefile.PL view on Meta::CPAN
ABSTRACT => 'a web front-end for a news server',
AUTHOR => 'Alex Schroeder',
LICENSE => 'agpl_3',
MIN_PERL_VERSION => '5.26.0', # Modern::Perl '2018'
EXE_FILES => [
'script/news',
],
PREREQ_PM => {
'Mojolicious' => 9.00,
'Modern::Perl' => 1.20180701, # for '2018'
'DateTime::Format::Mail' => 0,
},
META_MERGE => {
'meta-spec' => { version => 2 },
resources => {
repository => {
type => 'git',
url => 'https://alexschroeder.ch/cgit/news',
web => 'https://alexschroeder.ch/cgit/news/about/',
},
},
script/news view on Meta::CPAN
GNU Affero General Public License
=cut
# corelist
use Net::NNTP;
use Encode qw(encode decode);
# not core
use Mojolicious::Lite; # Mojolicious
use Mojo::Cache;
use DateTime::Format::Mail;
use List::Util qw(first);
use utf8;
# our own
use App::news qw(wrap html_unwrap ranges);
my $cache = Mojo::Cache->new;
get '/' => sub {
shift->redirect_to('index');
};
script/news view on Meta::CPAN
my $last_page = int($last / $per_page) + 1;
$page ||= $last_page;
my $to = $page * $per_page;
$to = $last if $to > $last;
my $from = ($page - 1) * $per_page;
$from = $first if $from < $first;
my $fmt = $nntp->overview_fmt;
app->log->debug("Getting $group $from-$to");
my $messages = $nntp->xover("$from-$to");
my $articles = [];
my $parser = DateTime::Format::Mail->new->loose;
for my $num (sort { $b <=> $a } keys %$messages) {
my ($subject, $from, $date, $id, $references) = @{$messages->{$num}};
$subject = decode("MIME-Header", $subject) || "?";
my ($tag) = $subject =~ /\[(.*?)\]/;
$from = no_email(decode("MIME-Header", $from));
my $dt = $parser->parse_datetime($date);
my $url = $c->url_for('article', group => $group, id => $num);
$url = $url->query(edit => $edit) if $edit;
push(@$articles, {
id => $id,
script/news view on Meta::CPAN
while (@nums > $per_page and not grep { $_ == $include } @page) {
@page = splice(@nums, -$per_page);
$page++;
}
@nums = @page if @page;
}
my $ranges = ranges(@nums);
my $fmt = $nntp->overview_fmt;
my $re = quotemeta($tag);
my $articles = [];
my $parser = DateTime::Format::Mail->new->loose;
for my $range (@$ranges) {
app->log->debug("Getting $group " . (ref $range ? join("-", @$range) : $range));
my $messages = $nntp->xover($range);
app->log->debug("Received " . scalar(keys %$messages) . " messages");
for my $num (sort keys %$messages) {
my ($subject, $from, $date, $id, $references) = @{$messages->{$num}};
$subject = decode("MIME-Header", $subject) || "?";
$subject =~ s/\[$re\]\s*//;
$from = no_email(decode("MIME-Header", $from));
my $dt = $parser->parse_datetime($date);
script/news view on Meta::CPAN
# $article is header lines, an empty line, and body lines
my $headers = Mojo::Headers->new;
while ($_ = shift(@$article)) {
$headers->parse("$_\r\n");
last unless /\S/;
}
my $id = $headers->header("message-id");
my $subject = decode("MIME-Header", $headers->header("subject")) || "?";
my $from = no_email(decode("MIME-Header", $headers->header("from")));
my $date = $headers->header("date");
my $dt = DateTime::Format::Mail->new->loose->parse_datetime($date);
$date = [$dt->ymd, sprintf("%02d:%02d", $dt->hour, $dt->minute)];
my $newsgroups = [split(/\s*,\s*/, decode("MIME-Header", $headers->header("newsgroups")) || "")];
$group ||= "@$newsgroups";
my $references = [split(/\s+/, decode("MIME-Header", $headers->header("references")) || "")];
my $body = join("", @$article);
$body =~ s/\s*<\S*?@\S*?>//g; # remove email addresses
$body =~ s/\s*"\S*?@\S*?"//g; # remove email addresses
if ($headers->header('content-type')) {
my ($charset) = $headers->header('content-type') =~ /charset=['"]?([^;'"]*)/;
$body = decode($charset, $body) if $charset;
script/news view on Meta::CPAN
} => 'post';
get '/latest' => sub {
my $c = shift;
my $list = cached("news " . ($ENV{NEWS_GROUPS} || "*"), sub {
my $nntp = Net::NNTP->new() or return 'error';
my $since = time() - 7 * 24 * 60 * 60; # one week
my $ids = $nntp->newnews($since, $ENV{NEWS_GROUPS} || "*");
$ids = [@$ids[$#$ids - $per_page .. $#$ids]] if @$ids > $per_page;
my $articles = [];
my $parser = DateTime::Format::Mail->new->loose;
for my $id (@$ids) {
my $head = $nntp->head($id);
next unless $head;
my $headers = Mojo::Headers->new;
for my $line (@$head) {
$headers->parse("$line\r\n");
}
$headers->parse("\r\n"); # make sure it finishes correctly
my $subject = decode("MIME-Header", $headers->header("subject")) || "?";
my ($tag) = $subject =~ /\[(.*?)\]/;
( run in 0.263 second using v1.01-cache-2.11-cpan-05444aca049 )