File Coverage

blib/lib/Net/Kotonoha.pm
Criterion Covered Total %
statement 24 97 24.7
branch 0 32 0.0
condition 0 20 0.0
subroutine 8 20 40.0
pod 1 10 10.0
total 33 179 18.4


line stmt bran cond sub pod time code
1             package Net::Kotonoha;
2              
3 2     2   3227 use strict;
  2         4  
  2         68  
4 2     2   11 use warnings;
  2         4  
  2         68  
5 2     2   11 use Carp;
  2         4  
  2         156  
6 2     2   2773 use WWW::Mechanize;
  2         422634  
  2         184  
7 2     2   2367 use HTML::Selector::XPath qw/selector_to_xpath/;
  2         7402  
  2         179  
8 2     2   2166 use HTML::TreeBuilder::XPath;
  2         88906  
  2         25  
9 2     2   87 use HTML::Entities qw/decode_entities/;
  2         4  
  2         123  
10 2     2   1319 use Net::Kotonoha::Koto;
  2         7  
  2         2214  
11              
12             our $VERSION = '0.08';
13              
14             sub new {
15 0     0 1   my $class = shift;
16 0           my %args = @_;
17              
18 0   0       $args{mail} ||= '';
19 0   0       $args{password} ||= '';
20 0   0       $args{user} ||= '';
21 0   0       $args{limit} ||= 1000;
22              
23 0 0 0       croak "need to set mail and password" unless $args{mail} && $args{password};
24              
25 0           my $mech = WWW::Mechanize->new;
26 0           $mech->agent_alias('Windows IE 6');
27 0           $mech->quiet(1);
28 0           $mech->add_header('Accept-Encoding', 'identity');
29 0           $args{mech} = $mech;
30              
31 0           return bless {%args}, $class;
32             }
33              
34             sub login {
35 0     0 0   my $self = shift;
36              
37 0 0         return 1 if $self->{loggedin};
38              
39 0           $self->{mech}->get('http://kotonoha.cc');
40 0           my $res = $self->{mech}->submit_form(
41             form_number => 1,
42             fields => {
43             mail => $self->{mail},
44             password => $self->{password},
45             }
46             );
47 0 0 0       if ($res->is_success && $self->{mech}->uri =~ /\/home$/) { # no critic
48 0           my $tree = HTML::TreeBuilder::XPath->new;
49 0           $tree->parse($res->content);
50 0           $tree->eof;
51 0           my $user = $tree->findnodes(selector_to_xpath('dt.profileicon a'));
52 0 0         my $link = $user ? $user->shift->attr('href') : '';
53 0 0         if ($link =~ /^\/user\/(\w+)/) {
54 0           $self->{loggedin} = ($self->{user} = $1);
55             }
56 0           $tree->delete;
57             }
58 0 0         croak "can't login kotonoha.cc" unless $self->{loggedin};
59 0           return $self->{loggedin};
60             }
61              
62             sub _get_list {
63 0     0     my $self = shift;
64 0           my $xpath = shift;
65 0   0       my $page = shift || 'http://kotonoha.cc/home';
66              
67 0 0         $self->login unless defined $self->{loggedin};
68              
69 0           my $res = $self->{mech}->get( $page );
70 0 0         croak "can't login kotonoha.cc" unless $res->is_success;
71 0 0         return unless $res->is_success;
72              
73 0           my @list;
74              
75 0           my $tree = HTML::TreeBuilder::XPath->new;
76 0           $tree->parse($res->content);
77 0           $tree->eof;
78 0           foreach my $item ($tree->findnodes(selector_to_xpath($xpath))) {
79 0 0         if ($item->attr('href') =~ /^\/no\/(\d+)/) {
80 0           my $koto_no = $1;
81 0 0         if ($item->as_text =~ /^(.*)\s*\(([^\)]+)\)$/) {
82 0           push @list, {
83             koto_no => $koto_no,
84             title => $1,
85             answers => $2
86             }
87             }
88             }
89             }
90 0           $tree->delete;
91 0           return \@list;
92             }
93              
94             sub _get_stream {
95 0     0     my $self = shift;
96 0           my $xpath = shift;
97 0   0       my $page = shift || 'http://kotonoha.cc/stream';
98              
99 0 0         $self->login unless defined $self->{loggedin};
100              
101 0           my $res = $self->{mech}->get( $page );
102 0 0         croak "can't login kotonoha.cc" unless $res->is_success;
103 0 0         return unless $res->is_success;
104              
105 0           my @list;
106              
107 0           my $tree = HTML::TreeBuilder::XPath->new;
108 0           $tree->parse($res->content);
109 0           $tree->eof;
110 0           foreach my $line ($tree->findnodes(selector_to_xpath($xpath))) {
111 0           my $html = decode_entities($line->as_HTML);
112 0 0         if ($html =~ /([^<]+)<\/a>[^<]+([^<]+)<\/a>([^ ]+)(?: [^ ]+ (.+))?$/) {
113 0   0       push @list, {
114             user => $1,
115             name => $2,
116             comment => $6 || '',
117             answer => $5,
118             koto_no => $3,
119             title => $4,
120             }
121             }
122             }
123 0           $tree->delete;
124 0           return \@list;
125             }
126              
127             sub newer_list {
128 0     0 0   return shift->_get_list('dl#newkoto a');
129             }
130              
131             sub recent_list {
132 0     0 0   return shift->_get_list('dl#recentkoto a');
133             }
134              
135             sub hot_list {
136 0     0 0   return shift->_get_list('dl#hot20 a');
137             }
138              
139             sub answered_list {
140 0     0 0   return shift->_get_list('dl#answeredkoto a');
141             }
142              
143             sub posted_list {
144 0     0 0   return shift->_get_list('dl#postedkoto a');
145             }
146              
147             sub stream_list {
148 0     0 0   return shift->_get_stream('dl#stream li');
149             }
150              
151             sub subscribed_list {
152 0     0 0   return shift->_get_stream('dl#subscribelist li', 'http://kotonoha.cc/inbox');
153             }
154              
155             sub get_koto {
156 0     0 0   my $self = shift;
157 0 0         $self->login unless defined $self->{loggedin};
158 0           return Net::Kotonoha::Koto->new(
159             kotonoha => $self,
160             koto_no => shift);
161             }
162              
163             1;
164             __END__