You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

257 line
12KB

  1. # -*- coding: utf-8 -*-
  2. from json import loads
  3. from os.path import join, exists
  4. from traceback import format_exc
  5. import time
  6. from aliyunsdkcore.client import AcsClient
  7. from loguru import logger
  8. from enums.ExceptionEnum import ExceptionType
  9. from exception.CustomerException import ServiceException
  10. from osssdk import Auth, Bucket, ResumableStore
  11. from osssdk.resumable import resumable_upload1
  12. from util.FileUtil import create_dir
  13. from util.RWUtils import getConfigs
  14. from vodsdk.AliyunVodUploader import AliyunVodUploader
  15. from vodsdk.UploadVideoRequest import UploadVideoRequest
  16. from aliyunsdkvod.request.v20170321.GetPlayInfoRequest import GetPlayInfoRequest
  17. class OssUtil:
  18. __slots__ = ('bucket', '__base_dir', '__config', 'progress', 'image_url', 'exception', "status")
  19. def __init__(self, base_dir):
  20. self.bucket = None
  21. self.__base_dir = base_dir
  22. self.__config = getConfigs(base_dir, 'config/aliyun.yml')
  23. self.progress = "0.0000"
  24. self.image_url = ""
  25. self.exception = None
  26. self.status = False
  27. def get_oss_bucket(self):
  28. if self.bucket is None:
  29. logger.info("初始化oss桶")
  30. auth = Auth(self.__config["access_key"], self.__config["access_secret"])
  31. self.bucket = Bucket(auth, self.__config["oss"]["endpoint"], self.__config["oss"]["bucket"])
  32. def percentage(self, useData, consumed_bytes, total_bytes):
  33. if total_bytes:
  34. # filePath = useData
  35. rate = round(float(float(consumed_bytes) / float(total_bytes)), 4)
  36. self.progress = str(rate)
  37. # logger.info("{}文件上传任务进度: {}", filePath, rate)
  38. """
  39. 上传本地文件
  40. """
  41. def put_object_from_file(self, uploadPath, filePath):
  42. logger.info("开始上传文件, key: {}, 文件: {}, ", uploadPath, filePath)
  43. MAX_RETRIES = 3
  44. retry_count = 0
  45. while True:
  46. try:
  47. self.progress = "0.0000"
  48. if not exists(filePath):
  49. break
  50. self.get_oss_bucket()
  51. useData = filePath
  52. resp = self.bucket.put_object_from_file_1(uploadPath, filePath, progress_callback=self.percentage,
  53. useData=useData)
  54. if resp.status == 200:
  55. self.image_url = join(self.__config['oss']['host_url'], uploadPath)
  56. self.progress = "1.0000"
  57. else:
  58. raise Exception("上传文件失败")
  59. logger.info("上传文件到oss成功! key: {}, filePath:{}, 状态码: {}", uploadPath, filePath, resp.status)
  60. break
  61. except Exception as e:
  62. self.bucket = None
  63. retry_count += 1
  64. time.sleep(1)
  65. logger.info("上传文件到oss失败, 重试次数:{}, key: {}, filePath:{}", uploadPath, filePath)
  66. if retry_count > MAX_RETRIES:
  67. logger.error("上传文件到oss重试失败:{}, key: {}, filePath:{}", format_exc(), uploadPath, filePath)
  68. raise e
  69. """
  70. 断点续传上传本地文件
  71. """
  72. def resumable_upload(self, uploadPath, filePath):
  73. logger.info("开始上传文件, key: {}, 文件: {}, ", uploadPath, filePath)
  74. MAX_RETRIES = 3
  75. retry_count = 0
  76. while True:
  77. try:
  78. self.progress = "0.0000"
  79. if not exists(filePath):
  80. break
  81. if self.status:
  82. break
  83. self.get_oss_bucket()
  84. useData = filePath
  85. size = 1024 * 1024 * 10
  86. tmp = join(join(self.__base_dir, "tmp"), 'oss')
  87. create_dir(tmp)
  88. resp = resumable_upload1(self.bucket, uploadPath, filePath,
  89. store=ResumableStore(root=tmp),
  90. multipart_threshold=size, part_size=size,
  91. progress_callback=self.percentage, num_threads=2, useData=useData)
  92. if resp.status == 200:
  93. self.image_url = "%s/%s" % (self.__config['oss']['host_url'], uploadPath)
  94. self.progress = "1.0000"
  95. else:
  96. raise Exception("上传文件失败")
  97. logger.info("上传文件到oss成功! key: {}, filePath:{}, 状态码: {}", uploadPath, filePath, resp.status)
  98. break
  99. except Exception as e:
  100. self.bucket = None
  101. retry_count += 1
  102. time.sleep(2)
  103. logger.info("上传文件到oss失败: {}, 重试次数:{}, key: {}, filePath:{}", format_exc(), retry_count,
  104. uploadPath, filePath)
  105. if retry_count > MAX_RETRIES:
  106. logger.error("上传文件到oss重试失败:{}, key: {}, filePath:{}", format_exc(), uploadPath, filePath)
  107. raise e
  108. def get_progress(self):
  109. return self.progress
  110. def get_image_url(self):
  111. return self.image_url
  112. class VodUtil:
  113. __slots__ = ('__config', 'progress', "__videoUrl", "exception", "uploader", "status")
  114. def __init__(self, base_dir):
  115. self.progress = "0.0000"
  116. self.__config = getConfigs(base_dir, 'config/aliyun.yml')
  117. self.__videoUrl = ""
  118. self.exception = None
  119. self.uploader = None
  120. self.status = False
  121. def init_vod_client(self, accessKeyId, accessKeySecret):
  122. regionId = self.__config["vod"]["ecsRegionId"]
  123. return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=60)
  124. def uploadProgressCallback(self, consumedBytes, totalBytes):
  125. try:
  126. if totalBytes:
  127. rate = round(float(float(consumedBytes) / float(totalBytes)), 4)
  128. else:
  129. rate = 0
  130. if rate != 0 and rate != 1:
  131. self.progress = str(rate)
  132. logger.info('视频上传中: {} bytes, percent:{}', consumedBytes, rate)
  133. except Exception as e:
  134. logger.exception("打印视频上传进度回调方法异常: {}", e)
  135. def get_play_info(self, videoId, filePath, file_title):
  136. logger.info("开始获取视频地址,videoId:{}, filePath: {}, file_title: {}", videoId, filePath, file_title)
  137. start = time.time()
  138. timeout = None
  139. retry_count = 0
  140. while True:
  141. try:
  142. if self.status:
  143. return ""
  144. if float(self.progress) < 0.8:
  145. self.progress = "0.8000"
  146. clt = self.init_vod_client(self.__config["access_key"],
  147. self.__config["access_secret"])
  148. request: GetPlayInfoRequest = GetPlayInfoRequest()
  149. request.set_accept_format('JSON')
  150. request.set_VideoId(videoId)
  151. request.set_AuthTimeout(3600 * 5)
  152. response = loads(clt.do_action_with_exception(request))
  153. play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"]
  154. logger.info("获取视频地址成功,视频地址: {}, file_title: {}", play_url, file_title)
  155. if play_url is None or len(play_url) == 0:
  156. raise Exception("获取视频地址失败")
  157. self.progress = "1.0000"
  158. return play_url
  159. except Exception as e:
  160. logger.info("获取视频地址失败,5秒后重试, 异常: {}, filePath:{}, file_title:{}", format_exc(), filePath,
  161. file_title)
  162. time.sleep(5)
  163. current_time = time.time()
  164. if "Uploading" in str(e):
  165. if timeout is None:
  166. timeout = time.time()
  167. if time.time() - timeout > 1800:
  168. logger.error("获取视频地址超时, filePath:{}, file_title:{}", filePath,
  169. file_title)
  170. raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
  171. ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
  172. if "UploadSucc" not in str(e) and "Transcoding" not in str(e) and "Uploading" not in str(e):
  173. retry_count += 1
  174. if retry_count > 3:
  175. logger.error("获取视频地址失败: {}, filePath:{}, file_title:{}", format_exc(), filePath, file_title)
  176. raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0],
  177. ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1])
  178. diff_time = current_time - start
  179. if diff_time > 60 * 60 * 5:
  180. logger.error("获取视频地址失败超时异常: {},超时时间:{}, filePath:{}, file_title:{}", format_exc(),
  181. diff_time, filePath, file_title)
  182. raise ServiceException(ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[0],
  183. ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[1])
  184. def upload_local_video(self, filePath, file_title):
  185. logger.info("开始执行vod视频上传, filePath: {}, fileTitle: {}", filePath, file_title)
  186. self.uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"],
  187. progress_callback=self.uploadProgressCallback)
  188. uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title)
  189. logger.info("视频分类:{}", self.__config["vod"]["cateId"])
  190. uploadVideoRequest.setCateId(self.__config["vod"]["cateId"])
  191. MAX_RETRIES = 3
  192. retry_count = 0
  193. while True:
  194. try:
  195. self.progress = "0.0000"
  196. if not exists(filePath):
  197. return None
  198. if self.status:
  199. return None
  200. result = self.uploader.uploadLocalVideo(uploadVideoRequest)
  201. if self.status:
  202. return None
  203. logger.info("vod视频上传成功, videoId:{}", result.get("VideoId"))
  204. return result.get("VideoId")
  205. except Exception:
  206. retry_count += 1
  207. time.sleep(1)
  208. logger.error("vod视频上传失败:{},重试次数:{}", format_exc(), retry_count)
  209. if retry_count >= MAX_RETRIES:
  210. raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
  211. ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
  212. def get_play_url(self, filePath, file_title):
  213. videoId = self.upload_local_video(filePath, file_title)
  214. if self.status:
  215. return
  216. if videoId is None or len(videoId) == 0:
  217. logger.error("上传视频失败!filePath: {}, file_title: {}", filePath, file_title)
  218. raise ServiceException(ExceptionType.UPLOAD_VIDEO_URL_EXCEPTION.value[0],
  219. ExceptionType.UPLOAD_VIDEO_URL_EXCEPTION.value[1])
  220. self.__videoUrl = self.get_play_info(videoId, filePath, file_title)
  221. def get_progress(self):
  222. return self.progress
  223. def get_video_url(self):
  224. return self.__videoUrl
  225. # if __name__ == "__main__":
  226. # vod = VodUtil(r"D:\tuoheng\codenew\tuoheng_airprt_media")
  227. # Thread(target=vod.get_play_url, args=(r"D:\test\video\222.mp4", 'aaa')).start()
  228. # while True:
  229. # time.sleep(1)
  230. # if vod.uploader:
  231. # print(vod.uploader.progress)