14
14
https://dev.twitter.com/docs/api/1.1
15
15
"""
16
16
17
+ import os
17
18
import warnings
19
+ try :
20
+ from StringIO import StringIO
21
+ except ImportError :
22
+ from io import StringIO
18
23
19
24
from .advisory import TwythonDeprecationWarning
20
25
@@ -139,6 +144,62 @@ def upload_media(self, **params):
139
144
"""
140
145
return self .post ('https://upload.twitter.com/1.1/media/upload.json' , params = params )
141
146
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
+
142
203
def get_oembed_tweet (self , ** params ):
143
204
"""Returns information allowing the creation of an embedded
144
205
representation of a Tweet on third party sites.
@@ -546,7 +607,7 @@ def list_mute_ids(self, **params):
546
607
list_mute_ids .iter_key = 'ids'
547
608
548
609
def create_mute (self , ** params ):
549
- """Mutes the specified user, preventing their tweets appearing
610
+ """Mutes the specified user, preventing their tweets appearing
550
611
in the authenticating user's timeline.
551
612
552
613
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/create
@@ -555,7 +616,7 @@ def create_mute(self, **params):
555
616
return self .post ('mutes/users/create' , params = params )
556
617
557
618
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
559
620
the authenticating user.
560
621
561
622
Docs: https://dev.twitter.com/docs/api/1.1/post/mutes/users/destroy
0 commit comments