返回顶部
首页 > 资讯 > 后端开发 > Python >优酷上传SDK解析(Python)
  • 830
分享到

优酷上传SDK解析(Python)

上传SDKPython 2023-01-31 00:01:04 830人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

  1.优酷上传   1)调用优酷的sdk完成优酷视频的上传首先需要将实例化YoukuUpload类实例化,传入的参数为(client_id,access_token,文件地址) 实例化时执行__init__()   2)实例化完成后得

 

1.优酷上传

  1)调用优酷的sdk完成优酷视频的上传首先需要将实例化YoukuUpload类实例化,传入的参数为(client_id,access_token,文件地址)

实例化时执行__init__()

  2)实例化完成后得到类的对象,通过对象调用upload方法,传入参数为字典(dict),字典内的必传参数为title,其余可为默认,其中的一些参数是为了控制视频一些信息的,具体参见代码的注释

  3)在upload方法中

    

    (1)会先判断upload_token 这个参数是否存在,该参数为优酷返回,存在就继续之前的上传,如果不存在的话就判断为新上传。

    (2)在新上传中限制性create方法来在服务端创建上传,在此之前会对传进来的参数和默认的参数会放入新的字典中

    def prepare_video_params(self, title=None, tags='Others', description='',
                             copyright_type='original', public_type='all',
                             cateGory=None, watch_passWord=None,
                             latitude=None, longitude=None, shoot_time=None
                             ):
        # 准备视频所以需要的一些参数
        params = {}
        if title is None:
            # 如果没有传title的话,title默认等于文件名
            title = self.file_name
        elif len(title) > 50:
            # 如果title过长,长度大于50的话,就截取前50个字符作为title
            title = title[:50]
        params['title'] = title
        params['tags'] = tags
        # tags就等于你传进来的那个tags,默认为others
        params['description'] = description
        # 描述默认为空,可以传进来
        params['copyright_type'] = copyright_type
        # 版权所有 original: 原创 reproduced: 转载
        params['public_type'] = public_type
        # 公开类型 all: 公开 friend: 仅好友观看 password: 输入密码观看 private: 私有
        if category:
            params['category'] = category
            # 视频分类 默认为空,可传
        if watch_password:
            params['watch_password'] = watch_password
            # 观看密码,默认为空,可传
        """
        latitude/longitude用户记录地理位置信息
        shoot_time用来标记视频中正片的开始时间
        """
        if latitude:
            params['latitude'] = latitude
            # 纬度
        if longitude:
            params['longitude'] = longitude
            # 经度
        if shoot_time:
            params['shoot_time'] = shoot_time
        log.debug("prepare_video_params:%s" % params)
        return params

    (3)在create方法中,会用get方法访问url = 'https://api.youku.com/uploads/create.JSON',并将参数传过去,创建oss客户端,优酷会返回一些字段

    def create(self, params):
        # prepare file info
        params['file_name'] = self.file_name
        params['file_size'] = self.file_size # 在__init__中获取到了,也就是在类的实例化时就已经根据文件的地址获取了文件的大小
        params['file_md5'] = self.file_md5 = self.checksum_md5file(self.file)
        # 将文件信息做md5 校验,根据文件名打开文件,然后每次读取8192B,进行md5更新后再转为十六进制返回
        self.logger.info('upload file %s, size: %d bytes' %
                         (self.file_name, self.file_size))
        self.logger.info('md5 of %s: %s' %
                         (self.file_name, self.file_md5))

        params['client_id'] = self.client_id # client_id
        params['access_token'] = self.access_token # access_token

        url = 'Https://api.youku.com/uploads/create.json'
        r = requests.get(url, params=params)# 以get方法将文件信息发送到'https://api.youku.com/uploads/create.json'
        check_error(r, 201)
        result = r.json()
        log.debug("file--->vid:%s,return_result:%s" % (self.v_vid, result))
        self.upload_token = result['upload_token']
        self.logger.info('upload token of %s: %s' %
                         (self.file_name, self.upload_token))
        self.upload_server_ip = Socket.gethostbyname(
            result['upload_server_uri'])
        self.logger.info('upload_server_ip of %s: %s' %
                         (self.file_name, self.upload_server_ip))
        log.debug("file_vid:%s ip:%s" % (self.v_vid, self.upload_server_ip))

 

       (4) 调用create_file方法,将文件的大小、token、每次上传切片大小传到上一步返回的ip所指向的服务器

       (5) 调用new_slice方法 告诉服务器才准备上传文件切片,目的在于检查服务器状态和返回服务器中这个新建切片的信息,没有报错就执行_save_slice_state方法

       (6)在_save_slice_state方法中,将切片的信息进行更新或者保存,之后判断返回的task_id是否为0,如果为零就直接提交commit完成整个上传,不为0就 调用upload_slice方法上传文件切片

      (7)在upload_slice方法中,每次打开文件移动指针位置到上一次上传的地方,然后读取2048kb的数据,之后调用url进行上传。

    def upload_slice(self):
        # 上传文件切片  seek():移动文件读取指针到指定位置

        data = None
        with open(self.file, 'rb') as f:
            f.seek(self.slice_offset) 
            data = f.read(self.slice_length) # 2048
        params = {
            'upload_token': self.upload_token,
            'slice_task_id': self.slice_task_id,
            'offset': self.slice_offset,
            'length': self.slice_length,  # Byte
            'hash': self.checksum_md5data(data)# hash这个字段是为了在服务端进行校验,来验证上传的文件有没有出现丢失或错误
        }
        url = 'http://%s/gupload/upload_slice' % self.upload_server_ip
        r = requests.post(url, params=params, data=data)
        check_error(r, 201)
        self._save_slice_state(r.json())

     (8) 循环判断task_id,若task_id为0则结束上传(即调用commit())

    整体流程:应该是先本地将文件的信息上传到服务器,在服务器创建同名文件,然后根据文件的size和每次对文件进行切片的大小控制上传,在上传过程中服务端会先返回这次要上传的切片的task_id,如果在服务端的文件大小等于你上传的参数中提交的size,就会返回task_id为0,否则就不为0。本地会根据这个参数来判断是否结束上传。

 2. 完整优酷上传sdk代码  

