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!!!