| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- #!/usr/bin/env python
- import os
- import sys
- import collections
- import googleapiclient.errors
- import oauth2client
- from . import auth
- from . import upload_video
- from . import categories
- from . import lib
- from . import playlists
- class InvalidCategory(Exception): pass
- class OptionsError(Exception): pass
- class AuthenticationError(Exception): pass
- class RequestError(Exception): pass
- EXIT_CODES = {
- OptionsError: 2,
- InvalidCategory: 3,
- RequestError: 3,
- AuthenticationError: 4,
- oauth2client.client.FlowExchangeError: 4,
- NotImplementedError: 5,
- }
- USE_DEBUG = False
- JOB = None
- #debug = lib.debug
- def debug(args):
- if USE_DEBUG:
- print(args)
- struct = collections.namedtuple
- class AttrDict(dict):
- def __init__(self, *args, **kwargs):
- super(AttrDict, self).__init__(*args, **kwargs)
- self.__dict__ = self
- def get_progress_info():
- """Return a function callback to update the progressbar."""
- progressinfo = struct("ProgressInfo", ["callback", "finish"])
- def _callback(total_size, completed):
- if JOB is not None:
- JOB.meta['status'] = 'uploading'
- JOB.meta['progress'] = "%.2f%%" % ((completed/total_size)*100)
- JOB.save()
- def _finish():
- if JOB is not None:
- JOB.meta['status'] = 'finished'
- JOB.meta['progress'] = 100
- JOB.save()
- return progressinfo(callback=_callback, finish=_finish)
- def get_category_id(category):
- """Return category ID from its name."""
- if category:
- if category in categories.IDS:
- ncategory = categories.IDS[category]
- debug("Using category: {0} (id={1})".format(category, ncategory))
- return str(categories.IDS[category])
- else:
- msg = "{0} is not a valid category".format(category)
- raise InvalidCategory(msg)
- def upload_youtube_video(youtube, options, video_path, total_videos, index):
- """Upload video with index (for split videos)."""
- u = lib.to_utf8
- title = u(options.title)
- if hasattr(u('string'), 'decode'):
- description = u(options.description or "").decode("string-escape")
- else:
- description = options.description
- if options.publish_at:
- debug("Your video will remain private until specified date.")
-
- tags = [u(s.strip()) for s in (options.tags or "").split(",")]
- ns = dict(title=title, n=index+1, total=total_videos)
- title_template = u(options.title_template)
- complete_title = (title_template.format(**ns) if total_videos > 1 else title)
- progress = get_progress_info()
- category_id = get_category_id(options.category)
- request_body = {
- "snippet": {
- "title": complete_title,
- "description": description,
- "categoryId": category_id,
- "tags": tags,
- "defaultLanguage": options.default_language,
- "defaultAudioLanguage": options.default_audio_language,
- },
- "status": {
- "privacyStatus": ("private" if options.publish_at else options.privacy),
- "publishAt": options.publish_at,
- },
- "recordingDetails": {
- "location": lib.string_to_dict(options.location),
- "recordingDate": options.recording_date,
- },
- }
- debug("Start upload: {0}".format(video_path))
- if JOB is not None:
- JOB.meta['status'] = 'starting upload'
- JOB.save()
- try:
- video_id = upload_video.upload(youtube, video_path,
- request_body, progress_callback=progress.callback)
- finally:
- progress.finish()
- return video_id
- def get_youtube_handler(options):
- """Return the API Youtube object."""
- home = os.path.expanduser("~")
- default_client_secrets = lib.get_first_existing_filename(
- [sys.prefix, os.path.join(sys.prefix, "local")],
- "share/youtube_upload/client_secrets.json")
- default_credentials = os.path.join(home, ".youtube-upload-credentials.json")
- client_secrets = options.client_secrets or default_client_secrets or \
- os.path.join(home, ".client_secrets.json")
- credentials = options.credentials_file or default_credentials
- debug("Using client secrets: {0}".format(client_secrets))
- debug("Using credentials file: {0}".format(credentials))
- get_code_callback = (auth.browser.get_code
- if options.auth_browser else auth.console.get_code)
- return auth.get_resource(client_secrets, credentials,
- get_code_callback=get_code_callback)
- def run_main(title,thumb,path,output=sys.stdout):
- """Run the main scripts from the parsed options/args."""
- options=AttrDict({ 'title': title, 'thumb': thumb ,
- 'privacy': 'unlisted', 'category': None,
- 'client_secrets': None, 'playlist': None, 'credentials_file': None, 'description': None, 'recording_date': None,
- 'tags': None, 'open_link': None, 'default_language': None, 'title_template': '{title} [{n}/{total}]', 'location': None,
- 'default_audio_language': None, 'publish_at': None, 'auth_browser': None
- })
- JOB.meta["type"]="Youtube"
- JOB.meta["target"]=title
- youtube = get_youtube_handler(options)
- video_path = path
- video_id=None
- if youtube:
- video_id = upload_youtube_video(youtube, options, video_path, 1, 1)
- if options.thumb:
- youtube.thumbnails().set(videoId=video_id, media_body=options.thumb).execute()
- output.write(video_id + "\n") #FIXME
- if JOB is not None:
- JOB.meta["video_id"]=video_id
- JOB.save()
- else:
- raise AuthenticationError("Cannot get youtube resource")
- return video_id
- def main(title,thumb,path,job=None):
- global JOB
- try:
- JOB = job
- return run_main(title,thumb,path)
- except googleapiclient.errors.HttpError as error:
- raise RequestError("Server response: {0}".format(bytes.decode(error.content).strip()))
|