Vimeo 'Replace' API Endpoint Not Changing Thumbnail

Viewed 253

I am using Vimeo's API for the users of my app to upload videos, or replace their existing video with a new one. I am using a Vimeo Client to help me make the calls in my Django Application. Uploading works without any issues, but when I try to replace an existing video with a new one, the thumbnail stays as the old video. If you play the video, it will play the new one, but the thumbnail never changes.

Model Method that Uploads/Replaces

def vimeo_upload(self):
        media_file = self.video_file
        if media_file and os.path.exists(media_file.path):
            v = vimeo.VimeoClient(token=settings.VIMEO_ACCESS_TOKEN, key=settings.VIMEO_API_KEY,
                                  secret=settings.VIMEO_API_SECRET)
            if self.video_url is None:
                try:
                    video_uri = v.upload(media_file.path)
                except AssertionError as exc:
                    logging.error('Vimeo Error: %s Video: %s' % (exc, media_file.path))
                else:
                    self.video_url = video_uri
            else:
                try:
                    v.replace(video_uri=self.video_url, filename=media_file.path)
                except Exception as exc:
                    self.video_url = None
                    logging.error('Vimeo Replace Error: %s Video: %s' % (exc, media_file.path))
            # set the video title, description, etc.
            if self.video_url:
                try:
                    # convert locale from en-us form to en
                    v.patch(self.video_url, data={'description': self.customer.full_name,     })
                except Exception as exc:
                    logging.error('Vimeo Patch Error: %s Video: %s' % (exc, media_file.path))

Vimeo Client Model, and UploadVideoMixin

class UploadVideoMixin(object):
    """Handle uploading a new video to the Vimeo API."""

    UPLOAD_ENDPOINT = '/me/videos'
    REPLACE_ENDPOINT = '{video_uri}/files'

    def upload(self, filename, upgrade_to_1080=False):
        """Upload the named file to Vimeo."""
        ticket = self.post(
            self.UPLOAD_ENDPOINT,
            data={'type': 'streaming',
                  'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
            params={'fields': 'upload_link,complete_uri'})

        return self._perform_upload(filename, ticket)

    def replace(self, video_uri, filename, upgrade_to_1080=False):
        """Replace the video at the given uri with the named source file."""
        uri = self.REPLACE_ENDPOINT.format(video_uri=video_uri)

        ticket = self.put(
            uri,
            data={'type': 'streaming',
                  'upgrade_to_1080': 'true' if upgrade_to_1080 else 'false'},
            params={'fields': 'upload_link,complete_uri'})

        return self._perform_upload(filename, ticket)

    def _perform_upload(self, filename, ticket):
        """Take an upload ticket and perform the actual upload."""

        if ticket.status_code != 201:
            raise UploadTicketCreationFailure(ticket, "Failed to create an upload ticket")

        ticket = ticket.json()

        # Perform the actual upload.
        target = ticket['upload_link']
        last_byte = 0
        # Try to get size of obj by path. If provided obj is not a file path
        # find the size of file-like object.
        try:
            size = os.path.getsize(filename)
            with io.open(filename, 'rb') as f:
                while last_byte < size:
                    try:
                        self._make_pass(target, f, size, last_byte)
                    except requests.exceptions.Timeout:
                        # If there is a timeout here, we are okay with it, since
                        # we'll check and resume.
                        pass
                    last_byte = self._get_progress(target, size)
        except TypeError:
            size = len(filename.read())
            f = filename
            while last_byte < size:
                try:
                    self._make_pass(target, f, size, last_byte)
                except requests.exceptions.Timeout:
                    # If there is a timeout here, we are okay with it, since
                    # we'll check and resume.
                    pass
                last_byte = self._get_progress(target, size)

        # Perform the finalization and get the location.
        finalized_resp = self.delete(ticket['complete_uri'])

        if finalized_resp.status_code != 201:
            raise VideoCreationFailure(finalized_resp, "Failed to create the video")

        return finalized_resp.headers.get('Location', None)

    def _get_progress(self, upload_target, filesize):
        """Test the completeness of the upload."""
        progress_response = self.put(
            upload_target,
            headers={'Content-Range': 'bytes */*'})

        range_recv = progress_response.headers.get('Range', None)
        _, last_byte = range_recv.split('-')

        return int(last_byte)

    def _make_pass(self, upload_target, f, size, last_byte):
        """Make a pass at uploading.

        This particular function may do many things.  If this is a large upload
        it may terminate without having completed the upload.  This can also
        occur if there are network issues or any other interruptions.  These
        can be recovered from by checking with the server to see how much it
        has and resuming the connection.
        """
        response = self.put(
            upload_target,
            timeout=None,
            headers={
                'Content-Length': str(size),
                'Content-Range': 'bytes: %d-%d/%d' % (last_byte, size, size)
            }, data=f)

        if response.status_code != 200:
            raise VideoUploadFailure(response, "Unexpected status code on upload")

class VimeoClient(ClientCredentialsMixin, AuthorizationCodeMixin, UploadMixin):
    """Client handle for the Vimeo API."""

    API_ROOT = "https://api.vimeo.com"
    HTTP_METHODS = set(('head', 'get', 'post', 'put', 'patch', 'options', 'delete'))
    ACCEPT_HEADER = "application/vnd.vimeo.*;version=3.2"
    USER_AGENT = "pyvimeo 0.3.10; (http://developer.vimeo.com/api/docs)"

    def __init__(self, token=None, key=None, secret=None, *args, **kwargs):
        """Prep the handle with the authentication information."""
        self.token = token
        self.app_info = (key, secret)
        self._requests_methods = dict()

        # Make sure we have enough info to be useful.
        assert token is not None or (key is not None and secret is not None)

    # Internally we back this with an auth mechanism for Requests.
    @property
    def token(self):
        return self._token.token

    @token.setter
    def token(self, value):
        self._token = _BearerToken(value) if value else None

    def __getattr__(self, name):
        """This is where we get the function for the verb that was just
        requested.

        From here we can apply the authentication information we have.
        """
        if name not in self.HTTP_METHODS:
            raise AttributeError("%r is not an HTTP method" % name)

        # Get the Requests based function to use to preserve their defaults.
        request_func = getattr(requests, name, None)
        if request_func is None:
            raise AttributeError(
                "%r could not be found in the backing lib" % name
            )

        @wraps(request_func)
        def caller(url, jsonify=True, **kwargs):
            """Hand off the call to Requests."""
            headers = kwargs.get('headers', dict())
            headers['Accept'] = self.ACCEPT_HEADER
            headers['User-Agent'] = self.USER_AGENT

            if jsonify \
                    and 'data' in kwargs \
                    and isinstance(kwargs['data'], (dict, list)):
                kwargs['data'] = json.dumps(kwargs['data'])
                headers['Content-Type'] = 'application/json'

            kwargs['timeout'] = kwargs.get('timeout', (1, 30))
            kwargs['auth'] = kwargs.get('auth', self._token)
            kwargs['headers'] = headers
            if not url[:4] == "http":
                url = self.API_ROOT + url

            response = request_func(url, **kwargs)
            if response.status_code == 429:
                raise APIRateLimitExceededFailure(
                    response, 'Too many API requests'
                )
            return response
        return caller


class _BearerToken(requests.auth.AuthBase):
    """Model the bearer token and apply it to the request."""
    def __init__(self, token):
        self.token = token

    def __call__(self, request):
        request.headers['Authorization'] = 'Bearer ' + self.token
        return request
0 Answers
Related