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

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

Subscription::LivedoorReader?: Better error handling.
via http://d.hatena.ne.jp/sfujiwara/20060629/1151562692

Line 
1 package Plagger::Plugin::Subscription::LivedoorReader;
2 use strict;
3 use base qw( Plagger::Plugin );
4
5 use JSON::Syck;
6 use URI;
7 use Plagger::Mechanize;
8 use Plagger::Util;
9
10 sub plugin_id {
11     my $self = shift;
12     $self->class_id . '-' . $self->conf->{username};
13 }
14
15 sub register {
16     my($self, $context) = @_;
17
18     $self->init_reader;
19     $context->register_hook(
20         $self,
21         'subscription.load' => \&notifier,
22     );
23 }
24
25 sub init_reader {
26     my $self = shift;
27     $self->{mech} = Plagger::Mechanize->new(cookie_jar => $self->cookie_jar);
28
29     unless (defined($self->conf->{username}) && defined($self->conf->{password})) {
30         Plagger->context->error("username and/or password is missing");
31     }
32 }
33
34 sub notifier {
35     my($self, $context) = @_;
36
37     $self->{mech}->get("http://rpc.reader.livedoor.com/notify?user=" . $self->conf->{username});
38     my $content = $self->{mech}->content;
39
40     # copied from WebService/Bloglines.pm
41
42     # |A|B| where A is the number of unread items
43     $content =~ /\|([\-\d]+)|(.*)|/
44         or $context->error("Bad Response: $content");
45
46     my($unread, $url) = ($1, $2);
47
48     # A is -1 if the user email address is wrong.
49     if ($unread == -1) {
50         $context->error("Bad username: " . $self->conf->{username});
51     }
52
53     return unless $unread;
54
55     $context->log(info => "You have $unread unread item(s) on livedoor Reader.");
56
57     my $feed = Plagger::Feed->new;
58     $feed->aggregator(sub { $self->sync(@_) });
59     $context->subscription->add($feed);
60 }
61
62 sub sync {
63     my($self, $context, $args) = @_;
64
65     my $mark_read = $self->conf->{mark_read};
66        $mark_read = 1 unless defined $mark_read;
67
68     $self->login_reader();
69
70     my $subs = $self->_request("/api/subs", { unread => 1 }) || [];
71
72     for my $sub (@$subs) {
73         $context->log(debug => "get unread items of $sub->{subscribe_id}");
74         my $data = $self->_request("/api/unread", { subscribe_id => $sub->{subscribe_id} }) or next;
75
76         my $feed = Plagger::Feed->new;
77         $feed->type('livedoorReader');
78         $feed->title( Plagger::Util::strip_html($data->{channel}->{title}) );
79         $feed->link($data->{channel}->{link});
80         $feed->url($data->{channel}->{feedlink});
81         $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
82         $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
83         $feed->meta->{rate} = $sub->{rate};
84         $feed->add_tag($_) for @{$sub->{tags}};
85         $feed->add_tag($sub->{folder}) if $sub->{folder};
86         $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) ) if $sub->{modified_on};
87         $feed->description($data->{channel}->{description});
88         $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
89
90         for my $item ( @{$data->{items}} ) {
91             my $entry = Plagger::Entry->new;
92             $entry->title($item->{title});
93             $entry->author($item->{author}) if $item->{author};
94             $entry->link($item->{link});
95             # TODO support enclosure
96             $entry->tags([ $item->{category} ]) if $item->{category};
97             $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
98             $entry->meta->{livedoor_reader_item_id} = $item->{id};
99             $entry->feed_link($feed->link);
100             $entry->body($item->{body});
101
102             $feed->add_entry($entry);
103         }
104
105         $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
106             if $mark_read;
107
108         $context->update->add($feed);
109     }
110 }
111
112 sub login_reader {
113     my $self = shift;
114
115     local $^W; # input type="search" warning
116     $self->{mech}->get("http://reader.livedoor.com/reader/");
117
118     if ($self->{mech}->content =~ /name="loginForm"/) {
119         Plagger->context->log(debug => "Logging in to Livedoor Reader");
120         $self->{mech}->submit_form(
121             form_name => 'loginForm',
122             fields => {
123                 livedoor_id => $self->conf->{username},
124                 password    => $self->conf->{password},
125             },
126         );
127
128         if ( $self->{mech}->content =~ /class="headcopy"/ ) {
129             Plagger->context->error("Failed to login using username & password");
130         }
131     }
132
133     $self->{mech}->cookie_jar->scan(
134         sub {
135             my($key, $val) = @_[1,2];
136             if ($key =~ /_sid/) {
137                 $self->{apikey} = $val;
138                 return;
139             }
140         },
141     );
142 }
143
144 sub _request {
145     my($self, $method, $param) = @_;
146
147     my $uri = URI->new_abs($method, "http://reader.livedoor.com/");
148     $uri->query_form(%$param, ApiKey => $self->{apikey});
149
150     $self->{mech}->get($uri->as_string);
151
152     if ($self->{mech}->status == 200) {
153         return JSON::Syck::Load($self->{mech}->content);
154     }
155
156     return;
157 }
158
159 1;
160
161 __END__
162
163 =head1 NAME
164
165 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
166
167 =head1 SYNOPSIS
168
169   - module: Subscription::LivedoorReader
170     config:
171       username: your-livedoor-id
172       password: your-password
173       mark_read: 1
174
175 =head1 DESCRIPTION
176
177 This plugin allows you to synchronize your subscription using Livedoor
178 Reader JSON API.
179
180 =head1 CONFIGURATION
181
182 =over 4
183
184 =item username, password
185
186 Your username & password to use with livedoor Reader.
187
188 Note that you don't have to supply username and password if you set
189 global cookie_jar in your configuration file and the cookie_jar
190 contains a valid login session there, such as:
191
192   global:
193     user_agent:
194       cookies: /path/to/cookies.txt
195
196 See L<Plagger::Cookies> for details.
197
198 =item mark_read
199
200 C<mark_read> specifies whether this plugin I<marks as read> the items
201 you synchronize. With this option set to 0, you will get the
202 duplicated updates everytime you run Plagger, until you mark them
203 unread using Livedoor Reader web interface.
204
205 =back
206
207 =head1 AUTHOR
208
209 Tatsuhiko Miyagawa
210
211 =head1 SEE ALSO
212
213 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
214
215 =cut
216
Note: See TracBrowser for help on using the browser.