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

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

Auto-rewrite config if encrypted fields are found. Fixes #91

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