diff --git a/data/interfaces/default/css/plexwatch.css b/data/interfaces/default/css/plexwatch.css index a11331a6..e80e73e2 100644 --- a/data/interfaces/default/css/plexwatch.css +++ b/data/interfaces/default/css/plexwatch.css @@ -8438,3 +8438,89 @@ ol.test >li { .stacked-configs > li > span > input[type='checkbox'] { } + +.accordion { + width: 100%; + max-width: 900px; + margin: 0px 0px 20px 0px; + background: #282828; + list-style: none; +} + +.accordion .link { + cursor: pointer; + display: block; + padding: 8px 20px 8px 30px; + color: #999; + border-bottom: 1px solid #2d2d2d; + position: relative; + -webkit-transition: all 0.4s ease; + -o-transition: all 0.4s ease; + transition: all 0.4s ease; +} + +.accordion li:last-child .link { border-bottom: 0; } + +.accordion li i { + position: absolute; + top: 10px; + left: 10px; + color: #999; + -webkit-transition: all 0.4s ease; + -o-transition: all 0.4s ease; + transition: all 0.4s ease; +} + +.accordion li i.fa-chevron-down { + right: 12px; + left: auto; + font-size: 16px; +} + +.accordion li .link:hover { + color: #FFF; + background: #2f2f2f; +} + +.accordion li.open .link { color: #eb8600; } + +.accordion li.open i { color: #eb8600; } + +.accordion li.open i.fa-chevron-down { + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} + +/** + * Submenu + -----------------------------*/ + + +.submenu { + display: none; + background: #2d2d2d; + list-style: none; + margin: 0px; + padding: 20px; +} + +.submenu li { + border-bottom: 1px solid #2f2f2f; +} + +.submenu a { + display: block; + text-decoration: none; + color: #d9d9d9; + padding: 12px; + -webkit-transition: all 0.25s ease; + -o-transition: all 0.25s ease; + transition: all 0.25s ease; +} + +.submenu a:hover { + background: #eb8600; + color: #FFF; +} \ No newline at end of file diff --git a/data/interfaces/default/edit_user.html b/data/interfaces/default/edit_user.html index aafca93b..f699d525 100644 --- a/data/interfaces/default/edit_user.html +++ b/data/interfaces/default/edit_user.html @@ -24,7 +24,7 @@ DOCUMENTATION :: END

Edit user ${data['user']}

+
+
+
+

Custom Notification Messages

+
+

+ You can set custom formatted text for each type of notification. + Click here for a list of available parameters which can be used. +

+
+ +
@@ -493,6 +558,51 @@ +
@@ -502,7 +612,7 @@ <%def name="javascriptIncludes()"> \ No newline at end of file diff --git a/plexpy/config.py b/plexpy/config.py index bcd3ed81..96aacc3b 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -104,6 +104,12 @@ _CONFIG_DEFINITIONS = { 'NMA_ON_STOP': (int, 'NMA', 0), 'NMA_ON_WATCHED': (int, 'NMA', 0), 'NOTIFY_WATCHED_PERCENT': (int, 'Monitoring', 85), + 'NOTIFY_ON_START_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'), + 'NOTIFY_ON_START_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) started playing {title}.'), + 'NOTIFY_ON_STOP_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'), + 'NOTIFY_ON_STOP_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has stopped {title}.'), + 'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'), + 'NOTIFY_ON_WATCHED_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has watched {title}.'), 'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/PlexPy'), 'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0), 'OSX_NOTIFY_ON_PLAY': (int, 'OSX_Notify', 0), diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py index 872f461e..f2bfb0a3 100644 --- a/plexpy/datafactory.py +++ b/plexpy/datafactory.py @@ -607,19 +607,19 @@ class DataFactory(object): 'thumb, parent_thumb, media_index, parent_media_index, year, started, user ' \ 'FROM session_history_metadata ' \ 'JOIN session_history ON session_history_metadata.id = session_history.id ' \ - 'WHERE user_id = ? ORDER BY started DESC LIMIT ?' + 'WHERE user_id = ? AND session_history.media_type != "track" ORDER BY started DESC LIMIT ?' result = monitor_db.select(query, args=[user_id, limit]) elif user: query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, title, ' \ 'thumb, parent_thumb, media_index, parent_media_index, year, started, user ' \ 'FROM session_history_metadata ' \ 'JOIN session_history ON session_history_metadata.id = session_history.id ' \ - 'WHERE user = ? ORDER BY started DESC LIMIT ?' + 'WHERE user = ? AND session_history.media_type != "track" ORDER BY started DESC LIMIT ?' result = monitor_db.select(query, args=[user, limit]) else: query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, title, ' \ 'thumb, parent_thumb, media_index, parent_media_index, year, started, user ' \ - 'FROM session_history_metadata ' \ + 'FROM session_history_metadata WHERE session_history.media_type != "track"' \ 'JOIN session_history ON session_history_metadata.id = session_history.id ' \ 'ORDER BY started DESC LIMIT ?' result = monitor_db.select(query, args=[limit]) diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 3f7ff149..ffcbe37d 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -19,28 +19,9 @@ import plexpy import time def notify(stream_data=None, notify_action=None): - from plexpy import pmsconnect, common, datafactory + from plexpy import datafactory if stream_data and notify_action: - # Get the server name - pms_connect = pmsconnect.PmsConnect() - server_name = pms_connect.get_server_pref(pref='FriendlyName') - - # Build the notification heading - notify_header = 'PlexPy (%s)' % server_name - - # Build media item title - if stream_data['media_type'] == 'episode' or stream_data['media_type'] == 'track': - item_title = '%s - %s' % (stream_data['grandparent_title'], stream_data['title']) - elif stream_data['media_type'] == 'movie': - item_title = stream_data['title'] - else: - item_title = stream_data['title'] - - if notify_action == 'play': - logger.info('PlexPy Notifier :: %s (%s) started playing %s.' % (stream_data['friendly_name'], - stream_data['player'], item_title)) - # Check if notifications enabled for user data_factory = datafactory.DataFactory() user_details = data_factory.get_user_friendly_name(user=stream_data['user']) @@ -53,34 +34,47 @@ def notify(stream_data=None, notify_action=None): for agent in notifiers.available_notification_agents(): if agent['on_play'] and notify_action == 'play': - logger.debug("PlexPy Notifier :: %s agent is configured to notify on playback start." % agent['name']) - message = '%s (%s) started playing %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='play', agent_info=agent) + elif agent['on_stop'] and notify_action == 'stop': - logger.debug("PlexPy Notifier :: %s agent is configured to notify on playback stop." % agent['name']) - message = '%s (%s) has stopped %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='stop', 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): - logger.debug("PlexPy Notifier :: %s agent is configured to notify on watched." % agent['name']) - message = '%s (%s) has watched %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='watched', 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']): - logger.debug("PlexPy Notifier :: %s agent is configured to notify on watched." % agent['name']) - message = '%s (%s) has watched %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='watched', agent_info=agent) elif stream_data['media_type'] == 'track': @@ -88,16 +82,21 @@ def notify(stream_data=None, notify_action=None): for agent in notifiers.available_notification_agents(): if agent['on_play'] and notify_action == 'play': - logger.debug("PlexPy Notifier :: %s agent is configured to notify on playback start." % agent['name']) - message = '%s (%s) started playing %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='play', agent_info=agent) + elif agent['on_stop'] and notify_action == 'stop': - logger.debug("PlexPy Notifier :: %s agent is configured to notify on playback stop." % agent['name']) - message = '%s (%s) has stopped %s.' % \ - (stream_data['friendly_name'], stream_data['player'], item_title) - notifiers.send_notification(config_id=agent['id'], subject=notify_header, body=message) + # 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='stop', agent_info=agent) elif stream_data['media_type'] == 'clip': @@ -151,3 +150,100 @@ def set_notify_state(session, state, agent_info): monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values) else: logger.error('PlexPy Notifier :: Unable to set notify state.') + +def build_notify_text(session, state): + from plexpy import pmsconnect + + # Get the server name + pms_connect = pmsconnect.PmsConnect() + server_name = pms_connect.get_server_pref(pref='FriendlyName') + + # Create a title + if session['media_type'] == 'episode': + full_title = '%s - %s' % (session['grandparent_title'], + session['title']) + elif session['media_type'] == 'track': + full_title = '%s - %s' % (session['grandparent_title'], + session['title']) + else: + full_title = session['title'] + + # Generate a combined transcode decision value + if session['video_decision']: + transcode_decision = 'V:%s/A:%s' % (session['video_decision'], session['audio_decision']) + else: + transcode_decision = 'A:%s' % session['audio_decision'] + + available_params = {'server_name': server_name, + 'user': session['friendly_name'], + 'player': session['player'], + 'title': full_title, + 'platform': session['platform'], + 'media_type': session['media_type'], + 'transcode_decision': transcode_decision} + + # Default subject text + subject_text = 'PlexPy (%s)' % server_name + + if state == 'play': + # Default body text + body_text = '%s (%s) is watching %s' % (session['friendly_name'], + session['player'], + full_title) + + if plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT and plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT: + try: + subject_text = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using default.") + + try: + body_text = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using default.") + + return [subject_text, body_text] + else: + return [subject_text, body_text] + elif state == 'stop': + # Default body text + body_text = '%s (%s) has stopped %s' % (session['friendly_name'], + session['player'], + full_title) + + if plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT and plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT: + try: + subject_text = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using default.") + + try: + body_text = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using default.") + + return [subject_text, body_text] + else: + return [subject_text, body_text] + elif state == 'watched': + # Default body text + body_text = '%s (%s) has watched %s' % (session['friendly_name'], + session['player'], + full_title) + + if plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT and plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT: + try: + subject_text = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using default.") + + try: + body_text = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT.format(**available_params) + except: + logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using default.") + + return [subject_text, body_text] + else: + return [subject_text, body_text] + else: + return None diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 6277991a..289938ec 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -407,7 +407,13 @@ class WebInterface(object): "music_logging_enable": checked(plexpy.CONFIG.MUSIC_LOGGING_ENABLE), "logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL, "pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE), - "notify_watched_percent": plexpy.CONFIG.NOTIFY_WATCHED_PERCENT + "notify_watched_percent": plexpy.CONFIG.NOTIFY_WATCHED_PERCENT, + "notify_on_start_subject_text": plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT, + "notify_on_start_body_text": plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT, + "notify_on_stop_subject_text": plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT, + "notify_on_stop_body_text": plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT, + "notify_on_watched_subject_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT, + "notify_on_watched_body_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT } return serve_template(templatename="settings.html", title="Settings", config=config) @@ -1075,7 +1081,9 @@ class WebInterface(object): 'I LIED!', 'See you at the party, Richter!', 'Are you Sarah Conner?', - 'I\'m a cop you idiot!' + 'I\'m a cop you idiot!', + 'Come with me if you want to live.', + 'Who is your daddy and what does he do?' ] random_number = randint(0, len(quote_list) - 1)