root/trunk/plagger/lib/Plagger/Plugin/CustomFeed/Frepa.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::CustomFeed::Frepa;
2 use strict;
3 use base qw( Plagger::Plugin );
4
5 use DateTime::Format::Strptime;
6 use Encode;
7 use Time::HiRes;
8 use UNIVERSAL::require;
9 use Plagger::Mechanize;
10
11 sub plugin_id {
12     my $self = shift;
13     $self->class_id . '-' . $self->conf->{livedoor_id};
14 }
15
16 sub register {
17     my ($self, $context) = @_;
18     $context->register_hook(
19         $self,
20         'subscription.load' => \&load,
21     );
22 }
23
24 sub load {
25     my ($self, $context) = @_;
26
27     $self->{mech} = Plagger::Mechanize->new(cookie_jar => $self->cookie_jar);
28
29     my $feed = Plagger::Feed->new;
30     $feed->aggregator(sub { $self->aggregate(@_) });
31     $context->subscription->add($feed);
32 }
33
34 sub aggregate {
35     my ($self, $context, $args) = @_;
36
37     unless ($self->login(livedoor_id => $self->conf->{livedoor_id}, password => $self->conf->{password})) {
38         $context->log(error => "Login to frepa failed.");
39         return;
40     }
41
42     $context->log(info => 'Login to frepa succeeded.');
43
44     my $feed_type = $self->conf->{feed_type} || [ qw(FriendDiary FriendStatus RecentComment) ];
45     for my $plugin (@$feed_type) {
46         my $plugin = (ref $self || $self) . "::$plugin";
47         $plugin->require or $context->error($@);
48         $self->aggregate_by_plugin($context, $plugin, $args);
49     }
50 }
51
52 sub aggregate_by_plugin {
53     my ($self, $context, $plugin, $args) = @_;
54
55     my $feed = Plagger::Feed->new;
56     $feed->type('frepa');
57     $feed->title($plugin->title);
58     $feed->link($plugin->start_url);
59
60     my $format = DateTime::Format::Strptime->new(pattern => '%Y/%m/%d %H:%M');
61
62     my @msgs = $plugin->get_list($self->{mech}, $self);
63     my $items = $self->conf->{fetch_items} || 20;
64
65     my $i = 0;
66     my $blocked = 0;
67     for my $msg (@msgs) {
68         last if $i++ >= $items;
69
70         my $entry = Plagger::Entry->new;
71         $entry->title($msg->{subject});
72         $entry->link($msg->{link});
73         $entry->author($msg->{name});
74         $entry->date( Plagger::Date->parse($format, $msg->{time}) );
75
76         if ($self->conf->{fetch_body} && !$blocked and $plugin->can('get_detail')) {
77             $context->log(info => "Fetch body from $msg->{link}");
78             my $item = $self->cache->get_callback(
79                 "item-$msg->{link}",
80                 sub {
81                     Time::HiRes::sleep( $self->conf->{fetch_body_interval} || 1.5 );
82                     $plugin->get_detail($msg->{link}, $self->{mech});
83                 },
84                 "1 hour",
85             );
86             if ($item) {
87                 my $body = $item->{description};
88                    $body =~ s!<br>!<br />!g;
89                 $entry->body($body);
90                 $entry->title($item->{subject}); # replace with full title
91             } else {
92                 $context->log(warn => "Fetch body failed. You might be blocked?");
93                 $blocked++;
94             }
95         }
96
97         if ($self->conf->{show_icon} && !$blocked) {
98             my $item = $self->fetch_icon($msg->{user_link});
99             if ($item && $item->{image} !~ /no_photo/) {
100                 $entry->icon({
101                     title => $item->{name},
102                     url   => $item->{image},
103                     link  => $msg->{user_link},
104                 });
105             }
106         }
107
108         $feed->add_entry($entry);
109     }
110
111     $context->update->add($feed);
112 }
113
114 sub fetch_icon {
115     my($self, $url) = @_;
116
117     Plagger->context->log(info => "Fetch icon from $url");
118     $self->cache->get_callback(
119         "icon-$url",
120         sub { $self->get_top($url) },
121         '1 day',
122     );
123 }
124
125 sub login {
126     my $self = shift;
127     my %args = @_;
128
129     my $start_url = 'http://www.frepa.livedoor.com/';
130     my $res = $self->{mech}->get($start_url);
131     return 0 unless $self->{mech}->success;
132
133     if ($self->{mech}->content =~ /loginside/) {
134         Plagger->context->log(debug => "cookie not found. logging in");
135         $self->{mech}->submit_form(
136             fields => {
137                 livedoor_id => $args{livedoor_id},
138                 password    => $args{password},
139                 auto_login  => 'on',
140             },
141         );
142         $self->{mech}->submit;
143         return 0 unless $self->{mech}->success;
144         return 0 if $self->{mech}->content =~ /loginside/;
145     }
146
147     return 1;
148 }
149
150 sub get_top {
151     my $self = shift;
152     my $link = shift;
153
154     my $item = {};
155     my $res = $self->{mech}->get($link);
156     return $item unless $self->{mech}->success;
157
158     my $html = decode('euc-jp', $self->{mech}->content);
159
160     chomp( my $re  = decode('utf-8', $self->top_re) );
161     if ($html =~ /$re/s) {
162         $item->{image} = $1;
163         $item->{name}  = $2;
164     }
165
166     return $item;
167 }
168
169 sub top_re {
170     return <<'RE';
171 <a href="http://(?:frepa\.livedoor\.com/.*?/|www\.frepa\.livedoor\.com/)"(?: rel="popup")?><img src="(http://img\d+\.(?:ico\.frepa\.livedoor\.com/member_photo/|bbs\.frepa\.livedoor\.com/community_board/).*?\.(?:jpe?g|JPE?G|gif|GIF|png|PNG))" border="0"></a>
172 </small>
173 .*?
174 <div id="namebody"><small><strong>(.*?)....</strong>
175 RE
176 }
177
178 1;
179
180 __END__
181
182 =head1 NAME
183
184 Plagger::Plugin::CustomFeed::Frepa - Custom feed for livedoor Frepa
185
186 =head1 SYNOPSIS
187
188   - module: CustomFeed::Frepa
189     config:
190       livedoor_id: your-id
191       password: password
192       fetch_body: 1
193       show_icon: 1
194       feed_type:
195         - FriendDiary
196         - FriendStatus
197         - RecentComment
198
199 =head1 DESCRIPTION
200
201 This plugin fetches your friend blog updates from livedoor Frepa
202 (L<http://frepa.livedoor.com/>) and creates a custom feed.
203
204 =head1 CONFIGURATION
205
206 See L<Plagger::Plugin::CustomFeed::Mixi> for C<fetch_body>,
207 C<fetch_body_interval> and C<show_icon>.
208
209 Note that you don't have to supply livedoor_id and password if you set
210 global cookie_jar in your configuration file and the cookie_jar
211 contains a valid login session there, such as:
212
213   global:
214     user_agent:
215       cookies: /path/to/cookies.txt
216
217 See L<Plagger::Cookies> for details.
218
219
220 =head1 AUTHOR
221
222 Kazuhiro Osawa
223
224 Tokuhiro Matsuno
225
226 Tatsuhiko Miyagawa
227
228 =head1 SEE ALSO
229
230 L<Plagger>, L<Plagger::Plugin::CustomFeed::Mixi>, L<Plagger::Mechanize>,
231 L<http://frepa.livedoor.com/>
232
233 =cut
Note: See TracBrowser for help on using the browser.