"""Youku cloud python Client

doc: http://cloud.youku.com/docs/doc?id=110
"""

import os
import requests
import json
import time
import hashlib
import socket
import logging
from time import sleep
from util import check_error, YoukuError

if not os.path.exists('/var/log/youku/'):
    os.makedirs('/var/log/youku')
log = logging.getLogger()
log.setLevel(logging.DEBUG)
fmt = logging.FORMatter("%(asctime)s %(pathname)s %(filename)s %(funcName)s %(lineno)s %(levelname)s - %(message)s",
                        "%Y-%m-%d %H:%M:%S")
stream_handler = logging.FileHandler(
    '/var/log/youku/debug-%s.log' % (time.strftime('%Y-%m-%d', time.localtime(time.time()))))
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(fmt)
log.addHandler(stream_handler)


class YoukuUpload(object):
    """Youku Upload Client.

    Upload file to Youku Video. Support resume upload if interrupted.
    Should use one instance of YoukuUpload for one upload file in one thread,
    since it has internal state of upload process.

    doc: http://cloud.youku.com/docs/doc?id=110
    """

    def __init__(self, client_id, access_token, file, v_vid = None, logger=None):
        """
        Args:
            file: string, include path and filename for open(). filename
                must contain video file extension.
        """
        super(YoukuUpload, self).__init__()
        self.client_id = client_id
        self.access_token = access_token
        self.v_vid = v_vid # 上传的视频id号
        self.logger = logger or logging.getLogger(__name__)

        # file info
        self.file = file
        self.file_size = os.path.getsize(self.file)  # int 获取文件的大小
        self.file_dir, self.file_name = os.path.split(self.file)  # string 分割路径来获取文件名
        if self.file_dir == '':
            self.file_dir = '.'
        self.file_ext = self.file_name.rsplit('.', 1)[1],  # file extension
        self.file_md5 = None  # string, do later

        # upload state
        self.upload_token = None  # string
        self.upload_server_ip = None  # string
        self.slice_task_id = None  # int
        self.slice_offset = None  # int
        self.slice_length = None  # int
        self.transferred = None  # int for bytes has uploaded
        self.finished = False  # boolean

        # resume upload state
        self._read_upload_state_from_file()

    def prepare_video_params(self, title=None, tags='Others', description='',
                             copyright_type='original', public_type='all',
                             category=None, watch_password=None,
                             latitude=None, longitude=None, shoot_time=None
                             ):
        # 准备视频所以需要的一些参数
        """ util method for create video params to upload.

        Only need to provide a minimum of two essential parameters:
        title and tags, other video params are optional. All params spec
        see: http://cloud.youku.com/docs?id=110#create .

        Args:
            title: string, 2-50 characters.
            tags: string, 1-10 tags joind with comma.
            description: string, less than 2000 characters.
            copyright_type: string, 'original' or 'reproduced'
            public_type: string, 'all' or 'friend' or 'password'
            watch_password: string, if public_type is password.
            latitude: double.
            longitude: double.
            shoot_time: datetime.

        Returns:
            dict params that upload/create method need.
        """
        params = {}
        if title is None:
            # 如果没有传title的话,title默认等于文件名
            title = self.file_name
        elif len(title) > 50:
            # 如果title过长,长度大于50的话,就截取前50个字符作为title
            title = title[:50]
        params['title'] = title
        params['tags'] = tags
        # tags就等于你传进来的那个tags,默认为others
        params['description'] = description
        # 描述默认为空,可以传进来
        params['copyright_type'] = copyright_type
        # 版权所有 original: 原创 reproduced: 转载
        params['public_type'] = public_type
        # 公开类型 all: 公开 friend: 仅好友观看 password: 输入密码观看 private: 私有
        if category:
            params['category'] = category
            # 视频分类 默认为空,可传
        if watch_password:
            params['watch_password'] = watch_password
            # 观看密码,默认为空,可传
        """
        latitude/longitude用户记录地理位置信息
        shoot_time用来标记视频中正片的开始时间
        """
        if latitude:
            params['latitude'] = latitude
            # 纬度
        if longitude:
            params['longitude'] = longitude
            # 经度
        if shoot_time:
            params['shoot_time'] = shoot_time
        log.debug("prepare_video_params:%s" % params)
        return params

    def create(self, params):
        # prepare file info
        params['file_name'] = self.file_name
        params['file_size'] = self.file_size # 在__init__中获取到了,也就是在类的实例化时就已经根据文件的地址获取了文件的大小
        params['file_md5'] = self.file_md5 = self.checksum_md5file(self.file)
        # 将文件信息做md5 校验,根据文件名打开文件,然后每次读取8192B,进行md5更新后再转为十六进制返回
        self.logger.info('upload file %s, size: %d bytes' %
                         (self.file_name, self.file_size))
        self.logger.info('md5 of %s: %s' %
                         (self.file_name, self.file_md5))

        params['client_id'] = self.client_id # client_id
        params['access_token'] = self.access_token # access_token

        url = 'https://api.youku.com/uploads/create.json'
        r = requests.get(url, params=params)# 以get方法将文件信息发送到'https://api.youku.com/uploads/create.json'
        check_error(r, 201)
        result = r.json()
        log.debug("file--->vid:%s,return_result:%s" % (self.v_vid, result))
        self.upload_token = result['upload_token']
        self.logger.info('upload token of %s: %s' %
                         (self.file_name, self.upload_token))
        self.upload_server_ip = socket.gethostbyname(
            result['upload_server_uri'])
        self.logger.info('upload_server_ip of %s: %s' %
                         (self.file_name, self.upload_server_ip))
        log.debug("file_vid:%s ip:%s" % (self.v_vid, self.upload_server_ip))
    def _save_upload_state_to_file(self):
        """if create and create_file has execute, save upload state
        to file for next resume upload if current upload process is
        interrupted.
        """
        # 保存文件的上传信息,先判断文件是否可写、可读、可执行
        # 保存的信息包括文件的上传upload_token.上传到的服务器ip
        # 保存的文件会在上传完毕之后删除
        if os.access(self.file_dir, os.W_OK | os.R_OK | os.X_OK):
            save_file = '/tmp' + 'youku.upload'
            data = {
                'upload_token': self.upload_token,
                'upload_server_ip': self.upload_server_ip
            }
            with open(save_file, 'w') as f:
                json.dump(data, f)

    def _read_upload_state_from_file(self):
        save_file = '/tmp' + 'youku.upload'
        try:
            with open(save_file) as f:
                data = json.load(f)
                self.upload_token = data['upload_token']
                self.upload_server_ip = data['upload_server_ip']
                # check upload_token expired
                try:
                    self.check()
                except YoukuError, e:
                    if e.code == 120010223:
                        # Expired upload token
                        self.upload_token = None
                        self.upload_server_ip = None
                        self._delete_upload_state_file()
        except:
            pass

    def _delete_upload_state_file(self):
        try:
            os.remove('/tmp' + 'youku.upload')
        except:
            pass

    def checksum_md5file(self, filename):
        md5 = hashlib.md5()
        with open(filename, 'rb') as f:
            for chunk in iter(lambda: f.read(8192), b''):
                md5.update(chunk)
        return md5.hexdigest()

    def checksum_md5data(self, data):
        md5 = hashlib.md5()
        md5.update(data)
        return md5.hexdigest()

    def create_file(self):
        params = {
            'upload_token': self.upload_token,
            'file_size': self.file_size,  # Byte
            'ext': self.file_ext,
            'slice_length': 2048  # KB
        }
        # 上传文件每次传2048KB
        url = 'http://%s/gupload/create_file' % self.upload_server_ip
        r = requests.post(url, data=params)
        check_error(r, 201)

        # save upload state to resume upload
        self._save_upload_state_to_file()

    def new_slice(self):
        params = {
            'upload_token': self.upload_token
        }
        url = 'http://%s/gupload/new_slice' % self.upload_server_ip
        r = requests.get(url, params=params)
        check_error(r, 201)
        self._save_slice_state(r.json())

    def _save_slice_state(self, result):
        # 更新切片状态
        self.slice_task_id = result['slice_task_id']
        self.slice_offset = result['offset']
        self.slice_length = result['length']
        self.transferred = result['transferred']
        self.finished = result['finished']

    def upload_slice(self):
        # 上传文件切片  seek():移动文件读取指针到指定位置

        data = None
        with open(self.file, 'rb') as f:
            f.seek(self.slice_offset)
            data = f.read(self.slice_length) # 2048
        params = {
            'upload_token': self.upload_token,
            'slice_task_id': self.slice_task_id,
            'offset': self.slice_offset,
            'length': self.slice_length,  # Byte
            'hash': self.checksum_md5data(data)
        }
        url = 'http://%s/gupload/upload_slice' % self.upload_server_ip
        r = requests.post(url, params=params, data=data)
        check_error(r, 201)
        self._save_slice_state(r.json())

    def check(self):
        params = {
            'upload_token': self.upload_token
        }
        url = 'http://%s/gupload/check' % self.upload_server_ip
        r = requests.get(url, params=params)
        check_error(r, 200)
        return r.json()

    def commit(self):
        status = self.check()# 检查上传状态
        if status['status'] == 4:
            raise ValueError('upload has not complete, should not commit')
        while status['status'] != 1:  # status is 2 or 3
            sleep(10)
            status = self.check()

        params = {
            'access_token': self.access_token,
            'client_id': self.client_id,
            'upload_token': self.upload_token,
            'upload_server_ip': status['upload_server_ip']
        }
        url = 'https://api.youku.com/uploads/commit.json'
        r = requests.post(url, data=params)
        check_error(r, 200)
        self.finished = True
        self._delete_upload_state_file()# 删除记录视频上传信息的文件
        log.debug("sdk---->vid:%s youku video_id:%s" % (self.v_vid, r.json()['video_id']))
        return r.json()['video_id']

    def cancel(self):
        status = self.check()
        params = {
            'access_token': self.access_token,
            'client_id': self.client_id,
            'upload_token': self.upload_token,
            'upload_server_ip': status['upload_server_ip']
        }
        url = 'https://api.youku.com/uploads/cancel.json'
        r = requests.get(url, params=params)
        check_error(r, 200)
        self._delete_upload_state_file()
        return r.json()['upload_token']

    def spec(self):
        url = 'https://api.youku.com/schemas/upload/spec.json'
        r = requests.get(url)
        check_error(r, 200)
        return r.json()

    def transferred_percent(self):
        """return current transferred percent
        """
        return int(self.transferred / self.file_size)

    def upload(self, params={}):
        """start uploading the file until upload is complete or error.
           This is the main method to used, If you do not care about
           state of process.

           Args:
                params: a dict object describe video info, eg title,
                tags, description, category.
                all video params see the doc of prepare_video_params.

           Returns:
                return video_id if upload successfully
        """
        if self.upload_token is not None:
            # resume upload
            status = self.check()
            if status['status'] != 4:
                return self.commit()
            else:
                self.new_slice()
                while self.slice_task_id != 0:
                    self.upload_slice()
                return self.commit()
        else:
            # new upload
            try:
                log.debug('youku upload params:%s' % params) # 记录上传参数
            except Exception as e:
                pass
            self.create(self.prepare_video_params(**params)) # 创建上传
            self.create_file()
            self.new_slice()
            while self.slice_task_id != 0:
                self.upload_slice()
            return self.commit()

--结束END--

本文标题: 优酷上传SDK解析(Python)

本文链接: https://lsjlt.com/news/182144.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 优酷上传SDK解析(Python)
      1.优酷上传   1)调用优酷的sdk完成优酷视频的上传首先需要将实例化YoukuUpload类实例化,传入的参数为(client_id,access_token,文件地址) 实例化时执行__init__()   2)实例化完成后得...
    99+
    2023-01-31
    上传 SDK Python
  • Python SDK怎么实现私服上传下载
    本篇内容介绍了“Python SDK怎么实现私服上传下载”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!编写Python SDK代码...
    99+
    2023-06-21
  • Python SDK实现私服上传下载的示例
    目录编写Python SDK代码打包并上传私服创建虚拟环境,并下载私服包进行验证编写Python SDK代码 工程目录结构 ├──── easyhttp ...
    99+
    2024-04-02
  • Android WebView 上传文件支持全解析
    默认情况下情况下,使用Android的WebView是不能够支持上传文件的。而这个,也是在我们的前端工程师告知之后才了解的。因为Android的每个版本WebView的实现有差...
    99+
    2022-06-06
    上传文件 webview Android
  • 全面解析SpringBoot文件上传功能
    这些天忙着刷题,又怕遗忘了spring boot, 所以抽出一点时间折腾折腾,加深点印象。 spring boot 的文件上传与 spring mvc 的文件上传基本一致,只需注意一些配置即可。 环境要求: Spring Boot v1.5...
    99+
    2023-05-30
    springboot 文件上传 bo
  • 全面解析node 表单的图片上传
    node 全面解析表单的图片上传 ,multiparty解析与内容类型的HTTP请求multipart/form-data,也被称为文件上传。 multiparty安装 npm install mult...
    99+
    2022-06-04
    表单 图片上传 node
  • java编程ThreadLocal上下传递源码解析
    目录引导语1、用法演示2、类结构2.1、类泛型2.2、关键属性2.2.1、ThreadLocalMap3、ThreadLocal 是如何做到线程之间数据隔离的4、set 方法&nbs...
    99+
    2024-04-02
  • 解析为什么github上传不了图片
    GitHub 是一个开源的代码托管平台,它提供了许多功能实用的工具,使开发人员可以更加方便地管理代码并与他人协作。然而,有时我们会发现在上传图片到 GitHub 时会遇到一些问题,比如图片无法正常显示或者上传失败等。那么,为什么 GitHu...
    99+
    2023-10-22
  • SpringBoot上传和下载文件的原理解析
    技术概述 我们的项目是实现一个论坛。在论坛上发布博客时应该要可以上传文件,用户阅读博客是应该要可以下载文件。于是我去学习了SpringBoot的上传和下载文件,我感觉技术的难点在于使...
    99+
    2024-04-02
  • 文件上传靶场-Nginx文件解析漏洞
    目录 1.靶场漏洞说明 2.漏洞利用过程 1.靶场漏洞说明 靶场地址:http://106.15.50.112:8020/ 一个简单的Nginx文件上传靶场,php配置中将cgi.fix_pathinfo设置为1,如果我们设置一个文件路径...
    99+
    2023-09-25
    php web安全 nginx 网络安全 学习
  • Android源码解析--享元设计模式,handler消息传递机制(基于Android API 33 SDK分析)
    文章目录 Android源码解析--享元设计模式,handler消息传递机制(基于Android API 33 SDK分析)一. 定义1.1 享元模式Demo 二. Android中源码...
    99+
    2023-08-31
    android 设计模式
  • python通过http上传文件思路详解
    这里主要是解决multipart/form-data这种格式的文件上传,基本现在http协议上传文件基本上都是通过这种格式上传 1 思路 一般情况下,如果我们往一个地址上传文件,则必...
    99+
    2024-04-02
  • 如何使用Python NumPy在Unix系统上优化HTTP传输?
    在当今的数字时代中,HTTP传输是非常重要的一种数据传输方式。然而,由于网络环境的不可控性以及传输数据的大小和复杂度,HTTP传输的效率往往受到一定的限制。为了更好地解决这个问题,我们可以使用Python NumPy库在Unix系统上进行优...
    99+
    2023-06-24
    numpy unix http
  • 详解Python下ftp上传文件linux服务器
    模块介绍: from ftplib import FTP ftp = FTP() #设置变量 ftp.set_debuglevel(2) #打开调试级别2 显示详细信息 ftp.connect("IP", "p...
    99+
    2022-06-04
    Python ftp linux
  • 优化 HTTP 传输:Python 重定向技术详解
    HTTP 重定向是一个常见的 Web 开发技术,它可以让用户在访问网站时自动跳转到另一个页面。在实际应用中,我们经常需要使用 Python 来实现 HTTP 重定向功能。本文将介绍 Python 重定向技术的实现原理和具体操作,帮助读者快...
    99+
    2023-11-06
    重定向 大数据 http
  • python人工智能遗传算法示例解析
    目录一、实验目的二、实验原理三、实验条件四、实验内容五、实验结果一、实验目的 熟悉和掌握遗传算法的原理、流程和编码策略,并利用遗传求解函数优化问题,理解求解流程并测试主要参数对结果的...
    99+
    2024-04-02
  • 详解Python如何优雅地解析命令行
    目录1. 手动解析2. getopt模块总结如何优雅地解析命令行选项 随着我们编程经验的增长,对命令行的熟悉程度日渐加深,想来很多人会渐渐地体会到使用命令行带来的高效率。 自然而然地...
    99+
    2024-04-02
  • java进阶解析Springboot上传excel存入数据库步骤
    目录一、导入依赖二、前端实现三、后台逻辑三、页面效果四、可能会遇到的问题一、导入依赖 这里还是用了Apache的POI插件,现在一般的springboot解析excel基本都用它 。...
    99+
    2024-04-02
  • SpringMvc3+extjs4实现上传与下载功能的代码解析
    这篇文章主要讲解了SpringMvc3+extjs4实现上传与下载功能的代码解析,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。本文实例为大家分享了SpringMvc3+extjs4实现上传与下载的具体代码,供大...
    99+
    2023-05-31
    springmvc3 extjs4
  • 文件上传漏洞基础/htaccess重写解析绕过/大小写绕过上传/windows特性绕过
    目录 一、htaccess重写解析绕过上传 htaccess文件 htaccess文件上传 靶场练习pass-04 代码分析 创建.htaccess文件 开始上传 访问 二、大小写绕过 upload-labs pass-05 代码分析 上...
    99+
    2023-09-02
    安全 web安全 网络安全 php
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作