Created
October 14, 2014 11:10
-
-
Save maugsburger/f929be60fe6490e244bd to your computer and use it in GitHub Desktop.
print twitter follower and friends
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use warnings; | |
use strict; | |
use v5.10; | |
use Data::Dumper; | |
use Net::Twitter::Lite::WithAPIv1_1; | |
use Net::Twitter::Lite::Error; | |
use Storable qw/lock_retrieve lock_store/; | |
use Log::Log4perl qw/:easy/; | |
use Getopt::Long; | |
use Pod::Usage; | |
Log::Log4perl->easy_init($INFO); | |
my $logger = Log::Log4perl->get_logger(); | |
$| = 1; # autoflush | |
# ARGS | |
my %opts; | |
GetOptions( \%opts, | |
'oauthkey:s', | |
'oauthsecret:s', | |
'verbose+', | |
'help', | |
'man', | |
'export:s', | |
) or pod2usage(1); | |
pod2usage(1) if $opts{help}; | |
pod2usage(-exitval => 0, -verbose => 2) if $opts{man}; | |
$logger->more_logging($opts{verbose}) if defined $opts{verbose}; | |
$logger->debug( sub { Data::Dumper->Dump( [\%opts], ['cli_arguments']); }); | |
# READ OLD DATA, IF AVAILABLE | |
my $datafile = shift @ARGV || pod2usage(-message=>'Filename missing', -exitval =>2); | |
my $data; | |
if ( -f $datafile ) { | |
$data = lock_retrieve($datafile) || $logger->logdie("coultn't read file ", $datafile); | |
} | |
$data->{oauthkey} = $opts{oauthkey} if defined $opts{oauthkey}; | |
$data->{oauthsecret} = $opts{oauthsecret} if defined $opts{oauthsecret}; | |
pod2usage(-message=>'oauthkey missing', -exitval =>1) unless defined $data->{oauthkey}; | |
pod2usage(-message=>'oauthsecret missing', -exitval =>1) unless defined $data->{oauthsecret}; | |
# OAUTH, IF NEEDED | |
our $nt = Net::Twitter::Lite::WithAPIv1_1->new( | |
consumer_key => $data->{oauthkey}, | |
consumer_secret => $data->{oauthsecret}, | |
ssl => 1 | |
); | |
# You'll save the token and secret in cookie, config file or session database | |
if ( $data->{access_token} && $data->{access_token_secret} ) { | |
$nt->access_token($data->{access_token}); | |
$nt->access_token_secret($data->{access_token_secret}); | |
} | |
unless ( $nt->authorized ) { | |
# The client is not yet authorized: Do it now | |
print "Authorize this app at ", $nt->get_authorization_url, " and enter the PIN\n#"; | |
my $pin = <STDIN>; # wait for input | |
chomp $pin; | |
my($access_token, $access_token_secret, $user_id, $screen_name) = | |
$nt->request_access_token(verifier => $pin); | |
$data->{access_token} = $access_token; | |
$data->{access_token_secret} = $access_token_secret; | |
$data->{user_id} = $user_id; | |
} | |
$logger->debug( sub { Data::Dumper->Dump( [$data], ['data']); }); | |
if (lock_store($data, $datafile)) { | |
$logger->debug("datafile written"); | |
} else { | |
$logger->warn('error writing datafile, retry next round'); | |
} | |
# Everything's ready | |
# CONNECT TO TWITTER | |
#my $nt = Net::Twitter::Lite->new( | |
#); | |
warn "$@\n" if $@; | |
# start export if wanted | |
if (defined $opts{export}) { | |
open EXPORT, '>>', $opts{export} || $logger->logdie("couldn't open #$opts{export}'"); | |
seek ( EXPORT, 0, 2 ) || $logger->logdie("couldn't seek to end of '$opts{export}'"); | |
$logger->info("logging tweets to '", $opts{export}, "'"); | |
} | |
my $r; | |
eval { $r = $nt->friends_ids }; | |
$logger->debug( sub { Data::Dumper->Dump( [$r], ['friends_ids']); }); | |
if ( $@ && $@->isa('Net::Twitter::Lite::Error' ) ) { | |
$logger->warn('Follower error: ', $@->error); | |
} elsif ( @{$r->{ids}} > 0 ) { | |
my %list = ids_to_usernames(@{$r->{ids}}); | |
my $c = keys %list; | |
say "FRIENDS ($c):"; | |
foreach my $id (sort {$a <=> $b} keys %list) { | |
printf "%12s %s\n", $id, $list{$id}; | |
} | |
} | |
print "\n"; | |
eval { $r = $nt->followers_ids }; | |
$logger->debug( sub { Data::Dumper->Dump( [$r], ['followers_ids']); }); | |
if ( $@ && $@->isa('Net::Twitter::Lite::Error' ) ) { | |
$logger->warn('Follower error: ', $@->error); | |
} elsif ( @{$r->{ids}} > 0 ) { | |
my %list = ids_to_usernames(@{$r->{ids}}); | |
my $c = keys %list; | |
say "FOLLOWER ($c):"; | |
foreach my $id (sort {$a <=> $b} keys %list) { | |
printf "%12s %s\n", $id, $list{$id}; | |
} | |
} | |
sub ids_to_usernames { | |
our $nt; | |
my @ids = @_; | |
my %map; | |
# api only allows chunks of 100 | |
while( my @u = splice(@ids, 0, 100 ) ) { | |
my $l; | |
eval { $l = $nt->lookup_users({ user_id => \@u }) }; | |
if ( $@ && $@->isa('Net::Twitter::Lite::Error' ) ) { | |
$logger->warn('Follower name error: ', $@->error); | |
} else { | |
foreach( @{$l} ) { | |
$map{$_->{id}} = $_->{screen_name}; | |
} | |
} | |
} | |
return %map; | |
} | |
__END__ | |
=head1 NAME | |
fdump - print twitter follower and friends | |
=head1 SYNOPSIS | |
fdump.pl [options] file | |
Options: | |
--oauthkey | |
--oauthsecret | |
--verbose | |
--help | |
--man | |
=head1 OPTIONS | |
=over 8 | |
=item B<--oauthkey=key> | |
Supply OAuth key, required at first run | |
=item B<--oauthsecret=secret> | |
Supply OAuth secret, required at first run | |
=item B<--verbose> | |
Increment log level (multiple times) | |
=item B<help> | |
Show brief usage hints | |
=item B<man> | |
Show manpage | |
=item B<file> | |
File settings will be saved to | |
=back | |
=head1 DESCRIPTION | |
B<This program> will read the given input file(s) and do something | |
useful with the contents thereof. | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment