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

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

Added plugin_id method to mean object ID, not class ID. Fixes #95

  • 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->feed_link($feed->link);
167             $entry->id($item->{guid});
168
169             $entry->body($item->{description});
170
171             $feed->add_entry($entry);
172         }
173
174         $context->update->add($feed);
175     }
176 }
177
178 1;
179
180 __END__
181
182 =head1 NAME
183
184 Plagger::Plugin::Subscription::Bloglines - Bloglines Subscription
185
186 =head1 SYNOPSIS
187
188   - module: Subscription::Bloglines
189     config:
190       username: your-email@account
191       password: your-password
192       mark_read: 1
193
194 =head1 DESCRIPTION
195
196 This plugin allows you to synchronize your subscription using
197 Bloglines Web Services sync API.
198
199 =head1 CONFIGURATION
200
201 =over 4
202
203 =item username, password
204
205 Your username & password to use with Bloglines API.
206
207 =item mark_read
208
209 C<mark_read> specifies whether this plugin I<marks as read> the items
210 you synchronize. With this option set to 0, you will get the
211 duplicated updates everytime you run Plagger, until you mark them
212 unread using Bloglines browser interface. Defaults to 1.
213
214 For people who uses Bloglines browser interface regularly, and use
215 Plagger as a tool to synchronize feed updates to mobile devices (like
216 PSP or iPod), I'd recommend set this option to 0.
217
218 Otherwise, especially for Publish::Gmail plugin users, I recommend set
219 to 1, the default.
220
221 =item fetch_meta
222
223 C<fetch_meta> specifies whether this plugin fetches I<folder>
224 strucuture using listsubs API. With this option on, all feeds under
225 I<Plagger> folder will have I<Plagger> as its tag.
226
227 You can use this tags information using Rules in later phase.
228
229 =back
230
231 =head1 AUTHOR
232
233 Tatsuhiko Miyagawa
234
235 =head1 SEE ALSO
236
237 L<Plagger>, L<WebService::Bloglines>, L<http://www.bloglines.com/>
238
239 =cut
240
Note: See TracBrowser for help on using the browser.