Advertisement
Guest User

Untitled

a guest
Jul 29th, 2015
214
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.43 KB | None | 0 0
  1. #!/usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5. use utf8;
  6. use opts;
  7. use AnyEvent;
  8. use AnyEvent::Twitter;
  9. use Coro;
  10. use Coro::Channel;
  11. use Coro::Timer;
  12. use Data::Dumper;
  13. use Log::Dispatch;
  14.  
  15. opts
  16. my $debug => +{ isa => 'Bool', default => 0, required => 1 },
  17. my $log_file => +{ isa => 'Str' };
  18.  
  19. binmode STDOUT, ':encoding(utf8)';
  20. binmode STDERR, ':encoding(utf8)';
  21.  
  22. my $twitter = AnyEvent::Twitter->new(
  23. access_token => '',
  24. access_token_secret => '',
  25. consumer_key => '',
  26. consumer_secret => '',
  27. );
  28.  
  29. my $logger = Log::Dispatch->new(
  30. outputs => (
  31. $log_file
  32. ? [
  33. [
  34. FileShared => (
  35. callbacks => \&modify_message,
  36. filename => $log_file,
  37. min_level => +($debug ? 'debug' : 'info'),
  38. name => 'FileLogger',
  39. newline => 1,
  40. )
  41. ],
  42. ]
  43. : [
  44. [
  45. Screen => (
  46. callbacks => \&modify_message,
  47. min_level => +($debug ? 'debug' : 'info'),
  48. newline => 1,
  49. )
  50. ],
  51. ]
  52. ),
  53. );
  54.  
  55. my $unko_tweets = Coro::Channel->new;
  56.  
  57. async {
  58. my $since_id = 0;
  59. while ($since_id == 0) {
  60. my ($header, $res, $reason) = search_unko_tweets($twitter, 1, $since_id);
  61. unless ($header->{Status} eq '200' and $res->{max_id}) {
  62. $logger->warn(sprintf('[search] Failed to fetch results: %s.', $reason));
  63. sleep_thread(30);
  64. next;
  65. }
  66. $since_id = $res->{max_id};
  67. }
  68.  
  69. while (1) {
  70. $logger->debug(sprintf('[search] since_id = %d.', $since_id));
  71. my ($header, $res, $reason) = search_unko_tweets($twitter, 100, $since_id);
  72.  
  73. unless ($header->{Status} eq '200' and $res->{max_id}) {
  74. $logger->warn(sprintf('[search] Failed to fetch results: %s.', $reason));
  75. next;
  76. }
  77. $since_id = $res->{max_id};
  78. for my $tweet (grep { is_unko_tweet($_) } @{ $res->{results} }) {
  79. if ($tweet->{text}) {
  80. $unko_tweets->put($tweet);
  81. cede;
  82. } else {
  83. $logger->info(
  84. sprintf('[search] Empty hash returned from API: %s.', Dumper($tweet))
  85. );
  86. }
  87. }
  88. } continue {
  89. sleep_thread(30);
  90. }
  91. };
  92.  
  93. async {
  94. while (1) {
  95. my $tweet = $unko_tweets->get;
  96. async {
  97. my $orig_tweet_id = $tweet->{id_str};
  98. my $reply_text = create_reply_text($tweet);
  99. my $target = $tweet->{from_user};
  100.  
  101. $logger->info(
  102. sprintf(
  103. '[reply] Reply for %s (id = %s, text = "%s", tweeted at %s)'
  104. . ' is scheduled.',
  105. $target,
  106. $orig_tweet_id,
  107. $tweet->{text},
  108. $tweet->{created_at},
  109. )
  110. );
  111.  
  112. sleep_thread(10 * 60);
  113.  
  114. $twitter->post('statuses/update' => +{
  115. in_reply_to_status_id => $orig_tweet_id,
  116. status => $reply_text,
  117. }, Coro::rouse_cb);
  118. my ($header, $res, $reason) = Coro::rouse_wait;
  119. if ($header->{Status} eq '200') {
  120. $logger->info(sprintf('[reply] Replied to %s.', $target));
  121. } else {
  122. $logger->warn(
  123. sprintf(
  124. '[reply] Failed to reply to %s'
  125. . ' (in_reply_to_status_id = %s, text = "%s") : %s.',
  126. $target,
  127. $orig_tweet_id,
  128. $reply_text,
  129. $reason
  130. )
  131. );
  132. }
  133. };
  134. }
  135. };
  136.  
  137. AE::cv->recv; # Infinite loop.
  138.  
  139. sub create_reply_text {
  140. my $tweet = shift;
  141. my $tmpl = '@!user が "!tweet" とつぶやいてから10分経った。うんこは有意義だったか?';
  142. my $orig_tweet = $tweet->{text};
  143. my $text = create_reply_text1($tmpl, $tweet->{from_user}, $orig_tweet);
  144. if (length($text) > 140) {
  145. substr($orig_tweet, 140 - length($text) - 1) = '…';
  146. $text = create_reply_text1($tmpl, $tweet->{from_user}, $orig_tweet);
  147. }
  148. return $text;
  149. }
  150.  
  151. sub create_reply_text1 {
  152. my ($tmpl, $screen_name, $orig_tweet) = @_;
  153. $tmpl =~ s/!user/$screen_name/;
  154. $tmpl =~ s/!tweet/$orig_tweet/;
  155. return $tmpl;
  156. }
  157.  
  158. sub is_unko_tweet {
  159. my $tweet = shift;
  160. return if $tweet->{to_user};
  161. return if $tweet->{text} =~ /\bRT\b/;
  162. 1;
  163. }
  164.  
  165. sub modify_message {
  166. my %args = @_;
  167. sprintf('[%d][%s]%s', time, $args{level}, $args{message});
  168. }
  169.  
  170. sub search_unko_tweets {
  171. my ($twitter, $rpp, $since_id) = @_;
  172. $twitter->get(
  173. search => +{
  174. locale => 'ja',
  175. q => 'うんこなう',
  176. result_type => 'recent',
  177. rpp => $rpp,
  178. since_id => $since_id,
  179. },
  180. Coro::rouse_cb
  181. );
  182. Coro::rouse_wait;
  183. }
  184.  
  185. sub sleep_thread {
  186. my $sec = shift;
  187. my $timeout = Coro::Timer::timeout($sec);
  188. schedule until $timeout;
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement