From 3fd2234a92590a67473ea094a01d029ad7641c0f Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 5 Jul 2020 19:20:52 -0700 Subject: [PATCH 1/5] Remove refresh reachability --- plexpy/pmsconnect.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index 2b2f679b..015b06f8 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -2971,8 +2971,6 @@ class PmsConnect(object): return key_list def get_server_response(self): - # Refresh Plex remote access port mapping first - self.put_refresh_reachability() account_data = self.get_account(output_format='xml') try: From 938134081b6f42d48a15e0ba473bbfb795701c96 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:36:44 -0700 Subject: [PATCH 2/5] Add remote access monitoring using websockets * Fixes Tautulli/Tautulli-Issues#251 --- plexpy/__init__.py | 1 + plexpy/activity_handler.py | 49 ++++++++++++++++++++++++++++++++++++++ plexpy/web_socket.py | 41 ++++++++++++++++++++----------- 3 files changed, 77 insertions(+), 14 deletions(-) diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 6c44d765..44cd5af2 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -137,6 +137,7 @@ DEV = False WEBSOCKET = None WS_CONNECTED = False PLEX_SERVER_UP = None +PLEX_REMOTE_ACCESS_UP = None TRACKER = None diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py index 91d8d382..1763313b 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -505,6 +505,55 @@ class TimelineHandler(object): schedule_callback('rating_key-{}'.format(rating_key), remove_job=True) +class ReachabilityHandler(object): + + def __init__(self, data): + self.data = data + + def is_reachable(self): + if 'reachability' in self.data: + return self.data['reachability'] + return False + + def remote_access_enabled(self): + pms_connect = pmsconnect.PmsConnect() + pref = pms_connect.get_server_pref(pref='PublishServerOnPlexOnlineKey') + return helpers.bool_true(pref) + + def process(self): + # Check if remote access is enabled + if not self.remote_access_enabled(): + return + + # Do nothing if remote access is still up and hasn't changed + if self.is_reachable() and plexpy.PLEX_REMOTE_ACCESS_UP: + return + + pms_connect = pmsconnect.PmsConnect() + server_response = pms_connect.get_server_response() + + if server_response: + # Waiting for port mapping + if server_response['mapping_state'] == 'waiting': + logger.warn("Tautulli Monitor :: Remote access waiting for port mapping.") + + elif plexpy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']: + logger.warn("Tautulli Monitor :: Remote access failed: %s" % server_response['reason']) + logger.info("Tautulli Monitor :: Plex remote access is down.") + + plexpy.PLEX_REMOTE_ACCESS_UP = False + plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extdown', 'remote_access_info': server_response}) + + elif plexpy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']: + logger.info("Tautulli Monitor :: Plex remote access is back up.") + + plexpy.PLEX_REMOTE_ACCESS_UP = True + plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extup', 'remote_access_info': server_response}) + + elif plexpy.PLEX_REMOTE_ACCESS_UP is None: + plexpy.PLEX_REMOTE_ACCESS_UP = self.is_reachable() + + def del_keys(key): if isinstance(key, set): for child_key in key: diff --git a/plexpy/web_socket.py b/plexpy/web_socket.py index 8a8ee39b..6ff5e4fc 100644 --- a/plexpy/web_socket.py +++ b/plexpy/web_socket.py @@ -255,42 +255,55 @@ def process(opcode, data): try: data = data.decode('utf-8') logger.websocket_debug(data) - info = json.loads(data) + event = json.loads(data) except Exception as e: logger.warn("Tautulli WebSocket :: Error decoding message from websocket: %s" % e) logger.websocket_error(data) return False - info = info.get('NotificationContainer', info) - info_type = info.get('type') + event = event.get('NotificationContainer', event) + event_type = event.get('type') - if not info_type: + if not event_type: return False - if info_type == 'playing': - time_line = info.get('PlaySessionStateNotification', info.get('_children', {})) + if event_type == 'playing': + event_data = event.get('PlaySessionStateNotification', event.get('_children', {})) - if not time_line: - logger.debug("Tautulli WebSocket :: Session found but unable to get timeline data.") + if not event_data: + logger.debug("Tautulli WebSocket :: Session event found but unable to get websocket data.") return False try: - activity = activity_handler.ActivityHandler(timeline=time_line[0]) + activity = activity_handler.ActivityHandler(timeline=event_data[0]) activity.process() except Exception as e: logger.exception("Tautulli WebSocket :: Failed to process session data: %s." % e) - if info_type == 'timeline': - time_line = info.get('TimelineEntry', info.get('_children', {})) + if event_type == 'timeline': + event_data = event.get('TimelineEntry', event.get('_children', {})) - if not time_line: - logger.debug("Tautulli WebSocket :: Timeline event found but unable to get timeline data.") + if not event_data: + logger.debug("Tautulli WebSocket :: Timeline event found but unable to get websocket data.") return False try: - activity = activity_handler.TimelineHandler(timeline=time_line[0]) + activity = activity_handler.TimelineHandler(timeline=event_data[0]) activity.process() except Exception as e: logger.exception("Tautulli WebSocket :: Failed to process timeline data: %s." % e) + if event_type == 'reachability': + event_data = event.get('ReachabilityNotification', event.get('_children', {})) + + if not event_data: + logger.debug("Tautulli WebSocket :: Reachability event found but unable to get websocket data.") + return False + + try: + activity = activity_handler.ReachabilityHandler(data=event_data[0]) + activity.process() + except Exception as e: + logger.exception("Tautulli WebSocket :: Failed to process reachability data: %s." % e) + return True From 7fe1e542df96226b72b7f939ab9ae76c1135a673 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:38:54 -0700 Subject: [PATCH 3/5] Remove check remote access scheduled task * Tautulli/Tautulli-Issues#251 --- plexpy/__init__.py | 6 ------ plexpy/activity_pinger.py | 41 --------------------------------------- 2 files changed, 47 deletions(-) diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 44cd5af2..5cf1dc08 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -445,10 +445,6 @@ def initialize_scheduler(): schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs', hours=12 * (not bool(CONFIG.PMS_URL_MANUAL)), minutes=0, seconds=0) - pms_remote_access_seconds = CONFIG.REMOTE_ACCESS_PING_INTERVAL if 60 <= CONFIG.REMOTE_ACCESS_PING_INTERVAL else 60 - - schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access', - hours=0, minutes=0, seconds=pms_remote_access_seconds * bool(CONFIG.MONITOR_REMOTE_ACCESS)) schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates', hours=pms_update_check_hours * bool(CONFIG.MONITOR_PMS_UPDATES), minutes=0, seconds=0) @@ -471,8 +467,6 @@ def initialize_scheduler(): schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs', hours=0, minutes=0, seconds=0) - schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access', - hours=0, minutes=0, seconds=0) schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates', hours=0, minutes=0, seconds=0) diff --git a/plexpy/activity_pinger.py b/plexpy/activity_pinger.py index e3b093a1..a28a461c 100644 --- a/plexpy/activity_pinger.py +++ b/plexpy/activity_pinger.py @@ -318,47 +318,6 @@ def connect_server(log=True, startup=False): logger.error("Websocket :: Unable to open connection: %s." % e) -def check_server_access(): - with monitor_lock: - pms_connect = pmsconnect.PmsConnect() - server_response = pms_connect.get_server_response() - - global ext_ping_count - global ext_ping_error - - # Check for remote access - if server_response: - log = (server_response['mapping_error'] != ext_ping_error) - - if server_response['reason']: - ext_ping_count += 1 - ext_ping_error = server_response['mapping_error'] - if log: - logger.warn("Tautulli Monitor :: Remote access failed: %s, ping attempt %s." - % (server_response['reason'], str(ext_ping_count))) - - # Waiting for port mapping - elif server_response['mapping_state'] == 'waiting': - ext_ping_error = server_response['mapping_error'] - if log: - logger.warn("Tautulli Monitor :: Remote access waiting for port mapping, ping attempt %s." - % str(ext_ping_count)) - - # Reset external ping counter - else: - if ext_ping_count >= plexpy.CONFIG.REMOTE_ACCESS_PING_THRESHOLD: - logger.info("Tautulli Monitor :: Plex remote access is back up.") - - plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extup', 'remote_access_info': server_response}) - - ext_ping_count = 0 - ext_ping_error = None - - if ext_ping_count == plexpy.CONFIG.REMOTE_ACCESS_PING_THRESHOLD: - logger.info("Tautulli Monitor: Plex remote access is down.") - plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extdown', 'remote_access_info': server_response}) - - def check_server_updates(): with monitor_lock: From 99e395ddfa41a67ddb4594ebbfb2e31c21f185d6 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 5 Jul 2020 20:39:31 -0700 Subject: [PATCH 4/5] Update scheduled tasks table * Tautulli/Tautulli-Issues#251 --- data/interfaces/default/scheduler_table.html | 4 ++-- plexpy/common.py | 23 ++++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/data/interfaces/default/scheduler_table.html b/data/interfaces/default/scheduler_table.html index 7cfe3cf3..583a03cb 100644 --- a/data/interfaces/default/scheduler_table.html +++ b/data/interfaces/default/scheduler_table.html @@ -28,7 +28,7 @@ DOCUMENTATION :: END
- % for job in common.SCHEDULER_LIST: + % for job, job_type in common.SCHEDULER_LIST.items(): % if job in scheduled_jobs: <% sched_job = plexpy.SCHED.get_job(job) @@ -41,7 +41,7 @@ DOCUMENTATION :: ENDUse the user defined connection details. Do not retrieve the server connection URL automatically.
Enable to have Tautulli check if updates are available for the Plex Media Server.
Enable to have Tautulli check if remote access to the Plex Media Server goes down.
-The interval (in seconds) Tautulli will ping the Plex Media Server for the remote access status. Minimum 60.
-The number of consecutive remote access status failures to consider remote access as down. Minimum 1.
-