Good Game Auto Blocker

ggautoblocker.pl 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #!/usr/bin/perl -w
  2. use strict;
  3. use Net::Twitter;
  4. # Needs read/write access!
  5. my $consumer_key = "";
  6. my $consumer_secret = "";
  7. my $access_token = "";
  8. my $access_secret = "";
  9. my $sourcelist_file = "sourcelist.txt";
  10. my $whitelist_file = "whitelist.txt";
  11. my $debug = 1;
  12. my ( @whitelist, @idiots );
  13. my %problem;
  14. my ( @follower_ids, @myfollower_ids, @sheeple_ids );
  15. # set up our twitter connection
  16. my $nt = Net::Twitter->new(
  17. traits => [qw/API::RESTv1_1/],
  18. ssl => 1,
  19. consumer_key => $consumer_key,
  20. consumer_secret => $consumer_secret,
  21. access_token => $access_token,
  22. access_token_secret => $access_secret
  23. );
  24. # check our rate limits.
  25. # this would probably be better off stored in a hash whose values are monitored by
  26. # this program so we didn't have to make this call so often, but whatever.
  27. sub get_rate_limit {
  28. my $type = shift;
  29. my $m = $nt->rate_limit_status;
  30. if ( $m->{'resources'}->{'application'}->{'/application/rate_limit_status'}->{'remaining'} == 0 ) {
  31. print " -- API limit reached, waiting for ". ( $m->{'resources'}->{'application'}->{'/application/rate_limit_status'}->{'reset'} - time ) . " seconds --\n" if $debug;
  32. sleep ( $m->{'resources'}->{'application'}->{'/application/rate_limit_status'}->{'reset'} - time + 1 );
  33. }
  34. if ( $type =~ /followers/ ) {
  35. return {
  36. remaining => $m->{'resources'}->{'followers'}->{'/followers/ids'}->{'remaining'},
  37. reset => $m->{'resources'}->{'followers'}->{'/followers/ids'}->{'reset'}
  38. };
  39. } elsif ( $type =~ /lookup_users/ ) {
  40. return {
  41. remaining => $m->{'resources'}->{'users'}->{'/users/lookup'}->{'remaining'},
  42. reset => $m->{'resources'}->{'users'}->{'/users/lookup'}->{'reset'}
  43. };
  44. }
  45. }
  46. # sleep until the reset is happy again.
  47. sub wait_for_rate_limit {
  48. my $type = shift;
  49. my $limit = get_rate_limit($type);
  50. if ( $limit->{'remaining'} == 0 ) {
  51. print " -- API limit reached, waiting for ". ( $limit->{'reset'} - time ) . " seconds --\n" if $debug;
  52. sleep ( $limit->{'reset'} - time + 1 );
  53. }
  54. }
  55. # get a list of followers
  56. sub get_followers {
  57. my $screen_name = shift;
  58. my @followers;
  59. for ( my $cursor = -1, my $r; $cursor; $cursor = $r->{next_cursor} ) {
  60. wait_for_rate_limit('followers');
  61. if ( $screen_name ) {
  62. $r = $nt->followers_ids({ screen_name => $screen_name, cursor => $cursor });
  63. } else {
  64. $r = $nt->followers_ids({ cursor => $cursor });
  65. }
  66. push @followers, @{$r->{ids}};
  67. }
  68. return @followers;
  69. }
  70. # get screen_names to go along with the account ids.
  71. sub get_screen_names {
  72. my $sheeple = shift;
  73. my @ids = keys %$sheeple;
  74. my @names;
  75. while ( $#ids > 0 ) {
  76. wait_for_rate_limit('lookup_users');
  77. my @subset_ids = splice @ids, 0, 100;
  78. my $users = $nt->lookup_users( { user_id => \@subset_ids } );
  79. foreach my $user ( @{$users} ) {
  80. $sheeple->{$user->{'id'}}->{'name'} = $user->{'screen_name'};
  81. }
  82. }
  83. }
  84. # is username in whitelist?
  85. sub is_whitelisted {
  86. my $sheep = shift;
  87. return 0 unless $sheep;
  88. if ( @whitelist ) {
  89. foreach my $notasheep ( @whitelist ) {
  90. return 1 if $notasheep =~ $sheep;
  91. }
  92. }
  93. return 0;
  94. }
  95. # get a list of whitelisted users
  96. open W, '<', $whitelist_file or die "Can't open $whitelist_file: $!\n";
  97. foreach ( <W> ) {
  98. chomp;
  99. push @whitelist, $_;
  100. }
  101. close W;
  102. # get a list of idiots
  103. open B, '<', $sourcelist_file or die "Can't open $sourcelist_file: $!\n";
  104. foreach ( <B> ) {
  105. chomp;
  106. push @idiots, $_;
  107. }
  108. close B;
  109. print "This is going to take a while, because API limits are dumb.\n\n";
  110. $| = 1;
  111. # first, get a list of the IDs of all the problem children.
  112. foreach my $idiot ( @idiots ) {
  113. print "Examining follower list for $idiot.\n";
  114. push @follower_ids, get_followers( $idiot );
  115. }
  116. # get a list of our personal followers
  117. print "Getting a list of my followers for comparison.\n";
  118. @myfollower_ids = get_followers;
  119. # get a list of unique IDs.
  120. print "Examining follower lists...\n";
  121. # if the sheeple is following us, don't put it in the main array. put it in
  122. # a separate data structure. This is to keep ourselves from doing excessive
  123. # API calls later when we're checking usernames.
  124. foreach my $id (@follower_ids) {
  125. if ( exists $problem{$id} ) {
  126. $problem{$id}->{'count'}++;
  127. } else {
  128. $problem{$id}->{'count'} = 1;
  129. # does this id exist in our followers?
  130. foreach my $my_id ( @myfollower_ids ) {
  131. if ( $my_id == $id ) {
  132. $problem{$id}->{'stalker'} = 1;
  133. }
  134. }
  135. }
  136. }
  137. # print out some stats
  138. # BUG! these numbers aren't accurate. plzfix.
  139. @sheeple_ids = keys %problem;
  140. print "> $#follower_ids users following idiots.\n";
  141. print "> $#sheeple_ids users following multiple accounts.\n";
  142. # save ids to file if we're debugging
  143. if ( $debug ) {
  144. print "Saving list of IDs to block_ids.txt.\n";
  145. open BL, '>block_ids.txt' or die "Can't open block_ids.txt: $!\n";
  146. foreach my $monster ( keys %problem ) {
  147. if ( $problem{$monster}->{'count'} == 1 ) {
  148. delete $problem{$monster};
  149. } else {
  150. print BL "$monster\n";
  151. }
  152. }
  153. close BL;
  154. }
  155. # turn IDs into usernames.
  156. print "Getting list of usernames from IDs.\n";
  157. get_screen_names(\%problem);
  158. # save to a file, but only if they aren't part of the whitelist.
  159. print "Saving list of usernames to block_names.txt & shared_names.txt\n";
  160. open BL, '>block_names.txt' or die "Can't open block_names.txt: $!\n";
  161. open SL, '>shared_names.txt' or die "Can't open shared_names.txt: $!\n";
  162. foreach my $sheep ( keys %problem ) {
  163. next if is_whitelisted( $problem{$sheep}->{'name'} );
  164. next unless exists $problem{$sheep}->{'name'};
  165. next unless exists $problem{$sheep}->{'count'};
  166. print BL $problem{$sheep}->{'name'}."\n";
  167. if ( exists $problem{$sheep}->{'stalker'} ) {
  168. print SL $problem{$sheep}->{'name'}."\n";
  169. }
  170. }
  171. close BL;
  172. close SL;
  173. # TODO: actually block the user!
  174. # $nt->create_block( { user_id => $id } )
  175. # TODO: do we want to look at account stats for these users? maybe limit by f:f ratio/acct creation date?
  176. # otherwise users like hootsuite are going to get blocked.