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

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

add Subscription::LivedoorReader?

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         my $data = $self->_request("/api/unread", { subscribe_id => $sub->{subscribe_id} });
74         $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
75             if $mark_read;
76
77         my $feed = Plagger::Feed->new;
78         $feed->type('livedoorReader');
79         $feed->title($data->{channel}->{title});
80         $feed->link($data->{channel}->{link});
81         $feed->url($data->{channel}->{feedlink});
82         $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
83         $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
84         $feed->meta->{rate} = $sub->{rate}; # xxx star?
85         $feed->add_tag($_) for @{$sub->{tags}};
86         $feed->add_tag($sub->{folder}) if $sub->{folder};
87         $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) );
88         $feed->description($data->{channel}->{description});
89         $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
90
91         for my $item ( @{$data->{items}} ) {
92             my $entry = Plagger::Entry->new;
93             $entry->title($item->{title});
94             $entry->author($item->{author}) if $item->{author};
95             $entry->link($item->{link});
96             # TODO support enclosure
97             $entry->tags([ $item->{category} ]) if $item->{category};
98             $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
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         $context->update->add($feed);
107     }
108 }
109
110 sub login_reader {
111     my $self = shift;
112
113     local $^W; # input type="search" warning
114     $self->{mech}->get("http://reader.livedoor.com/reader/");
115
116     $self->{mech}->submit_form(
117         form_name => 'loginForm',
118         fields => {
119             livedoor_id => $self->conf->{username},
120             password    => $self->conf->{password},
121         },
122     );
123
124     if ( $self->{mech}->content =~ /class="headcopy"/ ) {
125         Plagger->context->error("Failed to login using username & password");
126     }
127 }
128
129 sub _request {
130     my($self, $method, $param) = @_;
131
132     my $uri = URI->new_abs($method, "http://reader.livedoor.com/");
133     $uri->query_param(%$param) if $param;
134
135     $self->{mech}->get($uri->as_string);
136
137     return JSON::Syck::Load($self->{mech}->content);
138 }
139
140 1;
141
142 __END__
143
144 =head1 NAME
145
146 Plagger::Plugin::Subscription::LivedoorReader - Synchronize livedoor Reader with JSON API
147
148 =head1 SYNOPSIS
149
150   - module: Subscription::LivedoorReader
151     config:
152       username: your-livedoor-id
153       password: your-password
154       mark_read: 1
155
156 =head1 DESCRIPTION
157
158 This plugin allows you to synchronize your subscription using Livedoor
159 Reader JSON API.
160
161 =head1 CONFIGURATION
162
163 =over 4
164
165 =item username, password
166
167 Your username & password to use with livedoor Reader.
168
169 =item mark_read
170
171 C<mark_read> specifies whether this plugin I<marks as read> the items
172 you synchronize. With this option set to 0, you will get the
173 duplicated updates everytime you run Plagger, until you mark them
174 unread using Livedoor Reader web interface.
175
176 =back
177
178 =head1 AUTHOR
179
180 Tatsuhiko Miyagawa
181
182 =head1 SEE ALSO
183
184 L<Plagger>, L<Plagger::Plugin::Subscription::Bloglines>, L<http://reader.livedoor.com/>
185
186 =cut
187
Note: See TracBrowser for help on using the browser.