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