source: lab.git/twitterbot.pl @ aa0e8a6

twitter-0.1twitter-0.1@65twitter-0.1@66
Last change on this file since aa0e8a6 was aa0e8a6, checked in by mitty <mitty@…>, 14 years ago
  • fix typo

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

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