1414https://dev.twitter.com/docs/api/1.1
1515"""
1616
17+ import os
1718import warnings
19+ try :
20+ from StringIO import StringIO
21+ except ImportError :
22+ from io import StringIO
1823
1924from .advisory import TwythonDeprecationWarning
2025
@@ -139,6 +144,62 @@ def upload_media(self, **params):
139144 """
140145 return self .post ('https://upload.twitter.com/1.1/media/upload.json' , params = params )
141146
147+ def upload_video (self , media , media_type , size = None ):
148+ """Uploads video file to Twitter servers in chunks. The file will be available to be attached
149+ to a status for 60 minutes. To attach to a update, pass a list of returned media ids
150+ to the 'update_status' method using the 'media_ids' param.
151+
152+ Upload happens in 3 stages:
153+ - INIT call with size of media to be uploaded(in bytes). If this is more than 15mb, twitter will return error.
154+ - APPEND calls each with media chunk. This returns a 204(No Content) if chunk is received.
155+ - FINALIZE call to complete media upload. This returns media_id to be used with status update.
156+
157+ Twitter media upload api expects each chunk to be not more than 5mb. We are sending chunk of 1mb each.
158+
159+ Docs:
160+ https://dev.twitter.com/rest/public/uploading-media#chunkedupload
161+ """
162+ upload_url = 'https://upload.twitter.com/1.1/media/upload.json'
163+ if not size :
164+ media .seek (0 , os .SEEK_END )
165+ size = media .tell ()
166+ media .seek (0 )
167+
168+ # Stage 1: INIT call
169+ params = {
170+ 'command' : 'INIT' ,
171+ 'media_type' : media_type ,
172+ 'total_bytes' : size
173+ }
174+ response_init = self .post (upload_url , params = params )
175+ media_id = response_init ['media_id' ]
176+
177+ # Stage 2: APPEND calls with 1mb chunks
178+ segment_index = 0
179+ while True :
180+ data = media .read (1 * 1024 * 1024 )
181+ if not data :
182+ break
183+ media_chunk = StringIO ()
184+ media_chunk .write (data )
185+ media_chunk .seek (0 )
186+
187+ params = {
188+ 'command' : 'APPEND' ,
189+ 'media_id' : media_id ,
190+ 'segment_index' : segment_index ,
191+ 'media' : media_chunk ,
192+ }
193+ self .post (upload_url , params = params )
194+ segment_index += 1
195+
196+ # Stage 3: FINALIZE call to complete upload
197+ params = {
198+ 'command' : 'FINALIZE' ,
199+ 'media_id' : media_id
200+ }
201+ return self .post (upload_url , params = params )
202+
142203 def get_oembed_tweet (self , ** params ):
143204 """Returns information allowing the creation of an embedded
144205 representation of a Tweet on third party sites.
@@ -546,7 +607,7 @@ def list_mute_ids(self, **params):
546607 list_mute_ids .iter_key = 'ids'
547608
548609 def create_mute (self , ** params ):
549- """Mutes the specified user, preventing their tweets appearing
610+ """Mutes the specified user, preventing their tweets appearing
550611 in the authenticating user's timeline.
551612
552613 Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/create
@@ -555,7 +616,7 @@ def create_mute(self, **params):
555616 return self .post ('mutes/users/create' , params = params )
556617
557618 def destroy_mute (self , ** params ):
558- """Un-mutes the user specified in the user or ID parameter for
619+ """Un-mutes the user specified in the user or ID parameter for
559620 the authenticating user.
560621
561622 Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/destroy
0 commit comments