Skip to content

Commit

Permalink
Merge 2cca895 into 00d9d6a
Browse files Browse the repository at this point in the history
  • Loading branch information
karambir committed Sep 29, 2015
2 parents 00d9d6a + 2cca895 commit d26a6b0
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 3 deletions.
16 changes: 16 additions & 0 deletions docs/usage/advanced_usage.rst
Expand Up @@ -35,6 +35,22 @@ Documentation:
* https://dev.twitter.com/rest/reference/post/statuses/update
* https://dev.twitter.com/rest/reference/post/media/upload

Updating Status with Video
--------------------------

This uploads a video as a media object and associates it with a status update.

.. code-block:: python
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']])
Documentation:

* https://dev.twitter.com/rest/reference/post/statuses/update
* https://dev.twitter.com/rest/reference/post/media/upload

Posting a Status with an Editing Image
--------------------------------------

Expand Down
5 changes: 4 additions & 1 deletion twython/api.py
Expand Up @@ -194,7 +194,10 @@ def _request(self, url, method='GET', params=None, api_call=None):
retry_after=response.headers.get('X-Rate-Limit-Reset'))

try:
content = response.json()
if response.status_code == 204:
content = response.content
else:
content = response.json()
except ValueError:
raise TwythonError('Response was not valid JSON. \
Unable to decode.')
Expand Down
65 changes: 63 additions & 2 deletions twython/endpoints.py
Expand Up @@ -14,7 +14,12 @@
https://dev.twitter.com/docs/api/1.1
"""

import os
import warnings
try:
from StringIO import StringIO
except ImportError:
from io import StringIO

from .advisory import TwythonDeprecationWarning

Expand Down Expand Up @@ -139,6 +144,62 @@ def upload_media(self, **params):
"""
return self.post('https://upload.twitter.com/1.1/media/upload.json', params=params)

def upload_video(self, media, media_type, size=None):
"""Uploads video file to Twitter servers in chunks. The file will be available to be attached
to a status for 60 minutes. To attach to a update, pass a list of returned media ids
to the 'update_status' method using the 'media_ids' param.
Upload happens in 3 stages:
- INIT call with size of media to be uploaded(in bytes). If this is more than 15mb, twitter will return error.
- APPEND calls each with media chunk. This returns a 204(No Content) if chunk is received.
- FINALIZE call to complete media upload. This returns media_id to be used with status update.
Twitter media upload api expects each chunk to be not more than 5mb. We are sending chunk of 1mb each.
Docs:
https://dev.twitter.com/rest/public/uploading-media#chunkedupload
"""
upload_url = 'https://upload.twitter.com/1.1/media/upload.json'
if not size:
media.seek(0, os.SEEK_END)
size = media.tell()
media.seek(0)

# Stage 1: INIT call
params = {
'command': 'INIT',
'media_type': media_type,
'total_bytes': size
}
response_init = self.post(upload_url, params=params)
media_id = response_init['media_id']

# Stage 2: APPEND calls with 1mb chunks
segment_index = 0
while True:
data = media.read(1*1024*1024)
if not data:
break
media_chunk = StringIO()
media_chunk.write(data)
media_chunk.seek(0)

params = {
'command': 'APPEND',
'media_id': media_id,
'segment_index': segment_index,
'media': media_chunk,
}
self.post(upload_url, params=params)
segment_index += 1

# Stage 3: FINALIZE call to complete upload
params = {
'command': 'FINALIZE',
'media_id': media_id
}
return self.post(upload_url, params=params)

def get_oembed_tweet(self, **params):
"""Returns information allowing the creation of an embedded
representation of a Tweet on third party sites.
Expand Down Expand Up @@ -546,7 +607,7 @@ def list_mute_ids(self, **params):
list_mute_ids.iter_key = 'ids'

def create_mute(self, **params):
"""Mutes the specified user, preventing their tweets appearing
"""Mutes the specified user, preventing their tweets appearing
in the authenticating user's timeline.
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/create
Expand All @@ -555,7 +616,7 @@ def create_mute(self, **params):
return self.post('mutes/users/create', params=params)

def destroy_mute(self, **params):
"""Un-mutes the user specified in the user or ID parameter for
"""Un-mutes the user specified in the user or ID parameter for
the authenticating user.
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/destroy
Expand Down

0 comments on commit d26a6b0

Please sign in to comment.