root/lang/perl/WebService-Nowa/trunk/lib/WebService/Nowa.pm @ 5295

Revision 5295, 4.9 kB (checked in by woremacx, 5 years ago)

initial import of POE-Component-Client-Nowa and WebService?-Nowa

Line 
1package WebService::Nowa;
2
3# copyed from http://blog.livedoor.jp/nipotan/archives/50716810.html
4use strict;
5use 5.8.1;
6our $VERSION = '0.01';
7
8use strict;
9use WWW::Mechanize;
10use Time::HiRes qw(time);
11use Carp;
12use URI;
13use JSON::Syck;
14use Data::Dumper;
15use Encode ();
16use Scalar::Util qw(blessed);
17use List::Util qw(first);
18use Web::Scraper;
19
20use constant NOWA_HOME => 'http://my.nowa.jp/home/';
21
22sub new {
23    my $class = shift;
24    unless (ref($_[0]) eq 'HASH') {
25        croak "invalid argument";
26    }
27    my $self = shift;
28    my $mech = WWW::Mechanize->new( stack_depth => 1 );
29    $mech->agent_alias('Windows IE 6');
30    $self->{mech} = $mech;
31    bless $self, $class;
32    return $self;
33}
34
35sub update_nanishiteru {
36    my($self, $nanishiteru) = @_;
37    $self->_login unless $self->{_logged_in};
38    $self->_home;
39    my($rkey) =
40        $self->{mech}->content =~ m{hitokoto\.init\(\s*"([a-z\d]+)"\s*\)}i;
41    croak "Cannot find rkey" unless $rkey;
42    my $uri = URI->new_abs('/internal_api/status_message/', NOWA_HOME);
43    my($sec, $fsec) = time() =~ /^(\d+)(?:\.(\d+))?$/;
44    $fsec = substr($fsec, 0, 3);
45    $fsec .= '0' while length $fsec < 3;
46    my $uniqid = sprintf('%d%d', $sec, $fsec);
47    $uri->query_form(
48        rkey   => $rkey,
49        uniqid => $uniqid,
50        body   => $nanishiteru,
51    );
52    $self->{mech}->get($uri->as_string);
53    my $result = JSON::Syck::Load($self->{mech}->content);
54    croak "Cannot update your nanishiteru." if $result->{status} ne 'success';
55    return 1;
56}
57
58# from Web::Scraper
59sub scrape {
60    my ($self, $s, $url) = @_;
61
62    my $stuff = $url;
63    $stuff = $url->as_string if (blessed($url) && $url->isa('URI'));
64
65    require Encode;
66    require HTTP::Response::Encoding;
67
68    my $res = $self->{mech}->get($stuff);
69    my @encoding = (
70        $res->encoding,
71        ($res->header('Content-Type') =~ /charset=([\w\-]+)/g),
72        "latin-1",
73    );
74    my $encoding = first { defined $_ && Encode::find_encoding($_) } @encoding;
75    my $html = Encode::decode($encoding, $self->{mech}->content);
76
77    my $base = ($res->content =~ /<base\s+href="([^"]+)"/)[0] || $stuff;
78
79    my $scraped = $s->scrape($html, $base);
80    $scraped;
81}
82
83sub channels {
84    my $self = shift;
85    $self->_login unless $self->{_logged_in};
86
87    my $s = scraper {
88        process 'ul.home-chlist > li', 'channels[]' => scraper {
89            process 'a',
90                'name', 'TEXT',
91                'link', '@href';
92        };
93    };
94    my $res = $self->scrape($s, URI->new('http://my.nowa.jp/home/'));
95    my $data;
96    for my $chan (@{ $res->{channels} }) {
97        my $id = '#' . ($chan->{link} =~ m!^http://nowa.jp/ch/(.*?)/!)[0];
98        my $name = $chan->{name};
99        $name =~ s/\(\d+\)$//;
100        $data->{$id} = $name;
101    }
102    return wantarray ? %$data : $data;
103}
104
105sub recent {
106    my $self = shift;
107    $self->_login unless $self->{_logged_in};
108
109    my $s = scraper {
110        process '//div[@class="friendentry-box clearfix"]', 'entries[]' => scraper {
111            process '//div[@class="friendentrybody"]/a', 'userlink', '@href';
112            process 'span.time > a', 'permalink', '@href';
113
114            # message
115            process 'h2.statustitle', 'body', 'TEXT';
116
117            # entry
118            process '//h2[@class!="statustitle"]/a',
119                'entry', 'TEXT',
120                'entrylink', '@href';
121        };
122    };
123    my $res = $self->scrape($s, URI->new('http://my.nowa.jp/friend/'));
124
125    my @data;
126    for my $entry (@{ $res->{entries} }) {
127        my $user = ($entry->{userlink} =~ m!^http://([^\.]+)\.nowa\.jp/!)[0];
128        my $body;
129        if ($entry->{entry}) {
130            $body = $entry->{entry} . " " . $entry->{entrylink};
131            $entry->{permalink} = $entry->{entrylink};
132        } else {
133            $body = $entry->{body};
134        }
135
136        push(@data, +{
137            user      => $user,
138            permalink => $entry->{permalink},
139            body      => $body,
140        });
141    }
142
143    return wantarray ? @data : \@data;
144}
145
146sub _home {
147    my $self = shift;
148    if ($self->{mech}->uri ne NOWA_HOME) {
149        $self->{mech}->get(NOWA_HOME);
150    }
151    $self->_login unless $self->{mech}->uri ne NOWA_HOME;
152}
153
154sub _login {
155    my $self = shift;
156    $self->{mech}->get(NOWA_HOME);
157    $self->{_logged_in} = 1 if $self->{mech}->uri eq NOWA_HOME;
158    return if $self->{_logged_in};
159    my $uri = $self->{mech}->uri;
160    $self->{mech}->submit_form(
161        form_number => 1,
162        fields      => +{
163            nowa_id  => $self->{nowa_id},
164            password => $self->{password},
165        },
166    );
167    croak("login failed.") if $self->{mech}->uri eq $uri;
168    $self->{_logged_in} = 1;
169}
170
1711;
172
173__END__
174
175=head1 NAME
176
177WebService::Nowa -
178
179=head1 SYNOPSIS
180
181  use WebService::Nowa;
182
183=head1 DESCRIPTION
184
185WebService::Nowa is
186
187=head1 AUTHOR
188
189woremacx E<lt>woremacx at gmail dot comE<gt>
190
191=head1 LICENSE
192
193This library is free software; you can redistribute it and/or modify
194it under the same terms as Perl itself.
195
196=head1 SEE ALSO
197
198=cut
Note: See TracBrowser for help on using the browser.