summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2015-12-19 11:48:23 +0000
committerdakkar <dakkar@thenautilus.net>2015-12-19 11:48:23 +0000
commit6c4329d4e4ff25e5afc220bb348323ef312560fc (patch)
treebc76153cb6adbfc1fbf6858b8bdeb0b47808479b
downloadtwitlist-6c4329d4e4ff25e5afc220bb348323ef312560fc.tar.gz
twitlist-6c4329d4e4ff25e5afc220bb348323ef312560fc.tar.bz2
twitlist-6c4329d4e4ff25e5afc220bb348323ef312560fc.zip
first stab
-rw-r--r--twitlist.pl165
1 files changed, 165 insertions, 0 deletions
diff --git a/twitlist.pl b/twitlist.pl
new file mode 100644
index 0000000..57774a3
--- /dev/null
+++ b/twitlist.pl
@@ -0,0 +1,165 @@
+#!perl
+use strict;
+use warnings;
+use 5.020;
+use experimental 'postderef';
+use Net::Twitter;
+use Path::Tiny;
+use JSON;
+use Try::Tiny;
+use Safe::Isa;
+use open ':std',':locale';
+
+use Data::Printer;
+
+sub get_twitter {
+ my $config_file = $0 =~ s{\.[^.]+$}{.json}r;
+ my $conf = decode_json(path($config_file)->slurp_raw);
+ return Net::Twitter->new(traits=>[
+ 'API::RESTv1_1',
+ 'AutoCursor',
+ 'AutoCursor' => {
+ max_calls => 15,
+ force_cursor => 1,
+ array_accessor => 'users',
+ methods => [qw(friends followers)],
+ },
+ ],%$conf);
+}
+
+sub fetch_lists_info {
+ my ($tw) = @_;
+
+ my $lists = $tw->list_ownerships({
+ count => 200,
+ });
+ my %lists_info = map {
+ $_->{id} => {
+ name => $_->{name},
+ },
+ } $lists->{lists}->@*;
+
+ for my $list_id (sort keys %lists_info) {
+ my $members = $tw->list_members({
+ list_id => $list_id,
+ count => 2000,
+ skip_status => 1,
+ include_entities => 0,
+ });
+ $lists_info{$list_id}->{members}={
+ map { $_->{id} => 1 } $members->{users}->@*,
+ };
+ }
+ return \%lists_info;
+}
+
+sub fetch_friends_info {
+ my ($tw) = @_;
+
+ my $friends = $tw->friends({
+ count => 200,
+ skip_status => 1,
+ include_user_entities => 0,
+ });
+
+ my %friends_info = map {
+ $_->{id} => { name => $_->{name} }
+ } $friends->@*;
+
+ return \%friends_info;
+}
+
+sub cache_file { $0 =~ s{\.[^.]+$}{-cache.json}r };
+
+sub load_info {
+ return try { decode_json(path(cache_file)->slurp_raw) };
+}
+
+sub save_info {
+ path(cache_file)->spew_raw(encode_json({
+ lists=>$_[0],
+ friends=>$_[1],
+ }));
+ return;
+}
+
+sub to_list {
+ sort {
+ $a->{name} cmp $b->{name}
+ } map {
+ { id => $_, $_[0]->{$_}->%* }
+ } keys $_[0]->%*
+}
+
+sub set_display_name {
+ my $max=0;
+ for my $e ($_[0]->@*) {
+ $e->{dn} = sprintf '%s (%d)',$e->@{qw(name id)};
+ my $l = length($e->{dn});
+ $max = $l if $max<$l;
+ }
+ return $max;
+}
+
+sub print_friends_lists_matrix {
+ my ($li,$fi) = @_;
+
+ my @lists = to_list($li);
+ my $list_width = set_display_name(\@lists);
+ my @friends = to_list($fi);
+ my $friend_width = set_display_name(\@friends);
+
+ print ' ' x ($friend_width+1);
+ for my $l (@lists) {
+ print $l->{dn},' ';
+ }
+ print "\n";
+
+ for my $f (@friends) {
+ printf '%-*s ',$friend_width,$f->{dn};
+ for my $l (@lists) {
+ printf '%-*s ',
+ length($l->{dn}),
+ ( $l->{members}->{$f->{id}}
+ ? '*' : '_' );
+ }
+ print "\n";
+ }
+}
+
+sub parse_friends_lists_matrix {
+ my ($fn) = @_;
+
+ my @lines = path($fn)->lines_utf8;
+ my @list_ids = $lines[0] =~ m{\((\d+)\)}g;
+ shift @lines;
+
+ my %lists;
+ for my $l (@lines) {
+ $l =~ s{\A.*?\((\d+)\)\s+}{} or next;
+ my $friend_id = $1;
+
+ }
+}
+
+my $tw = get_twitter;
+try {
+ my $lists_info;
+ my $friends_info;
+ my $info = load_info();
+ if ($info) {
+ ($lists_info,$friends_info) = $info->@{qw(lists friends)},
+ }
+ else {
+ $lists_info = fetch_lists_info($tw);
+ $friends_info = fetch_friends_info($tw);
+ save_info($lists_info,$friends_info);
+ }
+ print_friends_lists_matrix($lists_info,$friends_info);
+} catch {
+ if ($_->$_isa('Net::Twitter::Error')) {
+ my $limit = $tw->rate_limit_status;
+ p $limit;
+ }
+ else { local $@=$_;die }
+};