Created
February 1, 2017 21:18
-
-
Save semifor/5f7e0721e3be95234988ed9e39b2b553 to your computer and use it in GitHub Desktop.
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/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