diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 2a4f45d1..f8e39615 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -405,9 +405,9 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
-

Enable to have PlexPy check if remote access to the Plex Media Server goes down. (Must have remote access set up in Plex.)

+

Enable to have PlexPy check if remote access to the Plex Media Server goes down. Your server needs to have remote access enabled.

@@ -479,7 +479,12 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
+
+
+
@@ -527,7 +532,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
-

Set the delay for recently added notifications to allow metadata to be processes. Minimum 60 seconds.

+

Set the delay for recently added notifications to allow metadata to be processed. Minimum 60 seconds.

diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html index 3f50ad63..e4388b65 100644 --- a/data/interfaces/default/welcome.html +++ b/data/interfaces/default/welcome.html @@ -1,4 +1,4 @@ -<% +<% import plexpy from plexpy import common %> @@ -130,7 +130,10 @@ from plexpy import common

PlexPy supports a wide variety of notification options. To set up a notification agent conifgure this in Settings -> Notification Agents after you have completed this setup wizard.


- Enable notifications on Movie and TV playback + Enable notifications on Movie playback +
+
+ Enable notifications on TV Show playback
Enable notifications on Music playback diff --git a/plexpy/activity_pinger.py b/plexpy/activity_pinger.py index d2340d4a..e890e719 100644 --- a/plexpy/activity_pinger.py +++ b/plexpy/activity_pinger.py @@ -18,7 +18,6 @@ from plexpy import logger, pmsconnect, plextv, notification_handler, database, h import threading import plexpy import time -import urllib2 monitor_lock = threading.Lock() ext_ping_count = 0 @@ -226,39 +225,39 @@ def check_server_response(): with monitor_lock: pms_connect = pmsconnect.PmsConnect() - internal_response = pms_connect.get_server_response() - global int_ping_count + server_response = pms_connect.get_server_response() - if not internal_response: + global int_ping_count + global ext_ping_count + + # Check for internal server response + if not server_response: int_ping_count += 1 logger.warn(u"PlexPy Monitor :: Unable to get an internal response from the server, ping attempt %s." \ % str(int_ping_count)) + # Reset internal ping counter else: int_ping_count = 0 - if plexpy.CONFIG.MONITOR_REMOTE_ACCESS: - plex_tv = plextv.PlexTV() - external_response = plex_tv.get_server_response() - global ext_ping_count + # Check for remote access + if server_response and plexpy.CONFIG.MONITOR_REMOTE_ACCESS: - if not external_response: - ext_ping_count += 1 - logger.warn(u"PlexPy Monitor :: Plex remote access port mapping failed, ping attempt %s." \ - % str(ext_ping_count)) - else: - host = external_response[0]['host'] - port = external_response[0]['port'] + mapping_state = server_response['mapping_state'] + mapping_error = server_response['mapping_error'] - try: - http_response = urllib2.urlopen('http://' + host + ':' + port) - except urllib2.HTTPError, e: - ext_ping_count = 0 - except urllib2.URLError, e: - ext_ping_count += 1 - logger.warn(u"PlexPy Monitor :: Unable to get an external response from the server, ping attempt %s." \ - % str(ext_ping_count)) - else: - ext_ping_count = 0 + # Check if the port is mapped + if not mapping_state == 'mapped': + ext_ping_count += 1 + logger.warn(u"PlexPy Monitor :: Plex remote access port not mapped, ping attempt %s." \ + % str(ext_ping_count)) + # Check if the port is open + elif mapping_error == 'unreachable': + ext_ping_count += 1 + logger.warn(u"PlexPy Monitor :: Plex remote access port mapped, but mapping failed, ping attempt %s." \ + % str(ext_ping_count)) + # Reset external ping counter + else: + ext_ping_count = 0 if int_ping_count == 3: # Fire off notifications diff --git a/plexpy/api.py b/plexpy/api.py index 38714b35..dc9d30ac 100644 --- a/plexpy/api.py +++ b/plexpy/api.py @@ -394,8 +394,8 @@ class Api(object): "grouping_global_history": bool(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY), "grouping_user_history": bool(plexpy.CONFIG.GROUPING_USER_HISTORY), "grouping_charts": bool(plexpy.CONFIG.GROUPING_CHARTS), - "tv_notify_enable": bool(plexpy.CONFIG.TV_NOTIFY_ENABLE), "movie_notify_enable": bool(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), + "tv_notify_enable": bool(plexpy.CONFIG.TV_NOTIFY_ENABLE), "music_notify_enable": bool(plexpy.CONFIG.MUSIC_NOTIFY_ENABLE), "tv_notify_on_start": bool(plexpy.CONFIG.TV_NOTIFY_ON_START), "movie_notify_on_start": bool(plexpy.CONFIG.MOVIE_NOTIFY_ON_START), diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 9d943697..2b91cc85 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -30,13 +30,66 @@ def notify(stream_data=None, notify_action=None): if not user_details['do_notify']: return - if stream_data['media_type'] == 'movie' or stream_data['media_type'] == 'episode': - if plexpy.CONFIG.MOVIE_NOTIFY_ENABLE or plexpy.CONFIG.TV_NOTIFY_ENABLE: + if (stream_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \ + or (stream_data['media_type'] == 'episode' and plexpy.CONFIG.TV_NOTIFY_ENABLE): - progress_percent = helpers.get_percent(stream_data['view_offset'], stream_data['duration']) + progress_percent = helpers.get_percent(stream_data['view_offset'], stream_data['duration']) - for agent in notifiers.available_notification_agents(): - if agent['on_play'] and notify_action == 'play': + for agent in notifiers.available_notification_agents(): + if agent['on_play'] and notify_action == 'play': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + + elif agent['on_stop'] and notify_action == 'stop' \ + and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT): + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + + elif agent['on_pause'] and notify_action == 'pause' \ + and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99): + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + + elif agent['on_resume'] and notify_action == 'resume' \ + and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99): + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + + elif agent['on_buffer'] and notify_action == 'buffer': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + + elif agent['on_watched'] and notify_action == 'watched': + # Get the current states for notifications from our db + notify_states = get_notify_state(session=stream_data) + + # If there is nothing in the notify_log for our agent id but it is enabled we should notify + if not any(d['agent_id'] == agent['id'] for d in notify_states): # Build and send notification notify_strings = build_notify_text(session=stream_data, state=notify_action) notifiers.send_notification(config_id=agent['id'], @@ -45,119 +98,65 @@ def notify(stream_data=None, notify_action=None): # Set the notification state in the db set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - elif agent['on_stop'] and notify_action == 'stop' \ - and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT): - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) + else: + # Check in our notify log if the notification has already been sent + for notify_state in notify_states: + if not notify_state['on_watched'] and (notify_state['agent_id'] == agent['id']): + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + elif (stream_data['media_type'] == 'track' and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE): - elif agent['on_pause'] and notify_action == 'pause' \ - and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99): - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) + for agent in notifiers.available_notification_agents(): + if agent['on_play'] and notify_action == 'play': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + elif agent['on_stop'] and notify_action == 'stop': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - elif agent['on_resume'] and notify_action == 'resume' \ - and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99): - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) + elif agent['on_pause'] and notify_action == 'pause': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + elif agent['on_resume'] and notify_action == 'resume': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - elif agent['on_buffer'] and notify_action == 'buffer': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif agent['on_watched'] and notify_action == 'watched': - # Get the current states for notifications from our db - notify_states = get_notify_state(session=stream_data) - - # If there is nothing in the notify_log for our agent id but it is enabled we should notify - if not any(d['agent_id'] == agent['id'] for d in notify_states): - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - else: - # Check in our notify log if the notification has already been sent - for notify_state in notify_states: - if not notify_state['on_watched'] and (notify_state['agent_id'] == agent['id']): - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif stream_data['media_type'] == 'track': - if plexpy.CONFIG.MUSIC_NOTIFY_ENABLE: - - for agent in notifiers.available_notification_agents(): - if agent['on_play'] and notify_action == 'play': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif agent['on_stop'] and notify_action == 'stop': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif agent['on_pause'] and notify_action == 'pause': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif agent['on_resume'] and notify_action == 'resume': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) - - elif agent['on_buffer'] and notify_action == 'buffer': - # Build and send notification - notify_strings = build_notify_text(session=stream_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=stream_data, state=notify_action, agent_info=agent) + elif agent['on_buffer'] and notify_action == 'buffer': + # Build and send notification + notify_strings = build_notify_text(session=stream_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=stream_data, state=notify_action, agent_info=agent) elif stream_data['media_type'] == 'clip': pass @@ -170,15 +169,22 @@ def notify(stream_data=None, notify_action=None): def notify_timeline(timeline_data=None, notify_action=None): if timeline_data and notify_action: - for agent in notifiers.available_notification_agents(): - if agent['on_created'] and notify_action == 'created': - # Build and send notification - notify_strings = build_notify_text(timeline=timeline_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1]) - # Set the notification state in the db - set_notify_state(session=timeline_data, state=notify_action, agent_info=agent) + if (timeline_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \ + or ((timeline_data['media_type'] == 'show' or timeline_data['media_type'] == 'episode') \ + and plexpy.CONFIG.TV_NOTIFY_ENABLE) \ + or ((timeline_data['media_type'] == 'artist' or timeline_data['media_type'] == 'track') \ + and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE): + + for agent in notifiers.available_notification_agents(): + if agent['on_created'] and notify_action == 'created': + # Build and send notification + notify_strings = build_notify_text(timeline=timeline_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1]) + # Set the notification state in the db + set_notify_state(session=timeline_data, state=notify_action, agent_info=agent) + elif not timeline_data and notify_action: for agent in notifiers.available_notification_agents(): if agent['on_extdown'] and notify_action == 'extdown': diff --git a/plexpy/plextv.py b/plexpy/plextv.py index 76c55d69..1c6682a1 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -462,23 +462,4 @@ class PlexTV(object): }) break - return server_times - - def get_server_response(self): - response = self.get_plextv_server_list(output_format='xml') - - server_url = [] - - try: - xml_head = response.getElementsByTagName('Server') - except: - return False - - for a in xml_head: - if helpers.get_xml_attr(a, 'machineIdentifier') == plexpy.CONFIG.PMS_IDENTIFIER: - server_url.append({"host": helpers.get_xml_attr(a, 'host'), - "port": helpers.get_xml_attr(a, 'port') - }) - break - - return server_url \ No newline at end of file + return server_times \ No newline at end of file diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index e647b34c..a313813a 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -271,6 +271,36 @@ class PmsConnect(object): return request """ + Return account details. + + Optional parameters: output_format { dict, json } + + Output: array + """ + def get_account(self, output_format=''): + uri = '/myplex/account' + request = self.request_handler.make_request(uri=uri, + proto=self.protocol, + request_type='GET', + output_format=output_format) + + return request + + """ + Refresh Plex remote access port mapping. + + Optional parameters: None + + Output: None + """ + def put_refresh_reachability(self): + uri = '/myplex/refreshReachability' + request = self.request_handler.make_request(uri=uri, + proto=self.protocol, + request_type='PUT') + + return request + """ Return processed and validated list of recently added items. Parameters required: count { number of results to return } @@ -1650,15 +1680,24 @@ class PmsConnect(object): return key_list - """ - Check for a server response. - - Output: bool - """ def get_server_response(self): - response = self.get_server_list() + # Refresh Plex remote access port mapping first + self.put_refresh_reachability() + account_data = self.get_account(output_format='xml') + + try: + xml_head = account_data.getElementsByTagName('MyPlex') + except: + logger.warn("Unable to parse XML for get_server_response.") + return None + + server_response = {} - if not response: - return False - else: - return True + for a in xml_head: + server_response = {'mapping_state': helpers.get_xml_attr(a, 'mappingState'), + 'mapping_error': helpers.get_xml_attr(a, 'mappingError'), + 'public_address': helpers.get_xml_attr(a, 'publicAddress'), + 'public_port': helpers.get_xml_attr(a, 'publicPort') + } + + return server_response \ No newline at end of file diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 24233bc1..ba09435d 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -90,8 +90,8 @@ class WebInterface(object): "pms_token": plexpy.CONFIG.PMS_TOKEN, "pms_ssl": checked(plexpy.CONFIG.PMS_SSL), "pms_uuid": plexpy.CONFIG.PMS_UUID, - "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "movie_notify_enable": checked(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), + "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "music_notify_enable": checked(plexpy.CONFIG.MUSIC_NOTIFY_ENABLE), "tv_notify_on_start": checked(plexpy.CONFIG.TV_NOTIFY_ON_START), "movie_notify_on_start": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_START), @@ -423,8 +423,8 @@ class WebInterface(object): "grouping_global_history": checked(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY), "grouping_user_history": checked(plexpy.CONFIG.GROUPING_USER_HISTORY), "grouping_charts": checked(plexpy.CONFIG.GROUPING_CHARTS), - "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "movie_notify_enable": checked(plexpy.CONFIG.MOVIE_NOTIFY_ENABLE), + "tv_notify_enable": checked(plexpy.CONFIG.TV_NOTIFY_ENABLE), "music_notify_enable": checked(plexpy.CONFIG.MUSIC_NOTIFY_ENABLE), "tv_notify_on_start": checked(plexpy.CONFIG.TV_NOTIFY_ON_START), "movie_notify_on_start": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_START), @@ -486,7 +486,7 @@ class WebInterface(object): checked_configs = [ "launch_browser", "enable_https", "api_enabled", "freeze_db", "check_github", "grouping_global_history", "grouping_user_history", "grouping_charts", "pms_use_bif", "pms_ssl", - "tv_notify_enable", "movie_notify_enable", "music_notify_enable", "monitoring_use_websocket", + "movie_notify_enable", "tv_notify_enable", "music_notify_enable", "monitoring_use_websocket", "tv_notify_on_start", "movie_notify_on_start", "music_notify_on_start", "tv_notify_on_stop", "movie_notify_on_stop", "music_notify_on_stop", "tv_notify_on_pause", "movie_notify_on_pause", "music_notify_on_pause", "refresh_users_on_startup",