|
8 | 8 | import urllib
|
9 | 9 | import uuid
|
10 | 10 | import time
|
| 11 | +import copy |
| 12 | +import math |
11 | 13 | from ImageUtils import getImageSize
|
12 | 14 | from requests_toolbelt import MultipartEncoder
|
| 15 | +from moviepy.editor import VideoFileClip |
13 | 16 |
|
14 | 17 | class InstagramAPI:
|
15 | 18 | API_URL = 'https://i.instagram.com/api/v1/'
|
@@ -134,17 +137,98 @@ def uploadPhoto(self, photo, caption = None, upload_id = None):
|
134 | 137 | self.expose()
|
135 | 138 | return False
|
136 | 139 |
|
137 |
| - def uploadVideo(self, video, caption = None): |
138 |
| - # TODO Instagram.php 290-415 |
| 140 | + def uploadVideo(self, video, thumbnail, caption = None, upload_id = None): |
| 141 | + if upload_id is None: |
| 142 | + upload_id = str(int(time.time() * 1000)) |
| 143 | + data = { |
| 144 | + 'upload_id': upload_id, |
| 145 | + '_csrftoken': self.token, |
| 146 | + 'media_type': '2', |
| 147 | + '_uuid': self.uuid, |
| 148 | + } |
| 149 | + m = MultipartEncoder(data, boundary=self.uuid) |
| 150 | + self.s.headers.update({'X-IG-Capabilities': '3Q4=', |
| 151 | + 'X-IG-Connection-Type': 'WIFI', |
| 152 | + 'Host': 'i.instagram.com', |
| 153 | + 'Cookie2': '$Version=1', |
| 154 | + 'Accept-Language': 'en-US', |
| 155 | + 'Accept-Encoding': 'gzip, deflate', |
| 156 | + 'Content-type': m.content_type, |
| 157 | + 'Connection': 'keep-alive', |
| 158 | + 'User-Agent': self.USER_AGENT}) |
| 159 | + response = self.s.post(self.API_URL + "upload/video/", data=m.to_string()) |
| 160 | + if response.status_code == 200: |
| 161 | + body = json.loads(response.text) |
| 162 | + upload_url = body['video_upload_urls'][3]['url'] |
| 163 | + upload_job = body['video_upload_urls'][3]['job'] |
| 164 | + |
| 165 | + videoData = open(video, 'rb').read() |
| 166 | + request_size = math.floor(len(videoData) / 4) |
| 167 | + lastRequestExtra = (len(videoData) - (request_size * 3)) |
| 168 | + |
| 169 | + headers = copy.deepcopy(self.s.headers) |
| 170 | + self.s.headers.update({'X-IG-Capabilities': '3Q4=', |
| 171 | + 'X-IG-Connection-Type': 'WIFI', |
| 172 | + 'Cookie2': '$Version=1', |
| 173 | + 'Accept-Language': 'en-US', |
| 174 | + 'Accept-Encoding': 'gzip, deflate', |
| 175 | + 'Content-type': 'application/octet-stream', |
| 176 | + 'Session-ID': upload_id, |
| 177 | + 'Connection': 'keep-alive', |
| 178 | + 'Content-Disposition': 'attachment; filename="video.mov"', |
| 179 | + 'job': upload_job, |
| 180 | + 'Host': 'upload.instagram.com', |
| 181 | + 'User-Agent': self.USER_AGENT}) |
| 182 | + for i in range(0, 4): |
| 183 | + start = i * request_size |
| 184 | + if i == 3: |
| 185 | + end = i * request_size + lastRequestExtra |
| 186 | + else: |
| 187 | + end = (i + 1) * request_size |
| 188 | + length = lastRequestExtra if i == 3 else request_size |
| 189 | + content_range = "bytes {start}-{end}/{lenVideo}".format(start=start, end=(end - 1), |
| 190 | + lenVideo=len(videoData)).encode('utf-8') |
| 191 | + |
| 192 | + self.s.headers.update({'Content-Length': str(end - start), 'Content-Range': content_range, }) |
| 193 | + response = self.s.post(upload_url, data=videoData[start:start + length]) |
| 194 | + self.s.headers = headers |
| 195 | + |
| 196 | + if response.status_code == 200: |
| 197 | + if self.configureVideo(upload_id, video, thumbnail, caption): |
| 198 | + self.expose() |
139 | 199 | return False
|
140 | 200 |
|
141 | 201 | def direct_share(self, media_id, recipients, text = None):
|
142 | 202 | # TODO Instagram.php 420-490
|
143 | 203 | return False
|
144 | 204 |
|
145 |
| - def configureVideo(self, upload_id, video, caption = ''): |
146 |
| - # TODO Instagram.php 490-530 |
147 |
| - return False |
| 205 | + def configureVideo(self, upload_id, video, thumbnail, caption = ''): |
| 206 | + clip = VideoFileClip(video) |
| 207 | + self.uploadPhoto(photo=thumbnail, caption=caption, upload_id=upload_id) |
| 208 | + data = json.dumps({ |
| 209 | + 'upload_id': upload_id, |
| 210 | + 'source_type': 3, |
| 211 | + 'poster_frame_index': 0, |
| 212 | + 'length': 0.00, |
| 213 | + 'audio_muted': False, |
| 214 | + 'filter_type': 0, |
| 215 | + 'video_result': 'deprecated', |
| 216 | + 'clips': { |
| 217 | + 'length': clip.duration, |
| 218 | + 'source_type': '3', |
| 219 | + 'camera_position': 'back', |
| 220 | + }, |
| 221 | + 'extra': { |
| 222 | + 'source_width': clip.size[0], |
| 223 | + 'source_height': clip.size[1], |
| 224 | + }, |
| 225 | + 'device': self.DEVICE_SETTINTS, |
| 226 | + '_csrftoken': self.token, |
| 227 | + '_uuid': self.uuid, |
| 228 | + '_uid': self.username_id, |
| 229 | + 'caption': caption, |
| 230 | + }) |
| 231 | + return self.SendRequest('media/configure/?video=1', self.generateSignature(data)) |
148 | 232 |
|
149 | 233 | def configure(self, upload_id, photo, caption = ''):
|
150 | 234 | (w,h) = getImageSize(photo)
|
|
0 commit comments