root/trunk/plagger/lib/Plagger/Plugin/Subscription/OPML.pm

Revision 238 (checked in by miyagawa, 14 years ago)
  • use URI::Fetch for smart caching in OPML and Simple. Fixes #3
  • Switch to Cache::Cache based as a default Cache. Fixes #86
  • Property svn:keywords set to Id Revision
Line 
1 package Plagger::Plugin::Subscription::OPML;
2 use strict;
3 use base qw( Plagger::Plugin );
4
5 use Plagger::UserAgent;
6 use URI;
7 use XML::OPML;
8
9 sub register {
10     my($self, $context) = @_;
11
12     $context->register_hook(
13         $self,
14         'subscription.load' => \&load,
15     );
16 }
17
18 sub load {
19     my($self, $context) = @_;
20     my $uri = URI->new($self->conf->{url})
21         or $context->error("config 'url' is missing");
22
23     $self->load_opml($context, $uri);
24 }
25
26 sub load_opml {
27     my($self, $context, $uri) = @_;
28
29     my $xml;
30     if (ref($uri) eq 'SCALAR') {
31         $xml = $$uri;
32     }
33     elsif ($uri->scheme =~ /^https?$/) {
34         $context->log(debug => "Fetch remote OPML from $uri");
35
36         my $response = Plagger::UserAgent->new->fetch($uri, $self);
37         unless ($response) {
38             $context->error("Fetch $uri failed: ". $response->status);
39         }
40         $xml = $response->content;
41     }
42     elsif ($uri->scheme eq 'file') {
43         $context->log(debug => "Open local OPML file " . $uri->path);
44         open my $fh, '<', $uri->path
45             or $context->error( $uri->path . ": $!" );
46         $xml = join '', <$fh>;
47     }
48     else {
49         $context->error("Unsupported URI scheme: " . $uri->scheme);
50     }
51
52     my $opml = XML::OPML->new;
53     $opml->parse($xml);
54     for my $outline (@{ $opml->outline }) {
55         $self->walk_down($outline, $context, 0, []);
56     }
57 }
58
59 sub walk_down {
60     my($self, $outline, $context, $depth, $containers) = @_;
61
62     if (delete $outline->{opmlvalue}) {
63         my $title = delete $outline->{title};
64         push @$containers, $title if $title ne 'Subscriptions';
65         for my $channel (values %$outline) {
66             $self->walk_down($channel, $context, $depth + 1, $containers);
67         }
68         pop @$containers if $title ne 'Subscriptions';
69     } else {
70         my $feed = Plagger::Feed->new;
71         $feed->url($outline->{xmlUrl});
72         $feed->link($outline->{htmlUrl});
73         $feed->title($outline->{title});
74         $feed->tags($containers);
75         $context->subscription->add($feed);
76     }
77 }
78
79 1;
80
81 __END__
82
83 =head1 NAME
84
85 Plagger::Plugin::Subscription::OPML - OPML subscription
86
87 =head1 SYNOPSIS
88
89   - module: Subscription::OPML
90     config:
91       url: http://example.com/mySubscriptions.opml
92
93 =head1 DESCRIPTION
94
95 This plugin creates Subscription by fetching remote OPML file by HTTP
96 or locally (with C<file://> URI). It supports nested folder structure
97 of OPML subscription.
98
99 =head1 AUTHOR
100
101 Tatsuhiko Miyagawa
102
103 =head1 SEE ALSO
104
105 L<Plagger>, L<XML::OPML>
106
107 =cut
Note: See TracBrowser for help on using the browser.