upload_video.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. import time
  2. import random
  3. import httplib
  4. import apiclient.http
  5. import httplib2
  6. import lib
  7. RETRIABLE_EXCEPTIONS = [
  8. httplib2.HttpLib2Error, IOError, httplib.NotConnected,
  9. httplib.IncompleteRead, httplib.ImproperConnectionState,
  10. httplib.CannotSendRequest, httplib.CannotSendHeader,
  11. httplib.ResponseNotReady, httplib.BadStatusLine,
  12. ]
  13. def with_retriable_exceptions(retriable_exceptions, max_retries=None):
  14. """Decorate a funcion with a a retry mechanism (exponential backoff)."""
  15. def _decorator(f):
  16. def _wrapper(*args, **kwargs):
  17. retry = 0
  18. while 1:
  19. try:
  20. return f(*args, **kwargs)
  21. except tuple(retriable_exceptions) as exc:
  22. retry += 1
  23. if type(exc) not in retriable_exceptions:
  24. raise exc
  25. elif max_retries is not None and retry > max_retries:
  26. lib.debug("Retry limit reached, time to give up")
  27. raise exc
  28. seconds = random.uniform(0, 2**retry)
  29. lib.debug("Retryable error {}/{}: {}. Waiting {} seconds".
  30. format(retry, max_retries or "inf", type(exc).__name__, seconds))
  31. time.sleep(seconds)
  32. return _wrapper
  33. return _decorator
  34. @with_retriable_exceptions(RETRIABLE_EXCEPTIONS, max_retries=10)
  35. def _upload_to_request(request, progress_callback):
  36. """Upload a video to a Youtube request. Return video ID."""
  37. while 1:
  38. status, response = request.next_chunk()
  39. if response:
  40. if "id" in response:
  41. return response['id']
  42. else:
  43. raise KeyError("Response has no 'id' field")
  44. elif status and progress_callback:
  45. progress_callback(status.total_size, status.resumable_progress)
  46. def upload(resource, path, body, chunksize=int(1e6), progress_callback=None):
  47. """Upload video to Youtube. Return video ID."""
  48. body_keys = ",".join(body.keys())
  49. media = apiclient.http.MediaFileUpload(path, chunksize=chunksize, resumable=True)
  50. videos = resource.videos()
  51. request = videos.insert(part=body_keys, body=body, media_body=media)
  52. return _upload_to_request(request, progress_callback)