def post_video(self, video_data, size, duration, thumbnail_data, caption='', to_reel=False, **kwargs):
        """
        Upload a video

        [CAUTION] FLAKY, IG is very picky about sizes, etc, needs testing.

        :param video_data: byte string or a file-like object of the video content
        :param size: tuple of (width, height)
        :param duration: in seconds
        :param thumbnail_data: byte string of the video thumbnail content
        :param caption:
        :param to_reel: post to reel as Story
        :param kwargs:
             - **location**: a dict of venue/location information, from :meth:`location_search`
               or :meth:`location_fb_search`
             - **disable_comments**: bool to disable comments
             - **max_retry_count**: maximum attempts to reupload. Default 10.
        :return:
        """
        warnings.warn('This endpoint has not been fully tested.', UserWarning)

        if not to_reel and not self.compatible_aspect_ratio(size):
            raise ValueError('Incompatible aspect ratio.')

        if to_reel and not self.reel_compatible_aspect_ratio(size):
            raise ValueError('Incompatible reel aspect ratio.')

        if not 612 <= size[0] <= 1080:
            # range was determined through sampling of video uploads
            raise ValueError('Invalid video width.')

        if duration < 3.0:
            raise ValueError('Duration is less than 3s.')

        if not to_reel and duration > 60.0:
            raise ValueError('Duration is more than 60s.')

        if to_reel and duration > 15.0:
            raise ValueError('Duration is more than 15s.')

        max_file_len = 50 * 1024 * 1000
        try:
            video_file_len = len(video_data)
        except TypeError:
            video_file_len = get_file_size(video_data)
        if video_file_len > max_file_len:
            raise ValueError('Video file is too big.')

        location = kwargs.pop('location', None)
        if location:
            self._validate_location(location)
        disable_comments = True if kwargs.pop('disable_comments', False) else False

        endpoint = 'upload/video/'
        upload_id = str(int(time.time() * 1000))

        width, height = size
        params = {
            '_csrftoken': self.csrftoken,
            '_uuid': self.uuid,
            'upload_id': upload_id,
        }
        is_sidecar = kwargs.pop('is_sidecar', False)
        if is_sidecar:
            params['is_sidecar'] = '1'
        else:
            params.update({
                'media_type': MediaTypes.VIDEO,
                'upload_media_duration_ms': int(duration * 1000),
                'upload_media_width': width,
                'upload_media_height': height
            })

        res = self._call_api(endpoint, params=params, unsigned=True)
        upload_url = res['video_upload_urls'][-1]['url']
        upload_job = res['video_upload_urls'][-1]['job']

        successful_chunk_ranges = []
        all_done = False

        max_retry_count = kwargs.pop('max_retry_count', 10)
        configure_delay = 0
        for _ in range(max_retry_count + 1):

            try:
                # Prevent excessively small chunks
                if video_file_len > 1 * 1024 * 1000:
                    # max num of chunks = 4
                    chunk_generator = max_chunk_count_generator(4, video_data)
                else:
                    # max chunk size = 350,000 so that we'll always have
                    # <4 chunks when it's <1mb
                    chunk_generator = max_chunk_size_generator(350000, video_data)

                for chunk, data in chunk_generator:
                    skip_chunk = False
                    for received_chunk in successful_chunk_ranges:
                        if received_chunk[0] <= chunk.start and received_chunk[1] >= (chunk.end - 1):
                            skip_chunk = True
                            break
                    if skip_chunk:
                        self.logger.debug('Skipped chunk: {0:d} - {1:d}'.format(chunk.start, chunk.end - 1))
                        continue

                    headers = self.default_headers
                    headers['Connection'] = 'keep-alive'
                    headers['Content-Type'] = 'application/octet-stream'
                    headers['Content-Disposition'] = 'attachment; filename="video.mov"'
                    headers['Session-ID'] = upload_id
                    if is_sidecar:
                        headers['Cookie'] = 'sessionid=' + self.get_cookie_value('sessionid')
                    headers['job'] = upload_job
                    headers['Content-Length'] = chunk.length
                    headers['Content-Range'] = 'bytes {0:d}-{1:d}/{2:d}'.format(
                        chunk.start, chunk.end - 1, video_file_len)
                    self.logger.debug('POST {0!s}'.format(upload_url))
                    self.logger.debug('Uploading Content-Range: {0!s}'.format(headers['Content-Range']))

                    req = compat_urllib_request.Request(
                        str(upload_url), data=data, headers=headers)

                    try:
                        res = self.opener.open(req, timeout=self.timeout)
                        post_response = self._read_response(res)
                        self.logger.debug('RESPONSE: {0:d} {1!s}'.format(res.code, post_response))
                        if res.info().get('Content-Type', '').startswith('application/json'):
                            # last chunk
                            upload_res = json.loads(post_response)
                            configure_delay = int(upload_res.get('configure_delay_ms', 0)) / 1000.0
                            all_done = True
                            break
                        else:
                            successful_chunk_ranges = []
                            post_progress = post_response.split(',')
                            for progress in post_progress:
                                mobj = re.match(r'(?P<start>[0-9]+)\-(?P<end>[0-9]+)/(?P<total>[0-9]+)', progress)
                                if mobj:
                                    successful_chunk_ranges.append((int(mobj.group('start')), int(mobj.group('end'))))
                                else:
                                    self.logger.error(
                                        'Received unexpected chunk upload response: {0!s}'.format(post_response))
                                    raise ClientError(
                                        'Upload has failed due to unexpected upload response: {0!s}'.format(
                                            post_response),
                                        code=500)

                    except compat_urllib_error.HTTPError as e:
                        error_response = self._read_response(e)
                        self.logger.debug('RESPONSE: {0:d} {1!s}'.format(e.code, error_response))
                        ErrorHandler.process(e, error_response)

                    except (SSLError, timeout, SocketError,
                            compat_urllib_error.URLError,   # URLError is base of HTTPError
                            compat_http_client.HTTPException) as connection_error:
                        raise ClientConnectionError('{} {}'.format(
                            connection_error.__class__.__name__, str(connection_error)))

                else:
                    # if not break due to completed chunks then continue with next chunk
                    continue
                break

            except ClientConnectionError as cce:
                # connectivity prob, so let's just continue with another attempt
                self.logger.warn('ClientConnectionError posting chunks: {}'.format(
                    str(cce)))
                continue

        if not all_done:
            raise ClientError('Upload has failed due to incomplete chunk uploads.', code=500)

        if not configure_delay:
            configure_delay = 3
        configure_retry_max = 2

        for i in range(1, configure_retry_max + 1):
            try:
                if not to_reel:
                    result = self.configure_video(
                        upload_id, size, duration, thumbnail_data, caption=caption, location=location,
                        disable_comments=disable_comments, is_sidecar=is_sidecar)
                else:
                    result = self.configure_video_to_reel(
                        upload_id, size, duration, thumbnail_data)
                return result
            except ClientConnectionError as cce:
                if i < configure_retry_max:
                    self.logger.warn(
                        'Retry configure after {0:f} seconds: {1:s}'.format(
                            configure_delay, cce.msg))
                    time.sleep(configure_delay)
                else:
                    raise
            except ClientError as ce:
                if (ce.code == 202 or ce.msg == 'Transcode timeout') and i < configure_retry_max:
                    self.logger.warn('Retry configure after {0:f} seconds'.format(configure_delay))
                    time.sleep(configure_delay)
                else:
                    raise

        Upload a video

        [CAUTION] FLAKY, IG is very picky about sizes, etc, needs testing.

        :param video_data: byte string or a file-like object of the video content
        :param size: tuple of (width, height)
        :param duration: in seconds
        :param thumbnail_data: byte string of the video thumbnail content
        :param caption:
        :param to_reel: post to reel as Story
        :param kwargs:
             - **location**: a dict of venue/location information, from :meth:`location_search`
               or :meth:`location_fb_search`
             - **disable_comments**: bool to disable comments
             - **max_retry_count**: maximum attempts to reupload. Default 10.
        :return:
        
instagram_private_api/endpoints/upload.py