#!/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 }) if JOB is not 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()))