Initial source.
authorjcipriano <jcipriano@twitter.com>
Wed, 6 Jul 2016 23:14:53 +0000 (16:14 -0700)
committerjcipriano <jcipriano@twitter.com>
Wed, 6 Jul 2016 23:14:53 +0000 (16:14 -0700)
.gitignore
README.md [new file with mode: 0644]
async-upload.py [new file with mode: 0644]
requirements.txt [new file with mode: 0644]

index 72364f99fe4bf8d5262df3b19b33102aeaa791e5..0ad7621b8e0204f9a76c923ced5d4bcc26d8f61d 100644 (file)
@@ -87,3 +87,6 @@ ENV/
 
 # Rope project settings
 .ropeproject
 
 # Rope project settings
 .ropeproject
+
+
+.DS_Store
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/async-upload.py b/async-upload.py
new file mode 100644 (file)
index 0000000..aa3e21b
--- /dev/null
@@ -0,0 +1,169 @@
+import os
+import sys
+import time
+
+import json
+import requests
+from requests_oauthlib import OAuth1
+
+
+MEDIA_ENDPOINT_URL = 'https://upload.twitter.com/1.1/media/upload.json'
+POST_TWEET_URL = 'https://api.twitter.com/1.1/statuses/update.json'
+
+CONSUMER_KEY = 'your-consumer-key'
+CONSUMER_SECRET = 'your-consumer-secret'
+ACCESS_TOKEN = 'your-access-token'
+ACCESS_TOKEN_SECRET = 'your-access-secret'
+
+VIDEO_FILENAME = 'path/to/video/file'
+
+
+oauth = OAuth1(CONSUMER_KEY,
+  client_secret=CONSUMER_SECRET,
+  resource_owner_key=ACCESS_TOKEN,
+  resource_owner_secret=ACCESS_TOKEN_SECRET)
+
+
+class VideoTweet(object):
+
+  def __init__(self, file_name):
+    '''
+    Defines video tweet properties
+    '''
+    self.video_filename = file_name
+    self.total_bytes = os.path.getsize(self.video_filename)
+    self.media_id = None
+    self.processing_info = None
+
+
+  def upload_init(self):
+    '''
+    Initializes Upload
+    '''
+    print('INIT')
+
+    request_data = {
+      'command': 'INIT',
+      'media_type': 'video/mp4',
+      'total_bytes': self.total_bytes,
+      'media_category': 'tweetvideo'
+    }
+
+    req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
+    media_id = req.json()['media_id']
+
+    self.media_id = media_id
+
+    print('Media ID: %s' % str(media_id))
+
+
+  def upload_append(self):
+    '''
+    Uploads media in chunks and appends to chunks uploaded
+    '''
+    segment_id = 0
+    bytes_sent = 0
+    file = open(self.video_filename, 'rb')
+
+    while bytes_sent < self.total_bytes:
+      chunk = file.read(4*1024*1024)
+      
+      print('APPEND')
+
+      request_data = {
+        'command': 'APPEND',
+        'media_id': self.media_id,
+        'segment_index': segment_id
+      }
+
+      files = {
+        'media':chunk
+      }
+
+      req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, files=files, auth=oauth)
+
+      if req.status_code < 200 or req.status_code > 299:
+        print(req.status_code)
+        print(req.text)
+        sys.exit(0)
+
+      segment_id = segment_id + 1
+      bytes_sent = file.tell()
+
+      print('%s of %s bytes uploaded' % (str(bytes_sent), str(self.total_bytes)))
+
+    print('Upload chunks complete.')
+
+
+  def upload_finalize(self):
+    '''
+    Finalizes uploads and starts video processing
+    '''
+    print('FINALIZE')
+
+    request_data = {
+      'command': 'FINALIZE',
+      'media_id': self.media_id
+    }
+
+    req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
+    print(req.json())
+
+    self.processing_info = req.json().get('processing_info', None)
+    self.check_status()
+
+
+  def check_status(self):
+    '''
+    Checks video processing status
+    '''
+    if self.processing_info is None:
+      return
+
+    state = self.processing_info['state']
+
+    print('Media processing status is %s ' % state)
+
+    if state == u'succeeded':
+      return
+
+    if state == u'failed':
+      sys.exit(0)
+
+    check_after_secs = self.processing_info['check_after_secs']
+    
+    print('Checking after %s seconds' % str(check_after_secs))
+    time.sleep(check_after_secs)
+
+    print('STATUS')
+
+    request_params = {
+      'command': 'STATUS',
+      'media_id': self.media_id
+    }
+
+    req = requests.get(url=MEDIA_ENDPOINT_URL, params=request_params, auth=oauth)
+    
+    self.processing_info = req.json().get('processing_info', None)
+    self.check_status()
+
+
+  def tweet(self):
+    '''
+    Publishes Tweet with attached video
+    '''
+    request_data = {
+      'status': 'I just uploaded a video with the @TwitterAPI.',
+      'media_ids': self.media_id
+    }
+
+    req = requests.post(url=POST_TWEET_URL, data=request_data, auth=oauth)
+    print(req.json())
+
+
+if __name__ == '__main__':
+  videoTweet = VideoTweet(VIDEO_FILENAME)
+  videoTweet.upload_init()
+  videoTweet.upload_append()
+  videoTweet.upload_finalize()
+  videoTweet.tweet()
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..a8e58d7
--- /dev/null
@@ -0,0 +1,3 @@
+oauthlib==1.1.2
+requests==2.10.0
+requests-oauthlib==0.6.1