Created
June 3, 2021 21:10
-
-
Save semifor/d902b13118b25706ab9d613d163e13f3 to your computer and use it in GitHub Desktop.
Chunked media upload with Twitter::API
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 | |
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