diff --git a/docs/cli.rst b/docs/cli.rst index 9afc99f4..b560cb91 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -77,22 +77,59 @@ For a list of all the supported options see :ref:`cli-options`. Plugin specific usage --------------------- -Authenticating with Twitch/Justin.tv -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -It's possible to access subscription based content on Twitch/Justin.tv by letting Livestreamer use your web browser sessions cookies. +Authenticating with Twitch +^^^^^^^^^^^^^^^^^^^^^^^^^^ -Cookies should be specified in a key value list separated by a semicolon. In this case only the `_twitch_session_id` and `persistent` keys are required by Twitch/Justin.tv. For example: +It's possible to access subscription content on Twitch by giving Livestreamer +access to your account. There are two methods to authenticate Livestreamer +to Twitch: Application authorization via OAuth or re-using your web browsers +cookies. + +Using the OAuth method is recommended since it is easier and will never expire +(unless access is revoked in your Twitch settings or a new access token is +created), unlike cookies which may stop working if you log out in your browser. + + +**Application authorization via OAuth** + +To authenticate Livestreamer with your Twitch account, simply run this command: .. sourcecode:: console - $ livestreamer --jtv-cookie "_twitch_session_id=xxxxxx; persistent=xxxxx" twitch.tv/ignproleague + $ livestreamer --twitch-oauth-authenticate + + +This will open a web browser where Twitch will ask you if you want to give +Livestreamer permission to access your account, then forward you to a page +with further instructions. + + +**Cookies** + +Cookies should be specified in a key value list separated by a semicolon. +In this case only the `_twitch_session_id` and `persistent` keys are required +by Twitch. For example: + + +.. sourcecode:: console + + $ livestreamer --twitch-cookie "_twitch_session_id=xxxxxx; persistent=xxxxx" twitch.tv/ignproleague [plugin.justintv][info] Attempting to authenticate using cookies [plugin.justintv][info] Successfully logged in as -Extracting cookies from your web browser varies from browser to browser, try googling " view cookies". -It's recommended to save these cookies in your :ref:`configuration file ` rather than specifying them manually every time. +Extracting cookies from your web browser varies from browser to browser, try +googling " view cookies". + +It's recommended to save these cookies in your +:ref:`configuration file ` rather than specifying them +manually every time. + +.. note:: + + Authenticating with Justin.tv is not possible since their video system + overhaul, but may be a unintended bug and could be fixed in the future. Authenticating with GOMTV.net @@ -118,7 +155,7 @@ This will cause Livestreamer to prompt you for your password and then attempt to The important part of this output is the last line, that's the cookies used to access this login session. To use these cookies pass them to the ``--gomtv-cookie`` option. It's recommended to save these cookies in your :ref:`configuration file ` rather than specifying them manually every time. -These instructions are for authenticating with a regular user account, if you are using a `Facebook `_ or `Twitter `_ account to authenticate you'll need to extract your cookies from your web browser instead. Extracting cookies from your web browser varies from browser to browser, try googling " view cookies". +These instructions are for authenticating with a regular user account, if you are using a Facebook or Twitter account to authenticate you'll need to extract your cookies from your web browser instead. Extracting cookies from your web browser varies from browser to browser, try googling " view cookies". Advanced usage @@ -391,6 +428,20 @@ Plugin options .. versionadded:: 1.6.0 +.. cmdoption:: --twitch-oauth-token token + + Specify a OAuth token to allow Livestreamer to access Twitch using + your account. + + .. versionadded:: 1.7.2 + +.. cmdoption:: --twitch-oauth-authenticate + + Opens a web browser where you can grant Livestreamer access to your + Twitch account. + + .. versionadded:: 1.7.2 + .. cmdoption:: --gomtv-cookie cookie Specify GOMTV cookie to allow access to streams, diff --git a/docs/twitch_oauth.rst b/docs/twitch_oauth.rst new file mode 100644 index 00000000..effc5779 --- /dev/null +++ b/docs/twitch_oauth.rst @@ -0,0 +1,35 @@ +.. _twitch_oauth: + +Twitch OAuth authentication +=========================== + + +.. raw:: html + + + +
+ + +You successfully authenticated Livestreamer with Twitch. + +Paste this into your :ref:`configuration file `: + +.. code-block:: bash + + twitch-oauth-token= + diff --git a/src/livestreamer/plugins/twitch.py b/src/livestreamer/plugins/twitch.py index faacf69c..85d76450 100644 --- a/src/livestreamer/plugins/twitch.py +++ b/src/livestreamer/plugins/twitch.py @@ -1,4 +1,5 @@ from livestreamer.exceptions import PluginError, NoStreamsError +from livestreamer.options import Options # Import base classes from a support plugin that must exist in the # same directory as this plugin. @@ -21,11 +22,20 @@ class TwitchAPI(JustinTVAPIBase): def channel_viewer_info(self, channel): return self.call("/api/channels/{0}/viewer".format(channel)) + def user(self): + return self.call("/kraken/user") + def videos(self, video_id): return self.call("/api/videos/{0}".format(video_id)) class Twitch(JustinTVPluginBase): + options = Options({ + "cookie": None, + "oauth_token": None, + "password": None + }) + @classmethod def can_handle_url(self, url): return "twitch.tv" in url @@ -35,6 +45,22 @@ class Twitch(JustinTVPluginBase): self.api = TwitchAPI() + def _authenticate(self): + oauth_token = self.options.get("oauth_token") + + if oauth_token and not self.api.oauth_token: + self.logger.info("Attempting to authenticate using OAuth token") + self.api.oauth_token = oauth_token + user = self.api.user().get("display_name") + + if user: + self.logger.info("Successfully logged in as {0}", user) + else: + self.logger.error("Failed to authenticate, the access token " + "is not valid") + else: + return JustinTVPluginBase._authenticate(self) + def _get_video_streams(self): self._authenticate() diff --git a/src/livestreamer_cli/argparser.py b/src/livestreamer_cli/argparser.py index 22eeaa82..b99c1c4b 100644 --- a/src/livestreamer_cli/argparser.py +++ b/src/livestreamer_cli/argparser.py @@ -187,6 +187,13 @@ pluginopt.add_argument("--jtv-password", "--twitch-password", help="Use this to access password protected streams.", metavar="password") +pluginopt.add_argument("--twitch-oauth-token", metavar="token", + help="Specify a OAuth token to allow Livestreamer to " + "access Twitch using your account.") + +pluginopt.add_argument("--twitch-oauth-authenticate", action="store_true", + help="Opens a web browser where you can grant " + "Livestreamer access to your Twitch account.") pluginopt.add_argument("--gomtv-cookie", metavar="cookie", help="Specify GOMTV cookie to allow access to " diff --git a/src/livestreamer_cli/main.py b/src/livestreamer_cli/main.py index c9cd896f..976689d7 100644 --- a/src/livestreamer_cli/main.py +++ b/src/livestreamer_cli/main.py @@ -4,6 +4,7 @@ import re import requests import sys import signal +import webbrowser from contextlib import closing from time import sleep @@ -467,6 +468,27 @@ def print_plugins(): console.msg("Loaded plugins: {0}", pluginlist_formatted) +def authenticate_twitch_oauth(): + """Opens a web browser to allow the user to grant Livestreamer + access to their Twitch account.""" + + client_id = "ewvlchtxgqq88ru9gmfp1gmyt6h2b93" + redirect_uri = "http://livestreamer.tanuki.se/en/develop/twitch_oauth.html" + url = ("https://api.twitch.tv/kraken/oauth2/authorize/" + "?response_type=token&client_id={0}&redirect_uri=" + "{1}&scope=user_read").format(client_id, redirect_uri) + + console.msg("Attempting to open a browser to let you authenticate " + "Livestreamer with Twitch") + + try: + if not webbrowser.open_new_tab(url): + raise webbrowser.Error + except webbrowser.Error: + console.exit("Unable to open a web browser, try accessing this URL " + "manually instead:\n{0}".format(url)) + + def load_plugins(dirs): """Attempts to load plugins from a list of directories.""" @@ -595,6 +617,10 @@ def setup_options(): livestreamer.set_plugin_option("twitch", "password", args.jtv_password) + if args.twitch_oauth_token: + livestreamer.set_plugin_option("twitch", "oauth_token", + args.twitch_oauth_token) + if args.gomtv_cookie: livestreamer.set_plugin_option("gomtv", "cookie", args.gomtv_cookie) @@ -652,5 +678,7 @@ def main(): with ignored(KeyboardInterrupt): setup_options() handle_url() + elif args.twitch_oauth_authenticate: + authenticate_twitch_oauth() else: parser.print_help()