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 :: END ${helpers.format_timedelta_Hms(sched_job.next_run_time - now)} ${sched_job.next_run_time.astimezone(plexpy.SYS_TIMEZONE).strftime('%Y-%m-%d %H:%M:%S')} - % elif job in ('Check for server response', 'Check for active sessions', 'Check for recently added items') and plexpy.WS_CONNECTED: + % elif job_type == 'websocket' and plexpy.WS_CONNECTED: % if job == 'Check for active sessions': ${job} diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 9d8fcc20..a8f5e742 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -775,7 +775,6 @@ -

Use the user defined connection details. Do not retrieve the server connection URL automatically.

@@ -832,7 +831,6 @@ -

Enable to have Tautulli check if updates are available for the Plex Media Server.

@@ -866,36 +864,6 @@

-
- - - -

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.

-
-
@@ -2158,7 +2126,6 @@ $(document).ready(function() { initConfigCheckbox('#https_create_cert'); initConfigCheckbox('#check_github'); initConfigCheckbox('#monitor_pms_updates'); - initConfigCheckbox('#monitor_remote_access'); initConfigCheckbox('#newsletter_self_hosted'); $('#menu_link_shutdown').click(function() { @@ -2404,7 +2371,6 @@ $(document).ready(function() { $('#pms_is_cloud').val(is_cloud !== 'undefined' && is_cloud === true ? 1 : 0); $('#pms_url_manual').prop('checked', false); $('#pms_url').val('Please verify your server above to retrieve the URL'); - PMSCloudCheck(); }, onDropdownOpen: function() { this.clear(); @@ -2435,38 +2401,6 @@ $(document).ready(function() { } getServerOptions(); - function PMSCloudCheck() { - if ($('#pms_is_cloud').val() === "1") { - $('#pms_port').val(443).prop('readonly', true); - $('#pms_is_remote_checkbox').prop('checked', true).prop('disabled', true); - $('#pms_is_remote').val(1); - $('#pms_ssl_checkbox').prop('checked', true).prop('disabled', true); - $('#pms_ssl').val(1); - $('#pms_url_manual').prop('checked', false).prop('disabled', true); - $('#monitor_pms_updates').prop('checked', false).prop('disabled', true); - $('#pms_update_options').hide(); - $('#monitor_remote_access').prop('checked', false).prop('disabled', true); - $('#cloudManualConnection').show(); - $('#cloudMonitorUpdates').show(); - $('#cloudMonitorRemoteAccess').show(); - $('#remoteAccessCheck').hide(); - } else { - $('#pms_port').prop('readonly', false); - $('#pms_is_remote_checkbox').prop('disabled', false); - $('#pms_is_remote').val($('#pms_is_remote_checkbox').is(':checked') ? 1 : 0); - $('#pms_ssl_checkbox').prop('disabled', false); - $('#pms_ssl').val($('#pms_ssl_checkbox').is(':checked') ? 1 : 0); - $('#pms_url_manual').prop('disabled', false); - $('#monitor_pms_updates').prop('disabled', false); - $('#monitor_remote_access').prop('disabled', false); - $('#cloudManualConnection').hide(); - $('#cloudMonitorUpdates').hide(); - $('#cloudMonitorRemoteAccess').hide(); - remoteAccessEnabledCheck() - } - } - PMSCloudCheck(); - function verifyServer(_callback) { var pms_ip = $("#pms_ip").val(); var pms_port = $("#pms_port").val(); @@ -2583,21 +2517,6 @@ $(document).ready(function() { pms_logs_debug = false; pms_logs = false; - function remoteAccessEnabledCheck() { - $.ajax({ - url: 'get_server_pref', - data: { pref: 'PublishServerOnPlexOnlineKey' }, - async: true, - success: function(data) { - if (data === 'false' || data === '0') { - $("#remoteAccessCheck").html("Remote access must be enabled on your Plex Server. Click here for help."); - $("#monitor_remote_access").attr("checked", false).attr("disabled", true); - } - } - }); - } - remoteAccessEnabledCheck(); - // Sortable home_sections function set_home_sections() { var home_sections = []; diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 68796580..ca59d672 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -136,6 +136,7 @@ DEV = False WEBSOCKET = None WS_CONNECTED = False PLEX_SERVER_UP = None +PLEX_REMOTE_ACCESS_UP = None TRACKER = None @@ -443,10 +444,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) @@ -469,8 +466,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_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/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: diff --git a/plexpy/common.py b/plexpy/common.py index 883c83f9..c509e070 100644 --- a/plexpy/common.py +++ b/plexpy/common.py @@ -217,18 +217,19 @@ EXTRA_TYPES = { } SCHEDULER_LIST = [ - 'Check GitHub for updates', - 'Check for server response', - 'Check for active sessions', - 'Check for recently added items', - 'Check for Plex updates', - 'Check for Plex remote access', - 'Refresh users list', - 'Refresh libraries list', - 'Refresh Plex server URLs', - 'Backup Tautulli database', - 'Backup Tautulli config' + ('Check GitHub for updates', 'websocket'), + ('Check for server response', 'websocket'), + ('Check for active sessions', 'websocket'), + ('Check for recently added items', 'websocket'), + ('Check for server remote access', 'websocket'), + ('Check for Plex updates', 'scheduled'), + ('Refresh users list', 'scheduled'), + ('Refresh libraries list', 'scheduled'), + ('Refresh Plex server URLs', 'scheduled'), + ('Backup Tautulli database', 'scheduled'), + ('Backup Tautulli config', 'scheduled') ] +SCHEDULER_LIST = OrderedDict(SCHEDULER_LIST) DATE_TIME_FORMATS = [ { 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: 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 diff --git a/plexpy/webserve.py b/plexpy/webserve.py index d01af716..375db16b 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2997,9 +2997,6 @@ class WebInterface(object): "grouping_user_history": checked(plexpy.CONFIG.GROUPING_USER_HISTORY), "grouping_charts": checked(plexpy.CONFIG.GROUPING_CHARTS), "monitor_pms_updates": checked(plexpy.CONFIG.MONITOR_PMS_UPDATES), - "monitor_remote_access": checked(plexpy.CONFIG.MONITOR_REMOTE_ACCESS), - "remote_access_ping_interval": plexpy.CONFIG.REMOTE_ACCESS_PING_INTERVAL, - "remote_access_ping_threshold": plexpy.CONFIG.REMOTE_ACCESS_PING_THRESHOLD, "refresh_libraries_interval": plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL, "refresh_libraries_on_startup": checked(plexpy.CONFIG.REFRESH_LIBRARIES_ON_STARTUP), "refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL, @@ -3077,7 +3074,7 @@ class WebInterface(object): "refresh_libraries_on_startup", "refresh_users_on_startup", "notify_consecutive", "notify_recently_added_upgrade", "notify_group_recently_added_grandparent", "notify_group_recently_added_parent", - "monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist", "http_hash_password", + "monitor_pms_updates", "get_file_sizes", "log_blacklist", "http_hash_password", "allow_guest_access", "cache_images", "http_proxy", "http_basic_auth", "notify_concurrent_by_ip", "history_table_activity", "plexpy_auto_update", "themoviedb_lookup", "tvmaze_lookup", "musicbrainz_lookup", "http_plex_admin", @@ -3130,8 +3127,6 @@ class WebInterface(object): kwargs.get('refresh_users_interval') != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL) or \ kwargs.get('pms_update_check_interval') != str(plexpy.CONFIG.PMS_UPDATE_CHECK_INTERVAL) or \ kwargs.get('monitor_pms_updates') != plexpy.CONFIG.MONITOR_PMS_UPDATES or \ - kwargs.get('monitor_remote_access') != plexpy.CONFIG.MONITOR_REMOTE_ACCESS or \ - kwargs.get('remote_access_ping_interval') != str(plexpy.CONFIG.REMOTE_ACCESS_PING_INTERVAL) or \ kwargs.get('pms_url_manual') != plexpy.CONFIG.PMS_URL_MANUAL: reschedule = True