Long time guys. I don’t really have a good excuse for why, because my excuse is laziness.

Anyway, I’m currently working on a personal project that involves uploading video to twitter. I don’t want to go into more details because I might never finish it, and I really don’t want too many people asking what happened.

While I was using it to upload some video, I encountered an error that I couldn’t easily fix:

twython.exceptions.TwythonError: Twitter API returned a 400 (Bad Request), Duration too long, maximum:30000, actual:60000 (MediaId: snf:1128709657999106049)

Now if you look at the Twython documentation for uploading a status with video you’ll find the following code:

video = open('/path/to/file/video.mp4', 'rb')
response = twitter.upload_video(media=video, media_type='video/mp4')
twitter.update_status(status='Checkout this cool video!', media_ids=[response['media_id']])

As part of my efforts to debug the issue I looked at the response object:

{'media_id': 1128709657999106049, 'media_id_string': '1128709657999106049', 'size': 5117159, 'expires_after_secs': 86400, 'video': {'video_type': 'video/mp4'}}

It’s a dictionary. This told me that the video was being uploaded but the length (remember the error: Duration too long, maximum:30000, actual:60000). Reading the Twitter documentation didn’t help much as the limitations mentioned are only about size:

Size restrictions for uploading via API
– Image 5MB
– GIF 15MB
– Video 15MB

After a bit of googling, I found out that the upload that Twython does in the example given is sync (this has a duration limit of 30 seconds, and a size limit of 15 MB) while what I needed was async or what twitter changed to calling chunked media upload.

However, the Twython documentation didn’t have that documented clearly. But I did find this issue on Github that pointed me in the right direction. I simply needed to add media_category='tweet_video', check_progress=True to the upload arguments.

video = open(video_path, 'rb') response = twitter.upload_video(media=video, media_type='video/mp4', media_category='tweet_video', check_progress=True)

Be careful though of following the example from before though. Because of how the upload is done, in chunks, which can take a little time. Keep an eye on the response object contains processing_info which contains a state variable. See examples:

1. 'processing_info': {'state': 'pending', 'check_after_secs': 1}
2. 'processing_info': {'state': 'succeeded', 'progress_percent': 100}

You can only upload after the state changes to succeeded. While Twython does have it’s own way of dealing with this there were a couple of times I did get the first state. I dealt with this by adding a sleep period that matches the check_after_secs variable if it is in the response variable otherwise it moves to update the status. This is what it looked like:

processing_info = response['processing_info']
state = processing_info['state']
wait = processing_info.get('check_after_secs', 1)
if (state == 'pending' or state == 'in_progress'):
    print('Waiting ' + wait + 's')
    time.sleep(wait)

This covered any edge cases for me. I hope you found this helpful. Peace!!!

Written by Sidney Ochieng

Data scientist, Intelipro. Feminist ally. Story teller. Child at heart and mind. Not so much selfish as narcissistic. Refuse to accept mediocrity.

Leave a Reply

Your email address will not be published. Required fields are marked *

20 − twenty =