#!/usr/bin/perl use strict; use Net::Twitter; use Data::Dumper; use Cache::FileCache; use Date::Parse; use Time::HiRes qw(sleep); use JSON::Any; use Storable qw(retrieve nstore); my $wait = 0.5; my $last_request_time; my $user = "username"; my $pass = "password"; my $twit = Net::Twitter->new(username => $user, password => $pass); my $cache = new Cache::FileCache({namespace => 'twitter', cache_root => '.cache', default_expires_in => 3600 }); my %expires = ( user_timeline => 1800 ); sub followers { get_with_cache($twit, "followers", { cache_key => $user }); } sub following { get_with_cache($twit, "following", { cache_key => $user }); } sub user_timeline { my $id = shift; get_with_cache($twit, "user_timeline", { args => [{ id => $id }], cache_key => $id, }); } sub followers_timeline { my $active_fans = active_fans(); my @protected = grep { $_->{protected} } @$active_fans; my @public = grep { !$_->{protected} } @$active_fans; my @timelines; warn sprintf("protected user: %s\n", scalar @protected); =pod # can't get, twitter's bug? for (@protected) { my $id = $_->{id}; warn $id, $_->{screen_name}; my $res = user_timeline($id); warn $res; push @timelines, $res if (defined $res); sleep 1; } =cut warn sprintf("public user: %s\n", scalar @public); for (@public) { my $id = $_->{id}; my $res = user_timeline($id); push @timelines, $res if (defined $res); } my @mixed; my $now = time; push @mixed, @{$_} for (@timelines); my @recent = grep { str2time($_->{created_at}) > $now - 60 * 60 * 8 } @mixed; my @sorted = map { $_->[0] } sort { $b->[1] <=> $a->[1] } map { [$_, str2time($_->{created_at})] } @recent; return wantarray ? @sorted : \@sorted; } sub get_with_cache { my($twit, $method, $opt) = @_; $opt = $opt || {}; my $cache_key = $opt->{cache_key} || undef; my @args = defined $opt->{args} ? @{$opt->{args}} : (); my $key = $cache_key ? join("::", $method, $cache_key) : $method; # warn $key; my $expire = $expires{$method}; my $c = $cache->get($key); return $c if defined $c; # warn Dumper @args; sleep $wait if (time == $last_request_time); $last_request_time = time; my $result = $twit->$method(@args); # warn $result; return unless $result; $cache->set($key => $result, $expire); $result; } sub active_fans { my $friends = following(); my $followers = followers(); my $stored_friends = eval { retrieve("$user.friends") } || {}; # warn Dumper $stored_friends; my %watched = map { $_->{screen_name} => 1 } @$friends; %watched = ( %watched, %{$stored_friends} ); nstore \%watched, "$user.friends"; my @fans = grep { ! exists $watched{$_->{screen_name}} } @$followers; my @active_fans; my $now = time; for (@fans) { my $d = str2time $_->{status}->{created_at}; if($d > $now - 3600 * 8){ push @active_fans, $_; } } return wantarray ? @active_fans : \@active_fans; } # print scalar @$friend; # print Dumper @$fan; my @timeline = followers_timeline(); print JSON::Any->Dump(\@timeline);