use Net::Twitter::Lite;
use FindBin qw($Bin);
use YAML::Tiny;
+use Date::Parse qw(str2time);
+
+my $_execmode = $ARGV[0] || 0;
+sub VERBOSE () { $_execmode eq 'verbose' };
+sub DEBUG () { VERBOSE or $_execmode eq 'debug' };
+use Data::Dumper;
+
+DEBUG and warn "$0: debug mode";
my $conf = loadconf("$Bin/config.yml");
if (! defined $conf) {
}
my $stat = loadconf("$Bin/status.yml");
if (! defined $stat) {
- $stat = {
- # do not set to 0
- since_id => 1,
- };
+ $stat = {};
}
my $bot = login($conf);
die "$0: this client is not yet authorized.\n";
}
-my %tweets;
-my $tweet;
+my $tweets = {};
+%$tweets = (
+ %$tweets,
+ %{ or_search($bot, $conf->{hashtag}, $stat->{search}) }
+);
+%$tweets = (
+ %$tweets,
+ %{ mentions_ids($bot, $stat->{mention}) }
+);
-$tweet = or_search($bot, $conf->{hashtag}, $stat->{since_id});
-if ($tweet) {
- %tweets = (%tweets, %$tweet);
-}
-
-$tweet = mentions_ids($bot, $stat->{since_id});
-if ($tweet) {
- %tweets = (%tweets, %$tweet);
-}
-
-foreach my $id (sort keys %tweets) {
- if ($tweets{$id} eq 'retweet') {
+foreach my $id (sort keys %$tweets) {
+ # $tweets->{$id}{type} eq 'search' => found by search API
+ # eq 'mention' => found by mention API
+ if ($tweets->{$id}{type} eq 'retweet') {
next;
}
- sleep($conf->{sleep});
- # retweet found tweet
- # $tweets->{$id} eq 'search' => found by search API
- # eq 'mention' => found by mention API
+ DEBUG or sleep($conf->{sleep});
+
+ # do retweet found tweets
my $res;
eval {
- $res = $bot->retweet($id);
+ DEBUG or $res = $bot->retweet($id);
+ DEBUG and warn "retweet($id) => ", Dumper($tweets->{$id});
};
if ($@) {
evalrescue($@);
next;
}
- $stat->{since_id} = $id;
+ $stat->{$tweets->{$id}{type}} = $id;
}
-if (%tweets) {
+foreach my $word (keys %{$conf->{response}}) {
+ # reply to follower's tweets containing keywords
+ $tweets = follower_search($bot, $word);
+ foreach my $id (sort keys %$tweets) {
+ if ($tweets->{$id}{type} eq 'retweet') {
+ next;
+ }
+ DEBUG or sleep($conf->{sleep});
+
+ my $text = '@' . $tweets->{$id}{screen_name}
+ . " " . $conf->{response}{$word};
+ my $res;
+ eval {
+ DEBUG or $res = $bot->update(
+ {
+ in_reply_to_status_id => $id,
+ status => $text,
+ }
+ );
+ DEBUG and warn "update(", $text, ") => ",
+ Dumper($tweets->{$id});
+ };
+ if ($@) {
+ evalrescue($@);
+ }
+ }
+}
+
+if ($tweets) {
# save last status to yaml file
- YAML::Tiny::DumpFile("$Bin/status.yml", $stat);
+ DEBUG or YAML::Tiny::DumpFile("$Bin/status.yml", $stat);
+ DEBUG and warn "status.yml => ", Dumper($stat);
}
my $bot = shift @_;
my $keywords = shift @_;
- my $since_id = shift @_;
+ my $since_id = shift @_ || 1;
my $key = "";
foreach my $word (@$keywords) {
$key = $word;
}
}
+ DEBUG and warn "searching '$key'";
my $res;
my $ids = {};
}
);
}
+ VERBOSE and warn Dumper($res);
if ($res->{results}) {
foreach my $tweet (@{$res->{results}}) {
my $res = $bot->show_status($tweet->{id});
+ VERBOSE and warn Dumper($res);
+
+ my $id = {
+ date => str2time($res->{created_at}),
+ screen_name => $res->{user}{screen_name},
+ status_id => $res->{id},
+ text => $res->{text},
+ user_id => $res->{user}{id},
+ };
if ($res->{retweeted_status}) {
- $ids->{$tweet->{id}} = 'retweet';
+ $id->{retweet_of} = $res->{retweeted_status}{id};
+ $id->{type} = 'retweet';
}
else {
- $ids->{$tweet->{id}} = 'search';
+ $id->{type} = 'search';
}
+ $ids->{$tweet->{id}} = $id;
}
}
};
evalrescue($@);
}
+ DEBUG and warn "search result => ", Dumper($ids);
return $ids;
}
# or undef (none is found)
my $bot = shift @_;
- my $since_id = shift @_;
+ my $since_id = shift @_ || 1;
my $res;
eval {
since_id => $since_id,
}
);
+ VERBOSE and warn Dumper($res);
};
if ($@) {
evalrescue($@);
}
- my $ids;
+ my $ids = {};
if ($res && @{$res}) {
$ids = {
- map { $_->{id} => 'mention' } @{$res}
+ map {
+ $_->{id} => {
+ date => str2time($_->{created_at}),
+ screen_name => $_->{user}{screen_name},
+ status_id => $_->{id},
+ text => $_->{text},
+ type => 'mention',
+ user_id => $_->{user}{id},
+ }
+ } @{$res}
};
}
+ DEBUG and warn "mentions result => ", Dumper($ids);
+ return $ids;
+}
+
+sub follower_search {
+ # search follower's tweets containing keywords
+ # param => Net::Twitter::Lite object, keyword string, since_id
+ # ret => HashRef of status_id (timeline order is destroyed)
+ # or undef (none is found)
+
+ my $bot = shift @_;
+ my $keyword = shift @_;
+ my $since_id = shift @_ || 1;
+
+ my $tweets = or_search($bot, [ $keyword ], $since_id);
+ if (! $tweets) {
+ return {};
+ }
+
+ my $followers;
+ eval {
+ $followers = $bot->followers_ids();
+ VERBOSE and warn Dumper($followers);
+ };
+ if ($@) {
+ evalrescue($@);
+ }
+
+ my $ids = {};
+ foreach my $status_id (keys %$tweets) {
+ foreach my $user_id (@$followers) {
+ if ($tweets->{$status_id}{user_id} == $user_id) {
+ $ids->{$status_id} = $tweets->{$status_id};
+ last;
+ }
+ }
+ }
+
+ DEBUG and warn "search result in followers => ", Dumper($ids);
return $ids;
}