Skip to content

Instantly share code, notes, and snippets.

@semifor
Created June 3, 2021 21:10
Show Gist options
  • Save semifor/d902b13118b25706ab9d613d163e13f3 to your computer and use it in GitHub Desktop.
Save semifor/d902b13118b25706ab9d613d163e13f3 to your computer and use it in GitHub Desktop.
Chunked media upload with Twitter::API
#!/usr/bin/env perl
use 5.14.1;
use warnings;
# Usage:
#
# chunked-media-upload [ --type=TYPE ] [ --category=CATEGORY ] FILENAME
use File::stat;
use Getopt::Long;
use JSON::MaybeXS;
use MIME::Base64;
use Twitter::API;
my $type = 'video/mp4';
my $category = 'tweet_video';
GetOptions(
'type|t=s' => \$type,
'category|c=s' => \$category,
) or die;
my $filename = shift // die 'usage: chunked-media-upload [ --type=TYPE ] [ --category=CATEGORY ] FILENAME';
my $client = Twitter::API->new_with_traits(
traits => [ qw/ApiMethods/ ],
consumer_key => $ENV{TWITTER_API_CONSUMER_KEY},
consumer_secret => $ENV{TWITTER_API_CONSUMER_SECRET},
access_token => $ENV{TWITTER_API_ACCESS_TOKEN},
access_token_secret => $ENV{TWITTER_API_ACCESS_TOKEN_SECRET},
);
open my $fh, '<:raw', $filename or die "failed to open $filename: $!";
my $total_bytes = stat($fh)->size;
# Initialize the upload
my $media = $client->upload_media({
command => 'INIT',
media_type => $type,
media_category => $category,
total_bytes => $total_bytes,
});
# Send chunked data
my $chunk_size = 4*1024*1024; # must be less than 5MB
local $/ = \$chunk_size;
my $bytes_sent = 0;
my $segment_index = 0;
while ( $bytes_sent < $total_bytes ) {
my $chunk = <$fh>;
say "uploading segment $segment_index";
$client->upload_media({
command => 'APPEND',
media_id => $$media{media_id},
media_data => encode_base64($chunk),
segment_index => $segment_index++,
});
$bytes_sent += length $chunk;
}
# Finalize the upload
my $r = $client->upload_media({
command => 'FINALIZE',
media_id => $$media{media_id},
});
# poll until complete
while ( my $processing_info = $$r{processing_info} ) {
last unless $$processing_info{state} eq 'pending';
sleep $$processing_info{check_after_secs};
$r = $client->request(get => $client->upload_url_for('media/upload'), {
command => 'STATUS',
media_id => $$media{media_id},
});
}
# Output the final result
say JSON->new->pretty->encode($r);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment