1.优酷上传

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

实例化时执行__init__()

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

  3)在upload方法中

    

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

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

  1. def prepare_video_params(self, title=None, tags='Others', description='',
  2. copyright_type='original', public_type='all',
  3. category=None, watch_password=None,
  4. latitude=None, longitude=None, shoot_time=None
  5. ):
  6. # 准备视频所以需要的一些参数
  7. params = {}
  8. if title is None:
  9. # 如果没有传title的话,title默认等于文件名
  10. title = self.file_name
  11. elif len(title) > 50:
  12. # 如果title过长,长度大于50的话,就截取前50个字符作为title
  13. title = title[:50]
  14. params['title'] = title
  15. params['tags'] = tags
  16. # tags就等于你传进来的那个tags,默认为others
  17. params['description'] = description
  18. # 描述默认为空,可以传进来
  19. params['copyright_type'] = copyright_type
  20. # 版权所有 original: 原创 reproduced: 转载
  21. params['public_type'] = public_type
  22. # 公开类型 all: 公开 friend: 仅好友观看 password: 输入密码观看 private: 私有
  23. if category:
  24. params['category'] = category
  25. # 视频分类 默认为空,可传
  26. if watch_password:
  27. params['watch_password'] = watch_password
  28. # 观看密码,默认为空,可传
  29. """
  30. latitude/longitude用户记录地理位置信息
  31. shoot_time用来标记视频中正片的开始时间
  32. """
  33. if latitude:
  34. params['latitude'] = latitude
  35. # 纬度
  36. if longitude:
  37. params['longitude'] = longitude
  38. # 经度
  39. if shoot_time:
  40. params['shoot_time'] = shoot_time
  41. log.debug("prepare_video_params:%s" % params)
  42. return params

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

  1. def create(self, params):
  2. # prepare file info
  3. params['file_name'] = self.file_name
  4. params['file_size'] = self.file_size # 在__init__中获取到了,也就是在类的实例化时就已经根据文件的地址获取了文件的大小
  5. params['file_md5'] = self.file_md5 = self.checksum_md5file(self.file)
  6. # 将文件信息做md5 校验,根据文件名打开文件,然后每次读取8192B,进行md5更新后再转为十六进制返回
  7. self.logger.info('upload file %s, size: %d bytes' %
  8. (self.file_name, self.file_size))
  9. self.logger.info('md5 of %s: %s' %
  10. (self.file_name, self.file_md5))
  11.  
  12. params['client_id'] = self.client_id # client_id
  13. params['access_token'] = self.access_token # access_token
  14.  
  15. url = 'https://api.youku.com/uploads/create.json'
  16. r = requests.get(url, params=params)# get方法将文件信息发送到'https://api.youku.com/uploads/create.json'
  17. check_error(r, 201)
  18. result = r.json()
  19. log.debug("file--->vid:%s,return_result:%s" % (self.v_vid, result))
  20. self.upload_token = result['upload_token']
  21. self.logger.info('upload token of %s: %s' %
  22. (self.file_name, self.upload_token))
  23. self.upload_server_ip = socket.gethostbyname(
  24. result['upload_server_uri'])
  25. self.logger.info('upload_server_ip of %s: %s' %
  26. (self.file_name, self.upload_server_ip))
  27. 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进行上传。

  1. def upload_slice(self):
  2. # 上传文件切片 seek():移动文件读取指针到指定位置
  3.  
  4. data = None
  5. with open(self.file, 'rb') as f:
  6. f.seek(self.slice_offset)
  7. data = f.read(self.slice_length) #
  8. params = {
  9. 'upload_token': self.upload_token,
  10. 'slice_task_id': self.slice_task_id,
  11. 'offset': self.slice_offset,
  12. 'length': self.slice_length, # Byte
  13. 'hash': self.checksum_md5data(data)# hash这个字段是为了在服务端进行校验,来验证上传的文件有没有出现丢失或错误
  14. }
  15. url = 'http://%s/gupload/upload_slice' % self.upload_server_ip
  16. r = requests.post(url, params=params, data=data)
  17. check_error(r, 201)
  18. self._save_slice_state(r.json())

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

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

2. 完整优酷上传sdk代码  

  1. """Youku cloud Python Client
  2.  
  3. doc: http://cloud.youku.com/docs/doc?id=110
  4. """
  5.  
  6. import os
  7. import requests
  8. import json
  9. import time
  10. import hashlib
  11. import socket
  12. import logging
  13. from time import sleep
  14. from util import check_error, YoukuError
  15.  
  16. if not os.path.exists('/var/log/youku/'):
  17. os.makedirs('/var/log/youku')
  18. log = logging.getLogger()
  19. log.setLevel(logging.DEBUG)
  20. fmt = logging.Formatter("%(asctime)s %(pathname)s %(filename)s %(funcName)s %(lineno)s %(levelname)s - %(message)s",
  21. "%Y-%m-%d %H:%M:%S")
  22. stream_handler = logging.FileHandler(
  23. '/var/log/youku/debug-%s.log' % (time.strftime('%Y-%m-%d', time.localtime(time.time()))))
  24. stream_handler.setLevel(logging.DEBUG)
  25. stream_handler.setFormatter(fmt)
  26. log.addHandler(stream_handler)
  27.  
  28. class YoukuUpload(object):
  29. """Youku Upload Client.
  30.  
  31. Upload file to Youku Video. Support resume upload if interrupted.
  32. Should use one instance of YoukuUpload for one upload file in one thread,
  33. since it has internal state of upload process.
  34.  
  35. doc: http://cloud.youku.com/docs/doc?id=110
  36. """
  37.  
  38. def __init__(self, client_id, access_token, file, v_vid = None, logger=None):
  39. """
  40. Args:
  41. file: string, include path and filename for open(). filename
  42. must contain video file extension.
  43. """
  44. super(YoukuUpload, self).__init__()
  45. self.client_id = client_id
  46. self.access_token = access_token
  47. self.v_vid = v_vid # 上传的视频id号
  48. self.logger = logger or logging.getLogger(__name__)
  49.  
  50. # file info
  51. self.file = file
  52. self.file_size = os.path.getsize(self.file) # int 获取文件的大小
  53. self.file_dir, self.file_name = os.path.split(self.file) # string 分割路径来获取文件名
  54. if self.file_dir == '':
  55. self.file_dir = '.'
  56. self.file_ext = self.file_name.rsplit('.', 1)[1], # file extension
  57. self.file_md5 = None # string, do later
  58.  
  59. # upload state
  60. self.upload_token = None # string
  61. self.upload_server_ip = None # string
  62. self.slice_task_id = None # int
  63. self.slice_offset = None # int
  64. self.slice_length = None # int
  65. self.transferred = None # int for bytes has uploaded
  66. self.finished = False # boolean
  67.  
  68. # resume upload state
  69. self._read_upload_state_from_file()
  70.  
  71. def prepare_video_params(self, title=None, tags='Others', description='',
  72. copyright_type='original', public_type='all',
  73. category=None, watch_password=None,
  74. latitude=None, longitude=None, shoot_time=None
  75. ):
  76. # 准备视频所以需要的一些参数
  77. """ util method for create video params to upload.
  78.  
  79. Only need to provide a minimum of two essential parameters:
  80. title and tags, other video params are optional. All params spec
  81. see: http://cloud.youku.com/docs?id=110#create .
  82.  
  83. Args:
  84. title: string, 2-50 characters.
  85. tags: string, 1-10 tags joind with comma.
  86. description: string, less than 2000 characters.
  87. copyright_type: string, 'original' or 'reproduced'
  88. public_type: string, 'all' or 'friend' or 'password'
  89. watch_password: string, if public_type is password.
  90. latitude: double.
  91. longitude: double.
  92. shoot_time: datetime.
  93.  
  94. Returns:
  95. dict params that upload/create method need.
  96. """
  97. params = {}
  98. if title is None:
  99. # 如果没有传title的话,title默认等于文件名
  100. title = self.file_name
  101. elif len(title) > 50:
  102. # 如果title过长,长度大于50的话,就截取前50个字符作为title
  103. title = title[:50]
  104. params['title'] = title
  105. params['tags'] = tags
  106. # tags就等于你传进来的那个tags,默认为others
  107. params['description'] = description
  108. # 描述默认为空,可以传进来
  109. params['copyright_type'] = copyright_type
  110. # 版权所有 original: 原创 reproduced: 转载
  111. params['public_type'] = public_type
  112. # 公开类型 all: 公开 friend: 仅好友观看 password: 输入密码观看 private: 私有
  113. if category:
  114. params['category'] = category
  115. # 视频分类 默认为空,可传
  116. if watch_password:
  117. params['watch_password'] = watch_password
  118. # 观看密码,默认为空,可传
  119. """
  120. latitude/longitude用户记录地理位置信息
  121. shoot_time用来标记视频中正片的开始时间
  122. """
  123. if latitude:
  124. params['latitude'] = latitude
  125. # 纬度
  126. if longitude:
  127. params['longitude'] = longitude
  128. # 经度
  129. if shoot_time:
  130. params['shoot_time'] = shoot_time
  131. log.debug("prepare_video_params:%s" % params)
  132. return params
  133.  
  134. def create(self, params):
  135. # prepare file info
  136. params['file_name'] = self.file_name
  137. params['file_size'] = self.file_size # 在__init__中获取到了,也就是在类的实例化时就已经根据文件的地址获取了文件的大小
  138. params['file_md5'] = self.file_md5 = self.checksum_md5file(self.file)
  139. # 将文件信息做md5 校验,根据文件名打开文件,然后每次读取8192B,进行md5更新后再转为十六进制返回
  140. self.logger.info('upload file %s, size: %d bytes' %
  141. (self.file_name, self.file_size))
  142. self.logger.info('md5 of %s: %s' %
  143. (self.file_name, self.file_md5))
  144.  
  145. params['client_id'] = self.client_id # client_id
  146. params['access_token'] = self.access_token # access_token
  147.  
  148. url = 'https://api.youku.com/uploads/create.json'
  149. r = requests.get(url, params=params)# get方法将文件信息发送到'https://api.youku.com/uploads/create.json'
  150. check_error(r, 201)
  151. result = r.json()
  152. log.debug("file--->vid:%s,return_result:%s" % (self.v_vid, result))
  153. self.upload_token = result['upload_token']
  154. self.logger.info('upload token of %s: %s' %
  155. (self.file_name, self.upload_token))
  156. self.upload_server_ip = socket.gethostbyname(
  157. result['upload_server_uri'])
  158. self.logger.info('upload_server_ip of %s: %s' %
  159. (self.file_name, self.upload_server_ip))
  160. log.debug("file_vid:%s ip:%s" % (self.v_vid, self.upload_server_ip))
  161. def _save_upload_state_to_file(self):
  162. """if create and create_file has execute, save upload state
  163. to file for next resume upload if current upload process is
  164. interrupted.
  165. """
  166. # 保存文件的上传信息,先判断文件是否可写、可读、可执行
  167. # 保存的信息包括文件的上传upload_token.上传到的服务器ip
  168. # 保存的文件会在上传完毕之后删除
  169. if os.access(self.file_dir, os.W_OK | os.R_OK | os.X_OK):
  170. save_file = '/tmp' + 'youku.upload'
  171. data = {
  172. 'upload_token': self.upload_token,
  173. 'upload_server_ip': self.upload_server_ip
  174. }
  175. with open(save_file, 'w') as f:
  176. json.dump(data, f)
  177.  
  178. def _read_upload_state_from_file(self):
  179. save_file = '/tmp' + 'youku.upload'
  180. try:
  181. with open(save_file) as f:
  182. data = json.load(f)
  183. self.upload_token = data['upload_token']
  184. self.upload_server_ip = data['upload_server_ip']
  185. # check upload_token expired
  186. try:
  187. self.check()
  188. except YoukuError, e:
  189. if e.code == 120010223:
  190. # Expired upload token
  191. self.upload_token = None
  192. self.upload_server_ip = None
  193. self._delete_upload_state_file()
  194. except:
  195. pass
  196.  
  197. def _delete_upload_state_file(self):
  198. try:
  199. os.remove('/tmp' + 'youku.upload')
  200. except:
  201. pass
  202.  
  203. def checksum_md5file(self, filename):
  204. md5 = hashlib.md5()
  205. with open(filename, 'rb') as f:
  206. for chunk in iter(lambda: f.read(8192), b''):
  207. md5.update(chunk)
  208. return md5.hexdigest()
  209.  
  210. def checksum_md5data(self, data):
  211. md5 = hashlib.md5()
  212. md5.update(data)
  213. return md5.hexdigest()
  214.  
  215. def create_file(self):
  216. params = {
  217. 'upload_token': self.upload_token,
  218. 'file_size': self.file_size, # Byte
  219. 'ext': self.file_ext,
  220. 'slice_length': 2048 # KB
  221. }
  222. # 上传文件每次传2048KB
  223. url = 'http://%s/gupload/create_file' % self.upload_server_ip
  224. r = requests.post(url, data=params)
  225. check_error(r, 201)
  226.  
  227. # save upload state to resume upload
  228. self._save_upload_state_to_file()
  229.  
  230. def new_slice(self):
  231. params = {
  232. 'upload_token': self.upload_token
  233. }
  234. url = 'http://%s/gupload/new_slice' % self.upload_server_ip
  235. r = requests.get(url, params=params)
  236. check_error(r, 201)
  237. self._save_slice_state(r.json())
  238.  
  239. def _save_slice_state(self, result):
  240. # 更新切片状态
  241. self.slice_task_id = result['slice_task_id']
  242. self.slice_offset = result['offset']
  243. self.slice_length = result['length']
  244. self.transferred = result['transferred']
  245. self.finished = result['finished']
  246.  
  247. def upload_slice(self):
  248. # 上传文件切片 seek():移动文件读取指针到指定位置
  249.  
  250. data = None
  251. with open(self.file, 'rb') as f:
  252. f.seek(self.slice_offset)
  253. data = f.read(self.slice_length) #
  254. params = {
  255. 'upload_token': self.upload_token,
  256. 'slice_task_id': self.slice_task_id,
  257. 'offset': self.slice_offset,
  258. 'length': self.slice_length, # Byte
  259. 'hash': self.checksum_md5data(data)
  260. }
  261. url = 'http://%s/gupload/upload_slice' % self.upload_server_ip
  262. r = requests.post(url, params=params, data=data)
  263. check_error(r, 201)
  264. self._save_slice_state(r.json())
  265.  
  266. def check(self):
  267. params = {
  268. 'upload_token': self.upload_token
  269. }
  270. url = 'http://%s/gupload/check' % self.upload_server_ip
  271. r = requests.get(url, params=params)
  272. check_error(r, 200)
  273. return r.json()
  274.  
  275. def commit(self):
  276. status = self.check()# 检查上传状态
  277. if status['status'] == 4:
  278. raise ValueError('upload has not complete, should not commit')
  279. while status['status'] != 1: # status is 2 or 3
  280. sleep(10)
  281. status = self.check()
  282.  
  283. params = {
  284. 'access_token': self.access_token,
  285. 'client_id': self.client_id,
  286. 'upload_token': self.upload_token,
  287. 'upload_server_ip': status['upload_server_ip']
  288. }
  289. url = 'https://api.youku.com/uploads/commit.json'
  290. r = requests.post(url, data=params)
  291. check_error(r, 200)
  292. self.finished = True
  293. self._delete_upload_state_file()# 删除记录视频上传信息的文件
  294. log.debug("sdk---->vid:%s youku video_id:%s" % (self.v_vid, r.json()['video_id']))
  295. return r.json()['video_id']
  296.  
  297. def cancel(self):
  298. status = self.check()
  299. params = {
  300. 'access_token': self.access_token,
  301. 'client_id': self.client_id,
  302. 'upload_token': self.upload_token,
  303. 'upload_server_ip': status['upload_server_ip']
  304. }
  305. url = 'https://api.youku.com/uploads/cancel.json'
  306. r = requests.get(url, params=params)
  307. check_error(r, 200)
  308. self._delete_upload_state_file()
  309. return r.json()['upload_token']
  310.  
  311. def spec(self):
  312. url = 'https://api.youku.com/schemas/upload/spec.json'
  313. r = requests.get(url)
  314. check_error(r, 200)
  315. return r.json()
  316.  
  317. def transferred_percent(self):
  318. """return current transferred percent
  319. """
  320. return int(self.transferred / self.file_size)
  321.  
  322. def upload(self, params={}):
  323. """start uploading the file until upload is complete or error.
  324. This is the main method to used, If you do not care about
  325. state of process.
  326.  
  327. Args:
  328. params: a dict object describe video info, eg title,
  329. tags, description, category.
  330. all video params see the doc of prepare_video_params.
  331.  
  332. Returns:
  333. return video_id if upload successfully
  334. """
  335. if self.upload_token is not None:
  336. # resume upload
  337. status = self.check()
  338. if status['status'] != 4:
  339. return self.commit()
  340. else:
  341. self.new_slice()
  342. while self.slice_task_id != 0:
  343. self.upload_slice()
  344. return self.commit()
  345. else:
  346. # new upload
  347. try:
  348. log.debug('youku upload params:%s' % params) # 记录上传参数
  349. except Exception as e:
  350. pass
  351. self.create(self.prepare_video_params(**params)) # 创建上传
  352. self.create_file()
  353. self.new_slice()
  354. while self.slice_task_id != 0:
  355. self.upload_slice()
  356. return self.commit()

