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

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

Subscription::LivedoorReader?: use POST per mala

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($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}) )
98                 if $item->{modified_on};
99             $entry->meta->{livedoor_reader_item_id} = $item->{id};
100             $entry->feed_link($feed->link);
101             $entry->body($item->{body});
102
103             $feed->add_entry($entry);
104         }
105
106         $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
107             if $mark_read;
108
109         $context->update->add($feed);
110     }
111 }
112
113 sub login_reader {
114     my $self = shift;
115
116     local $^W; # input type="search" warning
117     $self->{mech}->get("http://reader.livedoor.com/reader/");
118
119     if ($self->{mech}->content =~ /name="loginForm"/) {
120         Plagger->context->log(debug => "Logging in to Livedoor Reader");
121         $self->{mech}->submit_form(
122             form_name => 'loginForm',
123             fields => {
124                 livedoor_id => $self->conf->{username},
125                 password    => $self->conf->{password},
126             },
127         );
128
129         if ( $self->{mech}->content =~ /class="headcopy"/ ) {
130             Plagger->context->error("Failed to login using username & password");
131         }
132     }
133
134     $self->{mech}->cookie_jar->scan(
135         sub {
136             my($key, $val) = @_[1,2];
137             if ($key =~ /_sid/) {
138                 $self->{apikey} = $val;
139                 return;
140             }
141         },
142     );
143 }
144
145 sub _request {
146     my($self, $method, $param) = @_;
147
148     my $uri = URI->new_abs($method, "http://reader.livedoor.com/");
149     $self->{mech}->post($uri, { %$param, ApiKey => $self->{apikey} });
150
151     if ($self->{mech}->status == 200) {
152         return JSON::Syck::Load($self->{mech}->content);
153     }
154
155     return;
156 }
157
158 1;
159
160 __END__
161
162 =head1 NAME
163
164 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
165
166 =head1 SYNOPSIS
167
168   - module: Subscription::LivedoorReader
169     config:
170       username: your-livedoor-id
171       password: your-password
172       mark_read: 1
173
174 =head1 DESCRIPTION
175
176 This plugin allows you to synchronize your subscription using Livedoor
177 Reader JSON API.
178
179 =head1 CONFIGURATION
180
181 =over 4
182
183 =item username, password
184
185 Your username & password to use with livedoor Reader.
186
187 Note that you don't have to supply username and password if you set
188 global cookie_jar in your configuration file and the cookie_jar
189 contains a valid login session there, such as:
190
191   global:
192     user_agent:
193       cookies: /path/to/cookies.txt
194
195 See L<Plagger::Cookies> for details.
196
197 =item mark_read
198
199 C<mark_read> specifies whether this plugin I<marks as read> the items
200 you synchronize. With this option set to 0, you will get the
201 duplicated updates every time you run Plagger, until you mark them
202 unread using Livedoor Reader web interface.
203
204 =back
205
206 =head1 AUTHOR
207
208 Tatsuhiko Miyagawa
209
210 =head1 SEE ALSO
211
212 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
213
214 =cut
215
Note: See TracBrowser for help on using the browser.