Browse Source

split auth backend in modules

Arnau Sanchez 10 years ago
parent
commit
507a7c4559

+ 6 - 0
README.md

@@ -54,6 +54,12 @@ $ youtube-upload --title="A.S. Mutter"
 tx2Zb-145Yz
 ```
 
+* Upload a video using a browser window to authenticate (if required):
+
+```
+$ youtube-upload --title="A.S. Mutter" --auth-browser anne_sophie_mutter.flv
+```
+
 * Split a video with _ffmpeg_
 
 Youtube currently limits videos to <2Gb and <15' for almost all users. You can use the example script to split it before uploading:

+ 0 - 144
youtube_upload/auth.py

@@ -1,144 +0,0 @@
-"""Wrapper for Google OAuth2 API."""
-import sys
-import json
-
-import googleapiclient.discovery
-import oauth2client
-import httplib2
-
-import lib
-
-try:
-    from PyQt4 import QtCore, QtGui, QtWebKit
-    WEBKIT_BACKEND = "qt"
-except ImportError:
-    import gtk
-    import webkit
-    WEBKIT_BACKEND = "gtk"
-except ImportError:
-    WEBKIT_BACKEND = None
-    
-YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
-
-CHECK_AUTH_JS = """
-    var code = document.getElementById("code");
-    var access_denied = document.getElementById("access_denied");
-    var result;
-    
-    if (code) {
-        result = {authorized: true, code: code.value};
-    } else if (access_denied) {
-        result = {authorized: false, message: access_denied.innerText};
-    } else {
-        result = {};
-    }
-"""
-
-CHECK_AUTH_JS_GTK = CHECK_AUTH_JS + "window.status = JSON.stringify(result);"
-CHECK_AUTH_JS_QT = CHECK_AUTH_JS + "result;"
-
-def _on_qt_page_load_finished(dialog, webview):
-    to_s = lambda x: (str(x.toUtf8()) if isinstance(x, QtCore.QString) else x)
-    frame = webview.page().currentFrame()
-    jscode = QtCore.QString(CHECK_AUTH_JS_QT)
-    res = frame.evaluateJavaScript(jscode)
-    authorization = dict((to_s(k), to_s(v)) for (k, v) in res.toPyObject().items())
-    if authorization.has_key("authorized"):
-        dialog.authorization_code = authorization.get("code")
-        dialog.close()
-   
-def _get_code_from_browser_qt(url, size, title):
-    app = QtGui.QApplication([])
-    dialog = QtGui.QDialog()
-    dialog.setWindowTitle(title)
-    dialog.resize(*size)
-    webview = QtWebKit.QWebView()
-    webpage = QtWebKit.QWebPage()
-    webview.setPage(webpage)           
-    webpage.loadFinished.connect(lambda: _on_qt_page_load_finished(dialog, webview))
-    webview.setUrl(QtCore.QUrl.fromEncoded(url))
-    layout = QtGui.QGridLayout()
-    layout.addWidget(webview)
-    dialog.setLayout(layout)
-    dialog.authorization_code = None
-    dialog.show()
-    app.exec_()
-    return dialog.authorization_code    
-
-def _on_webview_status_bar_changed(webview, status, dialog):
-    if status:
-        authorization = json.loads(status)
-        if authorization.has_key("authorized"):
-            dialog.set_data("authorization_code", authorization["code"])
-            dialog.response(0)
-    
-def _get_code_from_browser_gtk(url, size, title):
-    """Open a webkit window and return the code the user wrote."""
-    dialog = gtk.Dialog(title=title)
-    webview = webkit.WebView()
-    scrolled = gtk.ScrolledWindow()
-    scrolled.add(webview)
-    dialog.get_children()[0].add(scrolled)
-    webview.load_uri(url)    
-    dialog.resize(*size)
-    dialog.show_all()
-    
-    dialog.connect("delete-event", lambda event, data: dialog.response(1))
-    webview.connect("load-finished", 
-        lambda view, frame: view.execute_script(CHECK_AUTH_JS_GTK))       
-    webview.connect("status-bar-text-changed", _on_webview_status_bar_changed, dialog)
-    dialog.set_data("authorization_code", None)
-    
-    status = dialog.run()
-    dialog.destroy()
-    while gtk.events_pending():
-        gtk.main_iteration(False)
-    return dialog.get_data("authorization_code")
-        
-def _get_credentials_interactively(flow, storage, get_code_callback):
-    """Return the credentials asking the user."""
-    flow.redirect_uri = oauth2client.client.OOB_CALLBACK_URN
-    authorize_url = flow.step1_get_authorize_url()
-    code = get_code_callback(authorize_url)
-    if code:
-        credential = flow.step2_exchange(code, http=None)
-        storage.put(credential)
-        credential.set_store(storage)
-        return credential
-
-def _get_credentials(flow, storage, get_code_callback):
-    """Return the user credentials. If not found, run the interactive flow."""
-    existing_credentials = storage.get()
-    if existing_credentials and not existing_credentials.invalid:
-        return existing_credentials
-    else:
-        return _get_credentials_interactively(flow, storage, get_code_callback)
-
-def get_code_from_prompt(authorize_url):
-    """Show authorization URL and return the code the user wrote."""
-    message = "Check this link in your browser: {0}".format(authorize_url)
-    lib.debug(message)
-    return raw_input("Enter verification code: ")
-
-def get_code_from_browser(url, size=(640, 480), title="Google authentication"):
-    if WEBKIT_BACKEND == "qt":
-        lib.debug("Using webkit backend: QT")
-        with lib.default_sigint():
-            return _get_code_from_browser_qt(url, size=size, title=title)
-    elif WEBKIT_BACKEND == "gtk":
-        lib.debug("Using webkit backend: GTK")
-        with lib.default_sigint():
-            return _get_code_from_browser_gtk(url, size=size, title=title)
-    else:
-        raise NotImplementedError("GUI auth requires pywebkitgtk or qtwebkit")
-
-def get_resource(client_secrets_file, credentials_file, get_code_callback=None):
-    """Authenticate and return a googleapiclient.discovery.Resource object."""
-    get_flow = oauth2client.client.flow_from_clientsecrets
-    flow = get_flow(client_secrets_file, scope=YOUTUBE_UPLOAD_SCOPE)
-    storage = oauth2client.file.Storage(credentials_file)
-    get_code = get_code_callback or get_code_from_prompt
-    credentials = _get_credentials(flow, storage, get_code)
-    if credentials:
-        http = credentials.authorize(httplib2.Http())
-        return googleapiclient.discovery.build("youtube", "v3", http=http)

+ 42 - 0
youtube_upload/auth/__init__.py

@@ -0,0 +1,42 @@
+"""Wrapper for Google OAuth2 API."""
+import sys
+import json
+
+import googleapiclient.discovery
+import oauth2client
+import httplib2
+
+from youtube_upload import lib
+from youtube_upload.auth import console
+from youtube_upload.auth import browser
+
+YOUTUBE_UPLOAD_SCOPE = "https://www.googleapis.com/auth/youtube.upload"
+
+def _get_credentials_interactively(flow, storage, get_code_callback):
+    """Return the credentials asking the user."""
+    flow.redirect_uri = oauth2client.client.OOB_CALLBACK_URN
+    authorize_url = flow.step1_get_authorize_url()
+    code = get_code_callback(authorize_url)
+    if code:
+        credential = flow.step2_exchange(code, http=None)
+        storage.put(credential)
+        credential.set_store(storage)
+        return credential
+
+def _get_credentials(flow, storage, get_code_callback):
+    """Return the user credentials. If not found, run the interactive flow."""
+    existing_credentials = storage.get()
+    if existing_credentials and not existing_credentials.invalid:
+        return existing_credentials
+    else:
+        return _get_credentials_interactively(flow, storage, get_code_callback)
+
+def get_resource(client_secrets_file, credentials_file, get_code_callback):
+    """Authenticate and return a googleapiclient.discovery.Resource object."""
+    get_flow = oauth2client.client.flow_from_clientsecrets
+    flow = get_flow(client_secrets_file, scope=YOUTUBE_UPLOAD_SCOPE)
+    storage = oauth2client.file.Storage(credentials_file)
+    credentials = _get_credentials(flow, storage, get_code_callback)
+    if credentials:
+        http = credentials.authorize(httplib2.Http())
+        return googleapiclient.discovery.build("youtube", "v3", http=http)

+ 22 - 0
youtube_upload/auth/browser.py

@@ -0,0 +1,22 @@
+import lib
+
+try:
+    from youtube_upload.auth import webkit_qt
+    WEBKIT_BACKEND = "qt"
+except ImportError:
+    from youtube_upload.auth import webkit_gtk
+    WEBKIT_BACKEND = "gtk"
+except ImportError:
+    WEBKIT_BACKEND = None
+
+def get_code(url, size=(640, 480), title="Google authentication"):
+    if WEBKIT_BACKEND == "qt":
+        lib.debug("Using webkit backend: QT")
+        with lib.default_sigint():
+            return webkit_qt.get_code(url, size=size, title=title)
+    elif WEBKIT_BACKEND == "gtk":
+        lib.debug("Using webkit backend: GTK")
+        with lib.default_sigint():
+            return webkit_gtk.get_code(url, size=size, title=title)
+    else:
+        raise NotImplementedError("GUI auth requires pywebkitgtk or qtwebkit")

+ 7 - 0
youtube_upload/auth/console.py

@@ -0,0 +1,7 @@
+import sys
+
+def get_code(authorize_url):
+    """Show authorization URL and return the code the user wrote."""
+    message = "Check this link in your browser: {0}".format(authorize_url)
+    sys.stderr.write(message + "\n")
+    return raw_input("Enter verification code: ")

+ 49 - 0
youtube_upload/auth/webkit_gtk.py

@@ -0,0 +1,49 @@
+import json
+
+import gtk
+import webkit
+
+CHECK_AUTH_JS = """
+    var code = document.getElementById("code");
+    var access_denied = document.getElementById("access_denied");
+    var result;
+    
+    if (code) {
+        result = {authorized: true, code: code.value};
+    } else if (access_denied) {
+        result = {authorized: false, message: access_denied.innerText};
+    } else {
+        result = {};
+    }
+    window.status = JSON.stringify(result);
+"""
+
+def _on_webview_status_bar_changed(webview, status, dialog):
+    if status:
+        authorization = json.loads(status)
+        if authorization.has_key("authorized"):
+            dialog.set_data("authorization_code", authorization["code"])
+            dialog.response(0)
+
+def get_code(url, size=(640, 480), title="Google authentication"):
+    """Open a GTK webkit window and return the access code."""
+    dialog = gtk.Dialog(title=title)
+    webview = webkit.WebView()
+    scrolled = gtk.ScrolledWindow()
+    scrolled.add(webview)
+    dialog.get_children()[0].add(scrolled)
+    webview.load_uri(url)    
+    dialog.resize(*size)
+    dialog.show_all()
+    
+    dialog.connect("delete-event", lambda event, data: dialog.response(1))
+    webview.connect("load-finished", 
+        lambda view, frame: view.execute_script(CHECK_AUTH_JS))       
+    webview.connect("status-bar-text-changed", _on_webview_status_bar_changed, dialog)
+    dialog.set_data("authorization_code", None)
+
+    status = dialog.run()
+    dialog.destroy()
+    while gtk.events_pending():
+        gtk.main_iteration(False)
+    return dialog.get_data("authorization_code")

+ 45 - 0
youtube_upload/auth/webkit_qt.py

@@ -0,0 +1,45 @@
+from PyQt4 import QtCore, QtGui, QtWebKit
+
+CHECK_AUTH_JS = """
+    var code = document.getElementById("code");
+    var access_denied = document.getElementById("access_denied");
+    var result;
+    
+    if (code) {
+        result = {authorized: true, code: code.value};
+    } else if (access_denied) {
+        result = {authorized: false, message: access_denied.innerText};
+    } else {
+        result = {};
+    }
+    result;
+"""
+
+def _on_qt_page_load_finished(dialog, webview):
+    to_s = lambda x: (str(x.toUtf8()) if isinstance(x, QtCore.QString) else x)
+    frame = webview.page().currentFrame()
+    jscode = QtCore.QString(CHECK_AUTH_JS)
+    res = frame.evaluateJavaScript(jscode)
+    authorization = dict((to_s(k), to_s(v)) for (k, v) in res.toPyObject().items())
+    if authorization.has_key("authorized"):
+        dialog.authorization_code = authorization.get("code")
+        dialog.close()
+   
+def get_code(url, size=(640, 480), title="Google authentication"):
+    """Open a QT webkit window and return the access code."""
+    app = QtGui.QApplication([])
+    dialog = QtGui.QDialog()
+    dialog.setWindowTitle(title)
+    dialog.resize(*size)
+    webview = QtWebKit.QWebView()
+    webpage = QtWebKit.QWebPage()
+    webview.setPage(webpage)           
+    webpage.loadFinished.connect(lambda: _on_qt_page_load_finished(dialog, webview))
+    webview.setUrl(QtCore.QUrl.fromEncoded(url))
+    layout = QtGui.QGridLayout()
+    layout.addWidget(webview)
+    dialog.setLayout(layout)
+    dialog.authorization_code = None
+    dialog.show()
+    app.exec_()
+    return dialog.authorization_code

+ 5 - 4
youtube_upload/main.py

@@ -20,11 +20,12 @@ import sys
 import optparse
 import collections
 
+import oauth2client
+
 import youtube_upload.auth
 import youtube_upload.upload_video
 import youtube_upload.categories
 import youtube_upload.lib as lib
-import oauth2client
 
 # http://code.google.com/p/python-progressbar (>= 2.3)
 try:
@@ -125,8 +126,8 @@ def run_main(parser, options, args, output=sys.stdout):
     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 = (youtube_upload.auth.get_code_from_browser 
-        if options.auth_gui else None)
+    get_code_callback = (youtube_upload.auth.browser.get_code 
+        if options.auth_browser else youtube_upload.auth.console.get_code)
     youtube = youtube_upload.auth.get_resource(client_secrets, credentials,
         get_code_callback=get_code_callback)
 
@@ -169,7 +170,7 @@ def main(arguments):
         type="string", help='Client secrets JSON file')
     parser.add_option('', '--credentials-file', dest='credentials_file',
         type="string", help='Client secrets JSON file')
-    parser.add_option('', '--auth-gui', dest='auth_gui', action="store_true",
+    parser.add_option('', '--auth-browser', dest='auth_browser', action="store_true",
         help='Open a GUI browser to authenticate if required')
 
     options, args = parser.parse_args(arguments)