优酷上传SDK解析(Python)的更多相关文章

  1. IT轮子系列(六)——Excel上传与解析,一套代码解决所有Excel业务上传,你Get到了吗

    前言 在日常开发当中,excel的上传与解析是很常见的.根据业务不同,解析的数据模型也都不一样.不同的数据模型也就需要不同的校验逻辑,这往往需要写多套的代码进行字段的检验,如必填项,数据格式.为了避免 ...

  2. php文件上传代码解析

    php文件上传代码解析 is_uploaded_file()  //函数判断指定的文件是否是通过 HTTP POST 上传的,返回一个布尔值. $_FILES['upfile']['tmp_name' ...

  3. Web攻防系列教程之文件上传攻防解析(转载)

    Web攻防系列教程之文件上传攻防解析: 文件上传是WEB应用很常见的一种功能,本身是一项正常的业务需求,不存在什么问题.但如果在上传时没有对文件进行正确处理,则很可能会发生安全问题.本文将对文件上传的 ...

  4. springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用

    一.问题描述为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter.目的是让MultipartFi ...

  5. java 文件上传与解析(excel,txt)

    excel上传与解析 https://blog.csdn.net/zsysu_it/article/details/79074067 txt解析 https://blog.csdn.net/CSDNw ...

  6. salesforce lightning零基础学习(十七) 实现上传 Excel解析其内容

    本篇参考: https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader https://github.com/SheetJS/sheetjs ...

  7. Salesforce LWC学习(三十二)实现上传 Excel解析其内容

    本篇参考:salesforce lightning零基础学习(十七) 实现上传 Excel解析其内容 上一篇我们写了aura方式上传excel解析其内容.lwc作为salesforce的新宠儿,逐渐的 ...

  8. 实现Excel文件的上传和解析

    前言 本文思维导图 一.需求描述 实现一个页面上传excel的功能,并对excel中的内容做解析,最后存储在数据库中. 二.代码实现 需求实现思路: 先对上传的文件做校验和解析,这里我们通过Excel ...

  9. 上传自己的Python代码到PyPI

    一.需要准备的事情 1.当然是自己的Python代码包了: 2.注册PyPI的一个账号. 二.详细介绍 1.代码包的结构: application \application __init__.py m ...

