From 1071d75857173534a28646a4c8bc53ad840f4de1 Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 3 Feb 2019 10:53:19 +0100 Subject: [PATCH 1/2] Improve dialog to manually enter PMS IP and port --- .../language/resource.language.en_gb/strings.po | 12 +++++++++++- resources/lib/initialsetup.py | 16 ++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index a486189a..b98f74bd 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -1081,6 +1081,16 @@ msgctxt "#39082" msgid "Direct Paths" msgstr "" +# Dialog for manually entering PMS +msgctxt "#39083" +msgid "Enter PMS IP or URL" +msgstr "" + +# Dialog for manually entering PMS +msgctxt "#39084" +msgid "Enter PMS port" +msgstr "" + msgctxt "#39200" msgid "Log-out Plex Home User " msgstr "" @@ -1133,7 +1143,7 @@ msgid "Enter your Plex Media Server's IP or URL, Examples are:" msgstr "" msgctxt "#39217" -msgid "Does your Plex Media Server support SSL connections? (https instead of http)?" +msgid "Use HTTPS (SSL) connections? With Kodi 18 or later, HTTPS will likely not work!" msgstr "" msgctxt "#39218" diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index 43718a35..269fa7a6 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -70,20 +70,22 @@ class InitialSetup(object): utils.window('plex_allows_mediaDeletion', value=value) def enter_new_pms_address(self): + LOG.info('Start getting manual PMS address and port') # "Enter your Plex Media Server's IP or URL. Examples are:" utils.messageDialog(utils.lang(29999), '%s\n%s\n%s' % (utils.lang(39215), '192.168.1.2', 'plex.myServer.org')) - address = utils.dialog('input', "Enter PMS IP or URL") - if address == '': + # "Enter PMS IP or URL" + address = utils.dialog('input', utils.lang(39083)) + if not address: return False - port = utils.dialog('input', "Enter PMS port", '32400', type='{numeric}') - if port == '': + port = utils.dialog('input', utils.lang(39084), '32400', type='{numeric}') + if not port: return False url = '%s:%s' % (address, port) - # "Does your Plex Media Server support SSL connections? - # (https instead of http)" + # "Use HTTPS (SSL) connections? With Kodi 18 or later, HTTPS will likely + # not work!" https = utils.yesno_dialog(utils.lang(29999), utils.lang(39217)) if https: url = 'https://%s' % url @@ -92,6 +94,7 @@ class InitialSetup(object): https = 'true' if https else 'false' machine_identifier = PF.GetMachineIdentifier(url) if machine_identifier is None: + LOG.error('Could not get machine identifier') # "Error contacting url # Abort (Yes) or save address anyway (No)" if utils.yesno_dialog(utils.lang(29999), @@ -100,6 +103,7 @@ class InitialSetup(object): utils.lang(39219))): return False else: + LOG.info('Saving manual address anyway') utils.settings('plex_machineIdentifier', '') else: utils.settings('plex_machineIdentifier', machine_identifier) From 01609e4d72cdd3034e971f5ebfb40d3f9561d730 Mon Sep 17 00:00:00 2001 From: croneter Date: Sun, 3 Feb 2019 16:44:37 +0100 Subject: [PATCH 2/2] Better inform the user if problems arise with manual PMS IP input --- .../resource.language.en_gb/strings.po | 5 ++ resources/lib/downloadutils.py | 31 ++++++-- resources/lib/initialsetup.py | 77 +++++++++++++------ resources/lib/plex_functions.py | 14 +++- resources/lib/service_entry.py | 31 ++++++-- 5 files changed, 119 insertions(+), 39 deletions(-) diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index b98f74bd..a4c04828 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -464,6 +464,11 @@ msgctxt "#30502" msgid "Sync Plex artwork from the PMS (recommended)" msgstr "" +# Message shown if SSL HTTPS certificate fails +msgctxt "#30503" +msgid "SSL certificate failed to validate. Please check {0} for solutions." +msgstr "" + # PKC Settings, category name msgctxt "#30506" msgid "Sync Options" diff --git a/resources/lib/downloadutils.py b/resources/lib/downloadutils.py index b4bc2562..77491c64 100644 --- a/resources/lib/downloadutils.py +++ b/resources/lib/downloadutils.py @@ -3,6 +3,7 @@ from __future__ import absolute_import, division, unicode_literals from logging import getLogger import requests +import requests.exceptions as exceptions from . import utils, clientinfo, app @@ -114,7 +115,7 @@ class DownloadUtils(): def downloadUrl(self, url, action_type="GET", postBody=None, parameters=None, authenticate=True, headerOptions=None, verifySSL=True, timeout=None, return_response=False, - headerOverride=None): + headerOverride=None, reraise=False): """ Override SSL check with verifySSL=False @@ -172,39 +173,55 @@ class DownloadUtils(): r = self._doDownload(s, action_type, **kwargs) # THE EXCEPTIONS - except requests.exceptions.SSLError as e: + except exceptions.SSLError as e: LOG.warn("Invalid SSL certificate for: %s", url) LOG.warn(e) + if reraise: + raise - except requests.exceptions.ConnectionError as e: + except exceptions.ConnectionError as e: # Connection error LOG.warn("Server unreachable at: %s", url) LOG.warn(e) + if reraise: + raise - except requests.exceptions.Timeout as e: + except exceptions.Timeout as e: LOG.warn("Server timeout at: %s", url) LOG.warn(e) + if reraise: + raise - except requests.exceptions.HTTPError as e: + except exceptions.HTTPError as e: LOG.warn('HTTP Error at %s', url) LOG.warn(e) + if reraise: + raise - except requests.exceptions.TooManyRedirects as e: + except exceptions.TooManyRedirects as e: LOG.warn("Too many redirects connecting to: %s", url) LOG.warn(e) + if reraise: + raise - except requests.exceptions.RequestException as e: + except exceptions.RequestException as e: LOG.warn("Unknown error connecting to: %s", url) LOG.warn(e) + if reraise: + raise except SystemExit: LOG.info('SystemExit detected, aborting download') self.stopSession() + if reraise: + raise except: LOG.warn('Unknown error while downloading. Traceback:') import traceback LOG.warn(traceback.format_exc()) + if reraise: + raise # THE RESPONSE ##### else: diff --git a/resources/lib/initialsetup.py b/resources/lib/initialsetup.py index 269fa7a6..78fc590b 100644 --- a/resources/lib/initialsetup.py +++ b/resources/lib/initialsetup.py @@ -9,7 +9,7 @@ from . import utils from .utils import etree from . import path_ops from . import migration -from .downloadutils import DownloadUtils as DU +from .downloadutils import DownloadUtils as DU, exceptions from . import plex_functions as PF from . import plex_tv from . import json_rpc as js @@ -92,28 +92,59 @@ class InitialSetup(object): else: url = 'http://%s' % url https = 'true' if https else 'false' - machine_identifier = PF.GetMachineIdentifier(url) - if machine_identifier is None: - LOG.error('Could not get machine identifier') - # "Error contacting url - # Abort (Yes) or save address anyway (No)" - if utils.yesno_dialog(utils.lang(29999), - '%s %s. %s' % (utils.lang(39218), - url, - utils.lang(39219))): - return False - else: - LOG.info('Saving manual address anyway') - utils.settings('plex_machineIdentifier', '') - else: - utils.settings('plex_machineIdentifier', machine_identifier) - LOG.info('Set new PMS to https %s, address %s, port %s, machineId %s', - https, address, port, machine_identifier) - utils.settings('https', value=https) - utils.settings('ipaddress', value=address) - utils.settings('port', value=port) - # Chances are this is a local PMS, so disable SSL certificate check - utils.settings('sslverify', value='false') + # Try to connect first + error = False + try: + machine_identifier = PF.GetMachineIdentifier(url) + except exceptions.SSLError: + LOG.error('SSL cert error contacting %s', url) + # "SSL certificate failed to validate. Please check {0} + # for solutions." + utils.messageDialog(utils.lang(29999), + utils.lang(30503).format('github.com/croneter/PlexKodiConnect/issues')) + return + except Exception: + error = True + if error or machine_identifier is None: + LOG.error('Could not even get a machineIdentifier for %s', url) + # "Server is unreachable" + utils.messageDialog(utils.lang(29999), utils.lang(33002)) + return + # Let's use the main account's token, not managed user token + token = utils.settings('plexToken') + xml = PF.pms_root(url, token) + if xml == 401: + LOG.error('Not yet authorized for %s', url) + # "User is unauthorized for server {0}", + # "Please sign in to plex.tv." + utils.messageDialog(utils.lang(29999), + '%s. %s' % (utils.lang(33010).format(address), + utils.lang(39014))) + return + try: + xml[0].attrib + except (IndexError, TypeError, AttributeError): + LOG.error('Could not get PMS root directory for %s', url) + # "Error contacting PMS" + utils.messageDialog(utils.lang(29999), utils.lang(39218)) + return + pms = { + 'baseURL': url, + 'ip': address, + # Assume PMS is not local so we're not resetting verifyssl + 'local': False, + 'machineIdentifier': xml.get('machineIdentifier'), + 'name': xml.get('friendlyName'), + # Assume that we own this PMS - no easy way to check + 'owned': True, + 'platform': xml.get('platform'), + 'port': port, + # 'relay': True, + 'scheme': 'https' if https else 'http', + 'token': token, + 'version': xml.get('version') + } + return pms def plex_tv_sign_in(self): """ diff --git a/resources/lib/plex_functions.py b/resources/lib/plex_functions.py index b006dc10..6d29609e 100644 --- a/resources/lib/plex_functions.py +++ b/resources/lib/plex_functions.py @@ -834,7 +834,8 @@ def GetMachineIdentifier(url): xml = DU().downloadUrl('%s/identity' % url, authenticate=False, verifySSL=False, - timeout=10) + timeout=10, + reraise=True) try: machineIdentifier = xml.attrib['machineIdentifier'] except (AttributeError, KeyError): @@ -937,6 +938,17 @@ def delete_item_from_pms(plexid): return False +def pms_root(url, token): + """ + Retrieve the PMS' most basic settings by retrieving / + """ + return DU().downloadUrl( + url, + authenticate=False, + verifySSL=True if v.KODIVERSION >= 18 else False, + headerOptions={'X-Plex-Token': token} if token else None) + + def get_PMS_settings(url, token): """ Retrieve the PMS' settings via /:/prefs diff --git a/resources/lib/service_entry.py b/resources/lib/service_entry.py index f59ed943..63b4e554 100644 --- a/resources/lib/service_entry.py +++ b/resources/lib/service_entry.py @@ -269,14 +269,29 @@ class Service(): self.auth_running = False def enter_new_pms_address(self): - if self.setup.enter_new_pms_address(): - app.CONN.load() - app.ACCOUNT.reset_session() - app.ACCOUNT.set_unauthenticated() - self.server_has_been_online = False - self.welcome_msg = False - # Force a full sync - app.SYNC.run_lib_scan = 'full' + server = self.setup.enter_new_pms_address() + if not server: + return + if not self.log_out(): + return False + # Save changes to to file + self.setup.save_pms_settings(server['baseURL'], server['token']) + self.setup.write_pms_to_settings(server) + if not v.KODIVERSION >= 18: + utils.settings('sslverify', value='false') + if not self.log_out(): + return False + # Wipe Kodi and Plex database as well as playlists and video nodes + utils.wipe_database() + app.CONN.load() + app.ACCOUNT.reset_session() + app.ACCOUNT.set_unauthenticated() + self.server_has_been_online = False + self.welcome_msg = False + # Force a full sync + app.SYNC.run_lib_scan = 'full' + LOG.info("Choosing new PMS complete") + return True def _do_auth(self): LOG.info('Authenticating user')