upload.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import os
  2. import sys
  3. import collections
  4. import webbrowser
  5. import googleapiclient.errors
  6. import oauth2client
  7. from . import lib
  8. from . import playlists
  9. from . import auth
  10. from . import upload_video
  11. from . import categories
  12. # http://code.google.com/p/python-progressbar (>= 2.3)
  13. try:
  14. import progressbar
  15. except ImportError:
  16. progressbar = None
  17. debug = lib.debug
  18. struct = collections.namedtuple
  19. class InvalidCategory(Exception): pass
  20. class AuthenticationError(Exception): pass
  21. class RequestError(Exception): pass
  22. def open_link(url):
  23. """Opens a URL link in the client's browser."""
  24. webbrowser.open(url)
  25. def get_progress_info():
  26. """Return a function callback to update the progressbar."""
  27. progressinfo = struct("ProgressInfo", ["callback", "finish"])
  28. if progressbar:
  29. bar = progressbar.ProgressBar(widgets=[
  30. progressbar.Percentage(), ' ',
  31. progressbar.Bar(), ' ',
  32. progressbar.FileTransferSpeed(),
  33. ])
  34. def _callback(total_size, completed):
  35. if not hasattr(bar, "next_update"):
  36. if hasattr(bar, "maxval"):
  37. bar.maxval = total_size
  38. else:
  39. bar.max_value = total_size
  40. bar.start()
  41. bar.update(completed)
  42. def _finish():
  43. if hasattr(bar, "next_update"):
  44. return bar.finish()
  45. return progressinfo(callback=_callback, finish=_finish)
  46. else:
  47. return progressinfo(callback=None, finish=lambda: True)
  48. def get_category_id(category):
  49. """Return category ID from its name."""
  50. if category:
  51. if category in categories.IDS:
  52. ncategory = categories.IDS[category]
  53. debug("Using category: {0} (id={1})".format(category, ncategory))
  54. return str(categories.IDS[category])
  55. else:
  56. msg = "{0} is not a valid category".format(category)
  57. raise InvalidCategory(msg)
  58. def upload_youtube_video(youtube, options, video_path):
  59. """Upload video."""
  60. u = lib.to_utf8
  61. title = u(options.title)
  62. if hasattr(u('string'), 'decode'):
  63. description = u(options.description or "").decode("string-escape")
  64. else:
  65. description = options.description
  66. if options.publish_at:
  67. debug("Your video will remain private until specified date.")
  68. tags = [u(s.strip()) for s in (options.tags or "").split(",")]
  69. progress = get_progress_info()
  70. category_id = get_category_id(options.category)
  71. request_body = {
  72. "snippet": {
  73. "title": title,
  74. "description": description,
  75. "categoryId": category_id,
  76. "tags": tags,
  77. "defaultLanguage": options.default_language,
  78. "defaultAudioLanguage": options.default_audio_language,
  79. },
  80. "status": {
  81. "privacyStatus": ("private" if options.publish_at else options.privacy),
  82. "publishAt": options.publish_at,
  83. },
  84. "recordingDetails": {
  85. "location": lib.string_to_dict(options.location),
  86. "recordingDate": options.recording_date,
  87. },
  88. }
  89. debug("Start upload: {0}".format(video_path))
  90. try:
  91. video_id = upload_video.upload(youtube, video_path,
  92. request_body, progress_callback=progress.callback)
  93. finally:
  94. progress.finish()
  95. return video_id
  96. def get_youtube_handler(options):
  97. """Return the API Youtube object."""
  98. home = os.path.expanduser("~")
  99. default_client_secrets = lib.get_first_existing_filename(
  100. [sys.prefix, os.path.join(sys.prefix, "local")],
  101. "share/youtube_upload/client_secrets.json")
  102. default_credentials = os.path.join(home, ".youtube-upload-credentials.json")
  103. client_secrets = options.client_secrets or default_client_secrets or \
  104. os.path.join(home, ".client_secrets.json")
  105. credentials = options.credentials_file or default_credentials
  106. debug("Using client secrets: {0}".format(client_secrets))
  107. debug("Using credentials file: {0}".format(credentials))
  108. get_code_callback = (auth.browser.get_code
  109. if options.auth_browser else auth.console.get_code)
  110. return auth.get_resource(client_secrets, credentials,
  111. get_code_callback=get_code_callback)
  112. def upload(video_path, options):
  113. """Run the main scripts from the parsed options/args."""
  114. youtube = get_youtube_handler(options)
  115. if youtube:
  116. try:
  117. video_id = upload_youtube_video(youtube, options, video_path)
  118. if options.open_link:
  119. open_link(video_url)
  120. if options.thumb:
  121. youtube.thumbnails().set(videoId=video_id, media_body=options.thumb).execute()
  122. if options.playlist:
  123. playlists.add_video_to_playlist(youtube, video_id,
  124. title=lib.to_utf8(options.playlist), privacy=options.privacy)
  125. except googleapiclient.errors.HttpError as error:
  126. raise RequestError("Server response: {0}".format(bytes.decode(error.content).strip()))
  127. return video_id
  128. else:
  129. raise AuthenticationError("Cannot get youtube resource")