Skip to content

Instantly share code, notes, and snippets.

@erikh
Created February 22, 2010 09:15
Show Gist options
  • Save erikh/310954 to your computer and use it in GitHub Desktop.
Save erikh/310954 to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
#
# a commentary on twitter. problem?
#
# MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLLLLLPLDQDDDDDDDDDDDDDDDDDDDDDDDDQQDLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMMMMMMEH^xxxxxxx#///////////////////////////\xxxxx&@@@@@@39999LMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMMMQ&:/:^p9999999MMMMMMMMMzJ7JJJJJJJJJJJ9JJWW999E@@@@@@& xxxx///: dppJzPMMMMMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMJ&##&NPLMMMMMMMMMMDQJ7939EPDLPPLLLLLPPPPPPPz9999W7999997NNNNd3ppp^ \x\\ HELMMMMMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMML3#[&zMMMMMMMMMMLDN3NQJQPDLQ999NN99999997W97QPLPPPPLLLLLLPLPPDLLLLL999WJE3^\[x&NPLMMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMzx/\NMMMMMMMMMM93W7DMJ93WJ7JJLMMMMMMMMMMMMMMLJJJJJJJJJJJJJJJJE7JJJJJQMM97QMMLN&:/:^QMMMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMp[[^MMMMMMMMMzJ9QMQJE3ED9EEW99399999999p_HJMMMMMMMMMMMMMMMQJJJJ7JJJJ9ELMMMMMMMMMMJd#[^EMMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMM7[[HMMMMMMLEN9DLPN37QEN37DPLMMMMMMMMMMMMLJdEMMMMMMMMMMMMM399LLPLPLLLPPQNW7JLMMMMMMMMD&[#EMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMMz\/^LMMMMMMD9LMP7HJD7HJDMMMMMMMMMMMMMMMMMMMP@MMMMMMMMMMMMMMQHDMMMMMMMMMMMMQ9dLMMMMMMMML\/pMMMMMMMMMMMM
# MMMMMMMMMMMMMMMMMQ\/ LMMMMMMMMMMD3JMWHEMMMMMMML99EE999LMMMMMMM@MMMMMMMMMMMMMM@DMMMMMMMMMMMMMMMN7MMMMMMMMM:/&MMMMMMMMMMMM
# MMMMMMMMMMMMMMMM7#/ MMMMMMMMMMMMMMMMQMMDz3 \//[/////#[//\ H9MMMMMMMMMMMMMMMMM@MMMMMMMMMMMMMMMMLDMMMMMMMMM3/[EMMMMMMMMMMM
# MMMMMMMMMMMMMQH [:3LMMMMMMMMMMMMMMMMMQd\\:\/////////dDQ9p^:[\dzLMMMMMMMMMMMMMWMQ9d@ \::\\\\\pELMMMMMMMMMML@##dELMMMMMMMM
# MMMMMMMMMMMD@\###@NNNNNNPLLMMMEWNd9Dz:/:_@x[////////HpWQPMD9^##xPMMMMMMMLPLMLJ^://[[/# x//[&MzNQPDLLLLPDJ^\[x&DMMMMMM
# MMMMMMMMMPd#/^_HJ7JzzzJJzJLMMMQNJ9NDz^#//x @ppppppp& x//x&N9Dx/[WMMMMMMM^x @^[////////[ 3EMJJJJ7JJJJEHpMLW\[ QMMMMM
# MMMMMMMMp[[^E&7MMMzp [//[////^WzJDPMMMMMMMMMMLW\[pMMMML9@xx//#_WMMMMMMMMDN&x//:^39PMMMMMMMMMMMMMMMMMMMMMN99E3W9M /#zMMMM
# MMMMMMD&[#373DMMD&## 3JQDzEQd \##\^W9QQQQQE3 \[x9LMMMMMMMPP99DMMMMMMMMMMMMML//7LMMMMMMMMMMMMMMMP9d@@@@@@9zD37Lz3P\/pMMMM
# MMMMML^/xJM@MMMP:/xJMMMMM^:9MLQ99dx:#xxxxx## HELMMMMMMMMMMMMMMMMMMMMMMMMMMMM//7MMMMMMMMMd_JQPJ_x[\^@@@&##xzM@MLWW:/pMMMM
# MMMMM9//JMM@MMPx[:DMMMMME#[x3JMMMMMMJJJJJJJPMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM:/xp9LMMMMMM@[//x[/[^LL9MMMD7NLL^PMM@\/pMMMM
# MMMMM9[/MMM@MMQ//QMMMLEp:/x \/x pELMMMMMMMMMMMMMMMMMMME9PW_ zMMMMMMMMMMMMM7 x/#3JMMMMMML9999EMM /@MMMMMMMdQM@z:/pMMMM
# MMMMME[[7MM@MMQ//9L^:\#://WLDJ3 \#\ 3EQLMMMMMD7999999NWz\[x@ppWLMMMMMMMMMMMMMMLPW[[#:HLMMMMMMMMMMM / ELMMDEHELP^7#[NMMMM
# MMMMML /_LM7pML^/:zJ99EQ [:JMMMMQEH ##:x&3JQPPLMMMMMMMMM//7LM3 dpQMMMMMMMMML@[##/xHNPPPMMMMMME#[/[9MMDJQPQHH#[&LMMMM
# MMMMMMW/[dPM^PMD:/ MMMMMJ#/\9LMMMMMMP\/: [//x @@9zMMMMMM:/:^M [@pp_ 7MMMMMMMME /#7DpzMDJ933zMMMWx/:// MDNW77E9x/xLMMMMM
# MMMMMMMQ /#zDH77DEPMMMMMDd\/[/xd7QMMM\/@MML9W@&x\/// _ppJ9HWMMMMMMMMMMMM9[xp@x/\3LMMMMMMMMMMP93\/\[: /#zDLMMM7#/@LMMMMMM
# MMMMMMMML^[#3EJD7N7MMMMMMMzx//\x[#x@9 /[3DMMMMMLPDzpdx/[#\: @H99JQQDMMMML3 _WPMMMMMMPDQEH \#[[ z:/:[[pMMMLE#[_LMMMMMMM
# MMMMMMMMML9 [[xW3LMMMMMMMMMP [\37N&:#[[//:3QQDPMMMLMM /#99H@ ::#\xx: _pppppppp3 xx:[# 3EH/#D9[/[[pMMMM^/:PMMMMMMMM
# MMMMMMMMMMMM7x/\3LMMMMMMMMMMMp#/@LMMJ\///////[x@3zMMD#/pMMMMMMMDzJJ /:pp@ [/: ppp9[/3MMMQ//QL^///pMMMM//WMMMMMMMMM
# MMMMMMMMMMMMMME [#7MMMMMMMMMMME /#7MM9//DN&x////[//:x/#7DMMMMMMMMMM@/ MMMMMMM&[/MMMMMMMM&/[7MMd[/& ////pMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMML_[#EMMMMMMMMMMMLd\# 9_[#MMMPQJ3 ::\/[/[##\\ @799999 /x9999999H//99999N@@_[[_\:[////////pMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMLx/:PMMMMMMMMMMMMQd#/[ EMMMMMMMMQQQ /\x:#[/////////////////////////////////////////////pMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMD:/xPMMMMMMMMMMMMMD@[[x3LMMMMMMMMM@/ MMJ93 [///////////////////////////////////[/[:[#zMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMMP /#3DMMMMMMMMMMMMMP7 [/ pDMMMML&[#pMMMMMMMMMz9#/x^x://[/////////////[//////:^//#N//&MMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMMMLE:/ 3DMMMMMMMMMMMMMLD3 ##xNzPp[/EMMMMMMMMMMMM:/pLPPQQQQQ&/[dpppp@[[^pN7\/xz@/#3x[xDMMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMQH [:3PMP9DLLMQ7DDLMMLJWx#\x[/^DLLMMMMMMMMMM\/pMMMMMMML#/&MMMML^/\DMQ /xzL :x /xzMMMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMM9 [\@EQ77W7MPz7Ep9PMMMQ7@ #/#x_@39PMMMMME#[pMMMMMMLQ//9MMML@/#7MM@//Wd@ \/xdDMMMMMMM//9MMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMMP&///xdJLz3W7EPMP3W9ELMMMMM9d@ x[//[/x [[ pppppppx/#dppdx//# \///[#x_@pzMMMMMMMMMM\/ MMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMMP&[#7W_:#\_WzDD737QzzQ73NJzDMMMLPDQDQJpppp3 ^ppppp9QQQDPLMMLzMMMMMMMMM3/#DMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMMDx[\7MMLQ9dx#\ HEPzQQN39LzJz9939zDPLMMMMMMMMLPLLLLLLLLLLLLLLPPLMMMMMMMMMLJH9MMMMWMMMMD#/pMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMMp#/:DMMMMMMMLJp^#/x @WQMQJNW7W9LLJN9N39JMMMMLJJJJJJJJJJJJJJJJzJQMMMMMMME3WNLMMMMM@MMMMM\/pMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMM@///x@7QMMMMMMMML9p@ #//x@7QMMD99p9EJJ9HHWW79999999999WJJJJJJJJJJJJW9p9zMMMMMMJpWpMMMMM\/pMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMML //H_x\#^WQLMMMMMMMMLDQW_x\#x@9QLMMLPLPPD799399QQDDQQDJJJJQLLLLLLLLLMMMMMMQJNpJPMMMMMML\/pMMMMMMMM
# MMMMMMMMMMMMMMMMMMMMMJ[[/JQJ7^#/: 3QQDDDDQDDQLMPzN&\#\ @9DLMMMMMMMMMMDQQQDDDDDQQN9999999999999997JDMMMMMMMML&[#EMMMMMMMM
# MMMMMMMMMMMMMMMMMMz9@ [//\////////////////_x/xNDMMMMJW_\/#x@9LMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMP /#7MMMMMMMMM
# MMMMMMMMMMMMMLE&://\x ///HEMMMMMMME [#^9MMMMWx//7LMMMMMMDN&x//#\/# @pEJPMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM9H#[^PMMMMMMMMMM
# MMMMMMMMMMLJ \#:&NQDL9/// PMMMMMMMMLEH:[:dzPMPW#[HLMMMMMMMMLQJpppp_ \x\\::^@99EDDMMMMMMMMMMMMMMMMMMDz9d\[:^ELMMMMMMMMMMM
# MMMMMMMMD3 #\dEDMMMMM9//#/ PMMMMMMMMMMD9 \\x7DLW/[7LMMMMMMMMMMMMMMMMQQEE9d&\:\#x\ pppppppppppp@ \:\x@9DMMMMMMMMMMMMMM
# MMMMMML3\/ 9DMMMMMMMM9//z#/xzMMMMMMMMMMMMLW\/#&D@[[HMMMMMMMMMMMMMMMMMMMMMMMMMLzJpp3 _ppJLMMMMMMMMMMMMMMMMMM
#
# This might have been written by me, but I assure you, there are plenty of
# people who would if they weren't as bored as I am. Either way, do whatever
# the hell you want with it.
#
use strict;
use warnings;
use Net::Twitter;
use List::MoreUtils qw(uniq);
use Data::Dumper;
use constant AUTH_CONFIG => 'twit_config';
use constant LAST_SPAM_CONFIG => 'last_spam';
use constant SENTINEL_CONFIG => 'sentinel';
use constant SPAM_FREQUENCY => 21600; # 6 hours or greater for next spam
our @COOL_STORY = (
'cool story bro',
'Wow. Cool story, bro.',
'Damn! Cool story bro!',
);
sub write_config {
my ($filename, $config) = @_;
my $fh;
open($fh, '>', $filename) || die;
print { $fh } join("\n", map { "$_ $config->{$_}" } keys %$config);
close($fh);
}
sub read_config {
my $filename = shift;
return () unless -f $filename;
my $fh;
my %config = (open($fh, $filename) && do { local $/ = undef; map { split(/\s/) } split(/\n/, <$fh>) });
close($fh);
return %config;
}
my $sentinel = int(open(SENTINEL, SENTINEL_CONFIG) && do { <SENTINEL> });
close(SENTINEL);
my %config = read_config(AUTH_CONFIG);
my %last_spam = read_config(LAST_SPAM_CONFIG);
my $twit = new Net::Twitter(traits => [qw/API::REST/], %config);
my %suckers;
my @followers = map { $_->{id} } @{$twit->followers};
my @following = map { $_->{id} } @{$twit->following};
my %followers = map { $_ => 1 } @followers;
my %following = map { $_ => 1 } @following;
my @suckers = grep { exists($followers{$_}) xor exists($following{$_}) } (@following, @followers);
# be a good neighbor and allow people to opt-in and opt-out by following or de-following this user.
for my $sucker (@suckers) {
if (exists($followers{$sucker})) {
$twit->create_friend($sucker);
$last_spam{$sucker} = 0;
} elsif (exists($following{$sucker})) {
$twit->destroy_friend($sucker);
delete($last_spam{$sucker});
} else {
# ??? mmm... dangling else.
}
}
my %victims;
eval {
my $feed = $twit->friends_timeline($sentinel ? { since_id => $sentinel, count => 1000 } : { });
foreach my $item (@$feed) {
# let's not spam ourselves!
next if ($item->{user}{screen_name} eq $config{username});
print Dumper $item;
$victims{$item->{id}} = $item->{user}{screen_name};
$sentinel = $item->{id} if ($item->{id} > $sentinel);
}
};
if ($@) { die $@ }
open(SENTINEL, '>', SENTINEL_CONFIG) && do { print SENTINEL $sentinel; close(SENTINEL) };
print Dumper \%last_spam;
# let's at least make an effort to not become the spam-spewing vile that we're
# mocking.
my @victim_names = grep { exists($last_spam{$_}) ? time - int($last_spam{$_}) - SPAM_FREQUENCY > 0 : 1 } uniq(values %victims);
my @victim_posts;
foreach my $id (keys %victims) {
push @victim_posts, $id if(scalar grep $victims{$id} eq $_, @victim_names);
}
my $winnar = $victim_posts[int(rand(@victim_posts))];
exit 0 unless $winnar;
print "$winnar - $victims{$winnar}\n";
$last_spam{$victims{$winnar}} = time;
write_config(LAST_SPAM_CONFIG, \%last_spam);
$twit->update({ status => "\@$victims{$winnar} ".$COOL_STORY[int(rand(scalar @COOL_STORY))], in_reply_to_status_id => $winnar });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment