Skip to content

Instantly share code, notes, and snippets.

@semifor
Created February 1, 2017 21:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save semifor/5f7e0721e3be95234988ed9e39b2b553 to your computer and use it in GitHub Desktop.
Save semifor/5f7e0721e3be95234988ed9e39b2b553 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
# ABSTRACT: Post a tweet storm to Twitter
#
# Copyright (c) 2017 by Marc Mims
# This is free software, licensed under The MIT (X11) License
use 5.14.0;
use warnings;
use open qw/:utf8 :std/;
use Data::Dump qw/dump/;
use Getopt::Long;
use Regexp::Common qw/URI/;
use Twitter::API;
my $usage = <<EOT;
tweet-storm.pl [ --dry-run ] [ --delay=N ] filename
--dry-run, -n Don't actually tweet, just display Twitter API calls
--delay, -d Delay bewtween tweets, defaults to 10 seconds
--help, -h Display this help message
--example, -x Displays an example tweet-storm text file used to create
https://twitter.com/semifor_test/status/826868027060727808
Will take input from a file or standard input. Each is the text for a tweet.
You can attach a tweet (quote tweet) by appending "attach=URL" to the end of a
line. You can add images to a tweet (up to 4) by appending "image=FILENAME" to
the end of the line for each image.
Requires Twitter OAuth credentials in environment variables:
TWITTER_API_CONSUMER_KEY
TWITTER_API_CONSUMER_SECRET
TWITTER_API_ACCESS_TOKEN
TWITTER_API_ACCESS_TOKEN_SECRET
Note: This isn't bullet proof. If your tweets are too long or unrecoverable
errors are encounted, it will bail out leaving the tweet-storm incomplete.
EOT
# defaults
my $dry_run = 0;
my $delay = 10; # seconds
GetOptions(
'dry-run|n' => \$dry_run,
'delay|d=i' => \$delay,
'help|h' => sub { print $usage; exit 0 },
'example|x' => sub { print <DATA>; exit 0 },
) or die $usage;
my %tokens;
@tokens{qw/consumer_key consumer_secret access_token access_token_secret/} =
map $ENV{$_} // die("expected environment variable $_"),
qw/
TWITTER_API_CONSUMER_KEY
TWITTER_API_CONSUMER_SECRET
TWITTER_API_ACCESS_TOKEN
TWITTER_API_ACCESS_TOKEN_SECRET
/;
my $client = Twitter::API->new_with_traits(
traits => [ qw/RetryOnError ApiMethods/ ],
%tokens
);
sub twitter_api {
my ( $method, $args ) = @_;
if ( $dry_run ) {
say "$method(", dump($args), ")";
return;
}
$client->$method($args);
}
my $prior_tweet;
while ( defined (my $text = <> ) ) {
chomp $text;
next unless length $text;
my %params = ( tweet_mode => 'extended' );
$params{in_reply_to_status_id} = $$prior_tweet{id} if $prior_tweet;
if ( $text =~ s/\battach=($RE{URI}{HTTP}{-scheme => 'https?'})\s*// ) {
$params{attachment_url} = $1;
}
my @images;
while ( $text =~ s/\bimage=(\S+)\s*// ) {
my $filename = $1;
my $media = twitter_api(upload_media => { media => [ $filename ] });
state $fake_image_id = 0;
push @images, $dry_run ? ++$fake_image_id : $$media{media_id};
}
$params{media_ids} = join ',' => @images if @images;
$text =~ s/^\s+|\s+$//g;
$params{status} = $text;
if ( $prior_tweet = twitter_api(update => \%params) ) {
say join ': ', $$prior_tweet{id}, $$prior_tweet{full_text};
}
sleep $delay unless $dry_run;
}
__DATA__
A little automated tweet storm, sarting with a quote tweet. attach=https://twitter.com/semifor_test/status/805876002479951872
Then an image. image=/Users/marc/tmp/hello.jpg
And we're all done. END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment