turn into working cli tool
[video-tweet.git] / async-upload.py
1 import os
2 import sys
3 import time
4
5 import json
6 import requests
7 from requests_oauthlib import OAuth1
8
9
10 MEDIA_ENDPOINT_URL = 'https://upload.twitter.com/1.1/media/upload.json'
11 POST_TWEET_URL = 'https://api.twitter.com/1.1/statuses/update.json'
12
13 CONSUMER_KEY = 'hJHyPhuU7nSVHrKTVsGVDM4Lw'
14 CONSUMER_SECRET = '8UCYePqc1y9DY6mg0yQzLoTuq57AIysype2Si63714uACGMCbO'
15
16 with open(os.path.expanduser('~') + '/.rainbow_oauth-fsf') as fp:
17 ACCESS_TOKEN = fp.readline().rstrip('\n')
18 ACCESS_TOKEN_SECRET = fp.readline().rstrip('\n')
19
20 oauth = OAuth1(CONSUMER_KEY,
21 client_secret=CONSUMER_SECRET,
22 resource_owner_key=ACCESS_TOKEN,
23 resource_owner_secret=ACCESS_TOKEN_SECRET)
24
25
26 class VideoTweet(object):
27
28 def __init__(self, file_name):
29 '''
30 Defines video tweet properties
31 '''
32 self.video_filename = file_name
33 self.total_bytes = os.path.getsize(self.video_filename)
34 self.media_id = None
35 self.processing_info = None
36
37
38 def upload_init(self):
39 '''
40 Initializes Upload
41 '''
42 print('INIT')
43
44 request_data = {
45 'command': 'INIT',
46 'media_type': 'video/mp4',
47 'total_bytes': self.total_bytes,
48 'media_category': 'tweet_video'
49 }
50
51 req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
52 media_id = req.json()['media_id']
53
54 self.media_id = media_id
55
56 print('Media ID: %s' % str(media_id))
57
58
59 def upload_append(self):
60 '''
61 Uploads media in chunks and appends to chunks uploaded
62 '''
63 segment_id = 0
64 bytes_sent = 0
65 file = open(self.video_filename, 'rb')
66
67 while bytes_sent < self.total_bytes:
68 chunk = file.read(4*1024*1024)
69
70 print('APPEND')
71
72 request_data = {
73 'command': 'APPEND',
74 'media_id': self.media_id,
75 'segment_index': segment_id
76 }
77
78 files = {
79 'media':chunk
80 }
81
82 req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, files=files, auth=oauth)
83
84 if req.status_code < 200 or req.status_code > 299:
85 print(req.status_code)
86 print(req.text)
87 sys.exit(0)
88
89 segment_id = segment_id + 1
90 bytes_sent = file.tell()
91
92 print('%s of %s bytes uploaded' % (str(bytes_sent), str(self.total_bytes)))
93
94 print('Upload chunks complete.')
95
96
97 def upload_finalize(self):
98 '''
99 Finalizes uploads and starts video processing
100 '''
101 print('FINALIZE')
102
103 request_data = {
104 'command': 'FINALIZE',
105 'media_id': self.media_id
106 }
107
108 req = requests.post(url=MEDIA_ENDPOINT_URL, data=request_data, auth=oauth)
109 print(req.json())
110
111 self.processing_info = req.json().get('processing_info', None)
112 self.check_status()
113
114
115 def check_status(self):
116 '''
117 Checks video processing status
118 '''
119 if self.processing_info is None:
120 return
121
122 state = self.processing_info['state']
123
124 print('Media processing status is %s ' % state)
125
126 if state == u'succeeded':
127 return
128
129 if state == u'failed':
130 sys.exit(0)
131
132 check_after_secs = self.processing_info['check_after_secs']
133
134 print('Checking after %s seconds' % str(check_after_secs))
135 time.sleep(check_after_secs)
136
137 print('STATUS')
138
139 request_params = {
140 'command': 'STATUS',
141 'media_id': self.media_id
142 }
143
144 req = requests.get(url=MEDIA_ENDPOINT_URL, params=request_params, auth=oauth)
145
146 self.processing_info = req.json().get('processing_info', None)
147 self.check_status()
148
149
150 def tweet(self):
151 '''
152 Publishes Tweet with attached video
153 '''
154 request_data = {
155 'status': tweet_text,
156 'media_ids': self.media_id
157 }
158
159 req = requests.post(url=POST_TWEET_URL, data=request_data, auth=oauth)
160 print(req.json())
161
162
163 if __name__ == '__main__':
164 if (len(sys.argv) < 2):
165 print('error: expected 2+ arguments, path to video (no spaces) and tweet text')
166 sys.exit(1)
167 VIDEO_FILENAME = sys.argv[1]
168 global tweet_text
169 tweet_text = ' '.join(sys.argv[2:])
170
171 videoTweet = VideoTweet(VIDEO_FILENAME)
172 videoTweet.upload_init()
173 videoTweet.upload_append()
174 videoTweet.upload_finalize()
175 videoTweet.tweet()