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

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

LivedoorReader?: skip if there's no modified_on. more debugging

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
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} = WWW::Mechanize->new;
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->{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($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     $self->{mech}->submit_form(
118         form_name => 'loginForm',
119         fields => {
120             livedoor_id => $self->conf->{username},
121             password    => $self->conf->{password},
122         },
123     );
124
125     if ( $self->{mech}->content =~ /class="headcopy"/ ) {
126         Plagger->context->error("Failed to login using username & password");
127     }
128 }
129
130 sub _request {
131     my($self, $method, $param) = @_;
132
133     my $uri = URI->new_abs($method, "http://reader.livedoor.com/");
134     $uri->query_param(%$param) if $param;
135
136     $self->{mech}->get($uri->as_string);
137
138     return JSON::Syck::Load($self->{mech}->content);
139 }
140
141 1;
142
143 __END__
144
145 =head1 NAME
146
147 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
148
149 =head1 SYNOPSIS
150
151   - module: Subscription::LivedoorReader
152     config:
153       username: your-livedoor-id
154       password: your-password
155       mark_read: 1
156
157 =head1 DESCRIPTION
158
159 This plugin allows you to synchronize your subscription using Livedoor
160 Reader JSON API.
161
162 =head1 CONFIGURATION
163
164 =over 4
165
166 =item username, password
167
168 Your username & password to use with livedoor Reader.
169
170 =item mark_read
171
172 C<mark_read> specifies whether this plugin I<marks as read> the items
173 you synchronize. With this option set to 0, you will get the
174 duplicated updates everytime you run Plagger, until you mark them
175 unread using Livedoor Reader web interface.
176
177 =back
178
179 =head1 AUTHOR
180
181 Tatsuhiko Miyagawa
182
183 =head1 SEE ALSO
184
185 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
186
187 =cut
188
Note: See TracBrowser for help on using the browser.