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

Revision 810 (checked in by miyagawa, 14 years ago)
  • added Plagger::Mechanize for a wrapper class around WWW::Mech (to set User-Agent from global config)
  • Updated plugins to use Plagger::Mechanize where WWW::Mech was used.
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} });
75         $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
76             if $mark_read;
77
78         my $feed = Plagger::Feed->new;
79         $feed->type('livedoorReader');
80         $feed->title( Plagger::Util::strip_html($data->{channel}->{title}) );
81         $feed->link($data->{channel}->{link});
82         $feed->url($data->{channel}->{feedlink});
83         $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
84         $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
85         $feed->meta->{rate} = $sub->{rate};
86         $feed->add_tag($_) for @{$sub->{tags}};
87         $feed->add_tag($sub->{folder}) if $sub->{folder};
88         $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) ) if $sub->{modified_on};
89         $feed->description($data->{channel}->{description});
90         $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
91
92         for my $item ( @{$data->{items}} ) {
93             my $entry = Plagger::Entry->new;
94             $entry->title($item->{title});
95             $entry->author($item->{author}) if $item->{author};
96             $entry->link($item->{link});
97             # TODO support enclosure
98             $entry->tags([ $item->{category} ]) if $item->{category};
99             $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
100             $entry->meta->{livedoor_reader_item_id} = $item->{id};
101             $entry->feed_link($feed->link);
102             $entry->body($item->{body});
103
104             $feed->add_entry($entry);
105         }
106
107         $context->update->add($feed);
108     }
109 }
110
111 sub login_reader {
112     my $self = shift;
113
114     local $^W; # input type="search" warning
115     $self->{mech}->get("http://reader.livedoor.com/reader/");
116
117     if ($self->{mech}->content =~ /name="loginForm"/) {
118         Plagger->context->log(debug => "Logging in to Livedoor Reader");
119         $self->{mech}->submit_form(
120             form_name => 'loginForm',
121             fields => {
122                 livedoor_id => $self->conf->{username},
123                 password    => $self->conf->{password},
124             },
125         );
126
127         if ( $self->{mech}->content =~ /class="headcopy"/ ) {
128             Plagger->context->error("Failed to login using username & password");
129         }
130     }
131
132     $self->{mech}->cookie_jar->scan(
133         sub {
134             my($key, $val) = @_[1,2];
135             if ($key =~ /_sid/) {
136                 $self->{apikey} = $val;
137                 return;
138             }
139         },
140     );
141 }
142
143 sub _request {
144     my($self, $method, $param) = @_;
145
146     my $uri = URI->new_abs($method, "http://reader.livedoor.com/");
147     $uri->query_form(%$param, ApiKey => $self->{apikey});
148
149     $self->{mech}->get($uri->as_string);
150
151     return JSON::Syck::Load($self->{mech}->content);
152 }
153
154 1;
155
156 __END__
157
158 =head1 NAME
159
160 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
161
162 =head1 SYNOPSIS
163
164   - module: Subscription::LivedoorReader
165     config:
166       username: your-livedoor-id
167       password: your-password
168       mark_read: 1
169
170 =head1 DESCRIPTION
171
172 This plugin allows you to synchronize your subscription using Livedoor
173 Reader JSON API.
174
175 =head1 CONFIGURATION
176
177 =over 4
178
179 =item username, password
180
181 Your username & password to use with livedoor Reader.
182
183 Note that you don't have to supply username and password if you set
184 global cookie_jar in your configuration file and the cookie_jar
185 contains a valid login session there, such as:
186
187   global:
188     user_agent:
189       cookies: /path/to/cookies.txt
190
191 See L<Plagger::Cookies> for details.
192
193 =item mark_read
194
195 C<mark_read> specifies whether this plugin I<marks as read> the items
196 you synchronize. With this option set to 0, you will get the
197 duplicated updates everytime you run Plagger, until you mark them
198 unread using Livedoor Reader web interface.
199
200 =back
201
202 =head1 AUTHOR
203
204 Tatsuhiko Miyagawa
205
206 =head1 SEE ALSO
207
208 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
209
210 =cut
211
Note: See TracBrowser for help on using the browser.