diff --git a/plexapi/exceptions.py b/plexapi/exceptions.py index c269c38e..182feb13 100644 --- a/plexapi/exceptions.py +++ b/plexapi/exceptions.py @@ -29,3 +29,8 @@ class Unsupported(PlexApiException): class Unauthorized(BadRequest): """ Invalid username/password or token. """ pass + + +class TwoFactorRequired(Unauthorized): + """ Two factor authentication required. """ + pass diff --git a/plexapi/myplex.py b/plexapi/myplex.py index 461cfecb..8d697924 100644 --- a/plexapi/myplex.py +++ b/plexapi/myplex.py @@ -12,7 +12,7 @@ from plexapi import (BASE_HEADERS, CONFIG, TIMEOUT, X_PLEX_ENABLE_FAST_CONNECT, log, logfilter, utils) from plexapi.base import PlexObject from plexapi.client import PlexClient -from plexapi.exceptions import BadRequest, NotFound, Unauthorized +from plexapi.exceptions import BadRequest, NotFound, Unauthorized, TwoFactorRequired from plexapi.library import LibrarySection from plexapi.server import PlexServer from plexapi.sonos import PlexSonosClient @@ -237,6 +237,8 @@ class MyPlexAccount(PlexObject): errtext = response.text.replace('\n', ' ') message = f'({response.status_code}) {codename}; {response.url} {errtext}' if response.status_code == 401: + if "verification code" in response.text: + raise TwoFactorRequired(message) raise Unauthorized(message) elif response.status_code == 404: raise NotFound(message) diff --git a/tools/plex-gettoken.py b/tools/plex-gettoken.py index 48b60a8b..03c32ae1 100755 --- a/tools/plex-gettoken.py +++ b/tools/plex-gettoken.py @@ -4,11 +4,16 @@ Plex-GetToken is a simple method to retrieve a Plex account token. """ from getpass import getpass +from plexapi.exceptions import TwoFactorRequired from plexapi.myplex import MyPlexAccount username = input("Plex username: ") password = getpass("Plex password: ") -code = input("Plex 2FA code (leave blank for none): ") -account = MyPlexAccount(username, password, code=code) +try: + account = MyPlexAccount(username, password) +except TwoFactorRequired: + code = input("Plex 2FA code: ") + account = MyPlexAccount(username, password, code=code) + print(account.authenticationToken)