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

Revision 584 (checked in by miyagawa, 14 years ago)

Fix Bloglines atom:id bug when permaLink = false.

  • Property svn:keywords set to Id Revision
Line 
1 package Plagger::Plugin::Subscription::Bloglines;
2 use strict;
3 use base qw( Plagger::Plugin );
4
5 our $VERSION = '0.10';
6 use WebService::Bloglines;
7
8 sub plugin_id {
9     my $self = shift;
10     $self->class_id . '-' . $self->conf->{username};
11 }
12
13 sub register {
14     my($self, $context) = @_;
15
16     $self->init_bloglines();
17
18     if ($self->conf->{no_sync_api}) {
19         $context->register_hook(
20             $self,
21             'subscription.load' => \&getsubs,
22         );
23     } else {
24         $context->register_hook(
25             $self,
26             'subscription.load' => \&notifier,
27         );
28     }
29 }
30
31 sub getsubs {
32     my($self, $context) = @_;
33     my $subscription = $self->{bloglines}->listsubs();
34
35     for my $folder ($subscription->folders, 0) {
36         my $subid = $folder ? $folder->{BloglinesSubId} : 0;
37         my $title = $folder ? $folder->{title} : undef;
38         $self->add_subscription($subscription, $subid, $title);
39     }
40 }
41
42 sub add_subscription {
43     my($self, $subscription, $subid, $title) = @_;
44
45     my @feeds = $subscription->feeds_in_folder($subid);
46     for my $source (@feeds) {
47         my $feed = Plagger::Feed->new;
48         $feed->title($source->{title});
49         $feed->link($source->{htmlUrl});
50         $feed->url($source->{xmlUrl} );
51         $feed->tags([ $title ]) if $title;
52         Plagger->context->subscription->add($feed);
53     }
54 }
55
56 sub init_bloglines {
57     my $self = shift;
58     $self->{bloglines} = WebService::Bloglines->new(
59         username => $self->conf->{username},
60         password => $self->conf->{password},
61         use_liberal => 1,
62     );
63 }
64
65 sub notifier {
66     my($self, $context) = @_;
67
68     my $count = $self->{bloglines}->notify();
69     $context->log(info => "You have $count unread item(s) on Bloglines.");
70     if ($count) {
71         my $feed = Plagger::Feed->new;
72         $feed->aggregator(sub { $self->sync(@_) });
73         $context->subscription->add($feed);
74
75         if ($self->conf->{fetch_meta}) {
76             $self->{bloglines_meta} = $self->cache->get_callback(
77                 'listsubs_meta',
78                 sub { $self->fetch_meta($context) },
79                 '1 day',
80             );
81         }
82     }
83 }
84
85 sub fetch_meta {
86     my($self, $context) = @_;
87
88     $self->{folders} = {};
89     $context->log(info => "call Bloglines listsubs API to get folder structure");
90
91     my $subscription = $self->{bloglines}->listsubs();
92
93     my $meta;
94     for my $folder ($subscription->folders, 0) {
95         my $subid = ref $folder ? $folder->{BloglinesSubId} : 0;
96         my @feeds = $subscription->feeds_in_folder($subid);
97         for my $feed (@feeds) {
98             $meta->{$feed->{htmlUrl}} = {
99                 folder => $folder ? $folder->{title} : undef,
100                 xmlUrl => $feed->{xmlUrl},
101                 subid  => $feed->{BloglinesSubId},
102             };
103         }
104     }
105
106     $meta;
107 }
108
109 sub sync {
110     my($self, $context, $args) = @_;
111
112     my $mark_read = $self->conf->{mark_read};
113        $mark_read = 1 unless defined $mark_read;
114
115     my @updates;
116
117     # catch bad XML feed by Bloglines
118     eval {
119         @updates = $self->{bloglines}->getitems(0, $mark_read);
120     };
121
122     if ($@) {
123         $context->log(warn => "Bloglines Sync API returned bad XML. fallbacks to loop mode");
124         my @feeds = $self->{bloglines}->listsubs()->feeds;
125         for my $feed (@feeds) {
126             if ($feed->{BloglinesUnread}) {
127                 $context->log(debug => "Fetch $feed->{BloglinesSubId}");
128                 push @updates, eval { $self->{bloglines}->getitems($feed->{BloglinesSubId}, $mark_read) };
129             }
130         }
131     }
132
133     $context->log(info => scalar(@updates) . " feed(s) updated.");
134
135     for my $update (@updates) {
136         my $source = $update->feed;
137
138         my $feed = Plagger::Feed->new;
139         $feed->type('bloglines');
140         $feed->title($source->{title});
141         $feed->link($source->{link});
142         $feed->image($source->{image});
143         $feed->description($source->{description});
144         $feed->language($source->{language});
145         $feed->author($source->{webmaster});
146         $feed->meta->{bloglines_id} = $source->{bloglines}->{siteid};
147
148         # under fetch_pfolders option, set folder as tags to feeds
149         if (my $meta = $self->{bloglines_meta}->{$feed->link}) {
150             $feed->tags([ $meta->{folder} ]) if $meta->{folder};
151             $feed->url($meta->{xmlUrl});
152             $feed->meta->{bloglines_subid} = $meta->{subid};
153         }
154
155         $feed->source_xml($update->{_xml});
156
157         for my $item ( $update->items ) {
158             my $entry = Plagger::Entry->new;
159
160             $entry->title($item->{title});
161             $entry->author($item->{dc}->{creator});
162             $entry->tags([ $item->{dc}->{subject} ])
163                 if $item->{dc}->{subject};
164             $entry->date( Plagger::Date->parse('Mail', $item->{pubDate}) );
165             $entry->link($item->{link});
166             $entry->permalink("$item->{guid}") # stringify MagicElement
167                 if $item->{guid} && $item->{guid} =~ m!^https?://! && $item->{isPermaLink} eq 'true';
168             $entry->feed_link($feed->link);
169             $entry->id($item->{guid});
170
171             $entry->body($item->{description});
172
173             $feed->add_entry($entry);
174         }
175
176         $context->update->add($feed);
177     }
178 }
179
180 1;
181
182 __END__
183
184 =head1 NAME
185
186 Plagger::Plugin::Subscription::Bloglines - Bloglines Subscription
187
188 =head1 SYNOPSIS
189
190   - module: Subscription::Bloglines
191     config:
192       username: your-email@account
193       password: your-password
194       mark_read: 1
195
196 =head1 DESCRIPTION
197
198 This plugin allows you to synchronize your subscription using
199 Bloglines Web Services sync API.
200
201 =head1 CONFIGURATION
202
203 =over 4
204
205 =item username, password
206
207 Your username & password to use with Bloglines API.
208
209 =item mark_read
210
211 C<mark_read> specifies whether this plugin I<marks as read> the items
212 you synchronize. With this option set to 0, you will get the
213 duplicated updates everytime you run Plagger, until you mark them
214 unread using Bloglines browser interface. Defaults to 1.
215
216 For people who uses Bloglines browser interface regularly, and use
217 Plagger as a tool to synchronize feed updates to mobile devices (like
218 PSP or iPod), I'd recommend set this option to 0.
219
220 Otherwise, especially for Publish::Gmail plugin users, I recommend set
221 to 1, the default.
222
223 =item fetch_meta
224
225 C<fetch_meta> specifies whether this plugin fetches I<folder>
226 strucuture using listsubs API. With this option on, all feeds under
227 I<Plagger> folder will have I<Plagger> as its tag.
228
229 You can use this tags information using Rules in later phase.
230
231 =back
232
233 =head1 AUTHOR
234
235 Tatsuhiko Miyagawa
236
237 =head1 SEE ALSO
238
239 L<Plagger>, L<WebService::Bloglines>, L<http://www.bloglines.com/>
240
241 =cut
242
Note: See TracBrowser for help on using the browser.