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

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

Add Sticky Query ApiKey? to LivedoorReader? API requests. Fixes #253

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 URI::QueryParam;
8 use WWW::Mechanize;
9 use Plagger::Util;
10
11 sub plugin_id {
12     my $self = shift;
13     $self->class_id . '-' . $self->conf->{username};
14 }
15
16 sub register {
17     my($self, $context) = @_;
18
19     $self->init_reader;
20     $context->register_hook(
21         $self,
22         'subscription.load' => \&notifier,
23     );
24 }
25
26 sub init_reader {
27     my $self = shift;
28     $self->{mech} = WWW::Mechanize->new(cookie_jar => $self->cache->cookie_jar);
29
30     unless (defined($self->conf->{username}) && defined($self->conf->{password})) {
31         Plagger->context->error("username and/or password is missing");
32     }
33 }
34
35 sub notifier {
36     my($self, $context) = @_;
37
38     $self->{mech}->get("http://rpc.reader.livedoor.com/notify?user=" . $self->conf->{username});
39     my $content = $self->{mech}->content;
40
41     # copied from WebService/Bloglines.pm
42
43     # |A|B| where A is the number of unread items
44     $content =~ /\|([\-\d]+)|(.*)|/
45         or $context->error("Bad Response: $content");
46
47     my($unread, $url) = ($1, $2);
48
49     # A is -1 if the user email address is wrong.
50     if ($unread == -1) {
51         $context->error("Bad username: " . $self->conf->{username});
52     }
53
54     return unless $unread;
55
56     $context->log(info => "You have $unread unread item(s) on livedoor Reader.");
57
58     my $feed = Plagger::Feed->new;
59     $feed->aggregator(sub { $self->sync(@_) });
60     $context->subscription->add($feed);
61 }
62
63 sub sync {
64     my($self, $context, $args) = @_;
65
66     my $mark_read = $self->conf->{mark_read};
67        $mark_read = 1 unless defined $mark_read;
68
69     $self->login_reader();
70
71     my $subs = $self->_request("/api/subs", { unread => 1 });
72
73     for my $sub (@$subs) {
74         $context->log(debug => "get unread items of $sub->{subscribe_id}");
75         my $data = $self->_request("/api/unread", { subscribe_id => $sub->{subscribe_id} });
76         $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
77             if $mark_read;
78
79         my $feed = Plagger::Feed->new;
80         $feed->type('livedoorReader');
81         $feed->title( Plagger::Util::strip_html($data->{channel}->{title}) );
82         $feed->link($data->{channel}->{link});
83         $feed->url($data->{channel}->{feedlink});
84         $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
85         $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
86         $feed->meta->{rate} = $sub->{rate};
87         $feed->add_tag($_) for @{$sub->{tags}};
88         $feed->add_tag($sub->{folder}) if $sub->{folder};
89         $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) ) if $sub->{modified_on};
90         $feed->description($data->{channel}->{description});
91         $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
92
93         for my $item ( @{$data->{items}} ) {
94             my $entry = Plagger::Entry->new;
95             $entry->title($item->{title});
96             $entry->author($item->{author}) if $item->{author};
97             $entry->link($item->{link});
98             # TODO support enclosure
99             $entry->tags([ $item->{category} ]) if $item->{category};
100             $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
101             $entry->meta->{livedoor_reader_item_id} = $item->{id};
102             $entry->feed_link($feed->link);
103             $entry->body($item->{body});
104
105             $feed->add_entry($entry);
106         }
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     return JSON::Syck::Load($self->{mech}->content);
153 }
154
155 1;
156
157 __END__
158
159 =head1 NAME
160
161 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
162
163 =head1 SYNOPSIS
164
165   - module: Subscription::LivedoorReader
166     config:
167       username: your-livedoor-id
168       password: your-password
169       mark_read: 1
170
171 =head1 DESCRIPTION
172
173 This plugin allows you to synchronize your subscription using Livedoor
174 Reader JSON API.
175
176 =head1 CONFIGURATION
177
178 =over 4
179
180 =item username, password
181
182 Your username & password to use with livedoor Reader.
183
184 =item mark_read
185
186 C<mark_read> specifies whether this plugin I<marks as read> the items
187 you synchronize. With this option set to 0, you will get the
188 duplicated updates everytime you run Plagger, until you mark them
189 unread using Livedoor Reader web interface.
190
191 =back
192
193 =head1 AUTHOR
194
195 Tatsuhiko Miyagawa
196
197 =head1 SEE ALSO
198
199 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
200
201 =cut
202
Note: See TracBrowser for help on using the browser.