source: lab.git/twitter/twitterbot.pl @ 35889d4

trunk
Last change on this file since 35889d4 was 35889d4, checked in by mitty <mitty@…>, 14 years ago
  • different since_id options on mentions, search

git-svn-id: https://lab.mitty.jp/svn/lab/trunk@52 7d2118f6-f56c-43e7-95a2-4bb3031d96e7

  • Property mode set to 100755
File size: 4.6 KB
Line 
1#! /usr/bin/perl -w
2
3use strict;
4use warnings;
5use utf8;
6
7## IMPORTANT ##
8# When Net::Twitter::Lite encounters a Twitter API error or a network error,
9# it throws a Net::Twitter::Lite::Error object.
10# You can catch and process these exceptions by using eval blocks and testing $@
11## from http://search.cpan.org/perldoc?Net::Twitter::Lite#ERROR_HANDLING
12use Net::Twitter::Lite;
13use FindBin qw($Bin);
14use YAML::Tiny;
15
16my $conf = loadconf("$Bin/config.yml");
17if (! defined $conf) {
18    die "$0: cannot parse config file.\n";
19}
20my $stat = loadconf("$Bin/status.yml");
21if (! defined $stat) {
22    $stat = {};
23}
24
25my $bot = login($conf);
26if (! $bot->authorized) {
27    die "$0: this client is not yet authorized.\n";
28}
29
30my %tweets;
31my $tweet;
32
33$tweet = or_search($bot, $conf->{hashtag}, $stat->{search});
34if ($tweet) {
35    %tweets = (%tweets, %$tweet);
36}
37
38$tweet = mentions_ids($bot, $stat->{mention});
39if ($tweet) {
40    %tweets = (%tweets, %$tweet);
41}
42
43foreach my $id (sort keys %tweets) {
44    if ($tweets{$id} eq 'retweet') {
45        next;
46    }
47    sleep($conf->{sleep});
48    # retweet found tweet
49    #   $tweets->{$id} eq 'search'  => found by search API
50    #                  eq 'mention' => found by mention API
51    my $res;
52    eval {
53        $res = $bot->retweet($id);
54    };
55    if ($@) {
56        evalrescue($@);
57        warn "status_id => $id\n";
58        next;
59    }
60   
61    $stat->{$tweets{$id}} = $id;
62}
63
64if (%tweets) {
65    # save last status to yaml file
66    YAML::Tiny::DumpFile("$Bin/status.yml", $stat);
67}
68
69
70sub loadconf {
71    # load configration data from yaml formatted file
72    #   param   => scalar string of filename
73    #   ret     => hash object of yaml data
74   
75    my $file = shift @_;
76   
77    my $yaml = YAML::Tiny->read($file);
78   
79    if ($!) {
80        warn "$0: '$file' $!\n";
81    }
82   
83    return $yaml->[0];
84}
85
86sub login {
87    # make Net::Twitter::Lite object and login
88    #   param   => hash object of configration
89    #   ret     => Net::Twitter::Lite object
90   
91    my $conf = shift @_;
92   
93    my $bot = Net::Twitter::Lite->new(
94        consumer_key    => $conf->{consumer_key},
95        consumer_secret => $conf->{consumer_secret},
96    );
97   
98    $bot->access_token($conf->{access_token});
99    $bot->access_token_secret($conf->{access_token_secret});
100   
101    return $bot;
102}
103
104sub or_search {
105    # search tweets containing keywords
106    #   param   => Net::Twitter::Lite object, ArrayRef of keywords, since_id
107    #   ret     => HashRef of status_id (timeline order is destroyed)
108    #               or undef (none is found)
109   
110    my $bot      = shift @_;
111    my $keywords = shift @_;
112    my $since_id = shift @_ || 1;
113   
114    my $key = "";
115    foreach my $word (@$keywords) {
116        if ($key) {
117            $key .= " OR $word";
118        }
119        else {
120            $key = $word;
121        }
122    }
123   
124    my $res;
125    my $ids = {};
126    eval {
127        if ($key) {
128            $res = $bot->search(
129                {
130                             => $key,
131                    since_id    => $since_id,
132                }
133            );
134        }
135        if ($res->{results}) {
136            foreach my $tweet (@{$res->{results}}) {
137                my $res = $bot->show_status($tweet->{id});
138                if ($res->{retweeted_status}) {
139                    $ids->{$tweet->{id}} = 'retweet';
140                }
141                else {
142                    $ids->{$tweet->{id}} = 'search';
143                }
144            }
145        }
146    };
147    if ($@) {
148        evalrescue($@);
149    }
150   
151    return $ids;
152}
153
154sub mentions_ids {
155    # return status_ids mentioned to me
156    #   param   => Net::Twitter::Lite object, since_id
157    #   ret     => HashRef of status_id (timeline order is destroyed)
158    #               or undef (none is found)
159   
160    my $bot      = shift @_;
161    my $since_id = shift @_ || 1;
162   
163    my $res;
164    eval {
165        $res = $bot->mentions(
166            {
167                since_id    => $since_id,
168            }
169        );
170    };
171    if ($@) {
172        evalrescue($@);
173    }
174   
175    my $ids;
176    if ($res && @{$res}) {
177        $ids = {
178            map { $_->{id} => 'mention' } @{$res}
179        };
180    }
181   
182    return $ids;
183}
184
185sub evalrescue {
186    # output error message at eval error
187   
188    use Scalar::Util qw(blessed);
189   
190    if (blessed $@ && $@->isa('Net::Twitter::Lite::Error')) {
191        warn $@->error;
192        if ($@->twitter_error) {
193            my %twitter_error = %{$@->twitter_error};
194            map {
195                $twitter_error{"$_ => "} = $twitter_error{$_} . "\n";
196                delete $twitter_error{$_}
197            } keys %twitter_error;
198            warn join("", %twitter_error);
199        }
200    }
201    else {
202        warn $@;
203    }
204}
Note: See TracBrowser for help on using the repository browser.