随机推荐

  1. 使用C#利用cmd来调用java jar包获取其中的数据

    其实也很简单,就是在C#中构建一个Process,启动jar包,并且给jar包传递参数 因为我并没有怎么学过JAVA,所以只写了个很小的Demo,就是根据传入的参数获取对应的数据 以下是JAVA De ...

  2. Docker(二):微服务教程

    Docker 是一个容器工具,提供虚拟环境.很多人认为,它改变了我们对软件的认识. 站在 Docker 的角度,软件就是容器的组合:业务逻辑容器.数据库容器.储存容器.队列容器......,Docke ...

  3. 关于pycharm 打不开某些文件夹和文件打不开的问题

    在使用pycharm的时候遇到了一个情况, 下载了一个文件,自己修改了文件夹名称后再打开文件夹里的py文件, 打不开了,pycharm没有反应, 百度了一下,没有类似的问题,觉得应该是个个例... 然 ...

  4. 基于Maven + SSM (Spring、SpringMVC、Mybatis)构建一个简单的测试项目

    最近在公司实习期间的培训交流中有机会接触到SSM,然后自己花费1周的时间投入学习.谈不上深刻理解其中原理,所以没有涉及理论知识,只是浅层次的学习如何使用,在此将学习过程记录整理出来,一方面自己备用:另 ...

  5. Andoid多语言国际化策略

    目前手上的项目,为了普及覆盖更多的用户群,也已经开始实现了多语言设置这样的功能,不过今天我要说的不是微信,而是我们自己项目中的实现策略. 直接附上关键代码: package com.huolonglu ...

  6. TOMCAT配置SSL认证为HTTPS协议服务

     1 . 问题概述 很多安全性要求较高的系统,都会使用安全套接字层(SSL)进行信息交换, Sun为了解决在Internet上的实现安全信息传输的解决方案.它实现了SSL和TSL(传输层安全)协议 ...

  7. idea 导入Mapper错误报错设置

    这个报错如图: 其实这个报错是错误,因为运行一切正常. 解决办法:

  8. shiro web 集成

    集成方法 shiro与web集成,主要是通过配置一个ShiroFilter拦截所有URL,其中ShiroFilter类似于SpringMVC的前端控制器,是所有请求入口点,负责根据配置(如ini配置文 ...

  9. VIM 乱码终极解决

    原文链接:http://blog.163.com/mageng11@126/blog/static/1408083742012128105645169/ 关于vim乱码,这篇文章讲的很详细,mark一 ...

  10. 回归JavaScript基础(二)

    主题:在HTML中使用JavaScript. 要想把JavaScript放到网页中,就必须涉及到Web的核心语言HTML.向HTML页面中插入JavaScript的主要方法,就是使用<scrip ...