diff --git a/data/interfaces/default/notifiers_table.html b/data/interfaces/default/notifiers_table.html
index 5a86ebf4..c446227d 100644
--- a/data/interfaces/default/notifiers_table.html
+++ b/data/interfaces/default/notifiers_table.html
@@ -10,7 +10,7 @@ DOCUMENTATION :: END
%doc>
- % for notifier in notifiers_list:
+ % for notifier in sorted(notifiers_list, key=lambda k: (k['agent_label'], k['id'])):
-
diff --git a/plexpy/__init__.py b/plexpy/__init__.py
index 75eefb73..168e4c6f 100644
--- a/plexpy/__init__.py
+++ b/plexpy/__init__.py
@@ -14,6 +14,7 @@
# along with PlexPy. If not, see .
import os
+from Queue import Queue
import sqlite3
import sys
import subprocess
@@ -35,6 +36,7 @@ import activity_pinger
import config
import database
import logger
+import notification_handler
import plextv
import pmsconnect
import versioncheck
@@ -58,6 +60,8 @@ PIDFILE = None
SCHED = BackgroundScheduler()
SCHED_LOCK = threading.Lock()
+NOTIFY_QUEUE = Queue()
+
INIT_LOCK = threading.Lock()
_INITIALIZED = False
started = False
@@ -345,7 +349,6 @@ def initialize_scheduler():
# Debug
#SCHED.print_jobs()
-
def schedule_job(function, name, hours=0, minutes=0, seconds=0, args=None):
"""
Start scheduled job if starting or restarting plexpy.
@@ -374,6 +377,13 @@ def start():
if _INITIALIZED:
initialize_scheduler()
+
+ # Start background notification thread
+ if any([CONFIG.MOVIE_NOTIFY_ENABLE, CONFIG.TV_NOTIFY_ENABLE,
+ CONFIG.MUSIC_NOTIFY_ENABLE, CONFIG.NOTIFY_RECENTLY_ADDED]):
+ logger.info(u"Starting background notification handler.")
+ notification_handler.start_thread(num_threads=3)
+
started = True
@@ -450,8 +460,8 @@ def dbcheck():
c_db.execute(
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp INTEGER, '
'session_key INTEGER, rating_key INTEGER, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
- 'user_id INTEGER, user TEXT, agent_id INTEGER, agent_name TEXT, notify_action TEXT, '
- 'subject_text TEXT, body_text TEXT, script_args TEXT, poster_url TEXT)'
+ 'user_id INTEGER, user TEXT, notifier_id INTEGER, agent_id INTEGER, agent_name TEXT, notify_action TEXT, '
+ 'subject_text TEXT, body_text TEXT, poster_url TEXT)'
)
# library_sections table :: This table keeps record of the servers library sections
@@ -899,6 +909,15 @@ def dbcheck():
'ALTER TABLE notify_log_temp RENAME TO notify_log'
)
+ # Upgrade notify_log table from earlier versions
+ try:
+ c_db.execute('SELECT notifier_id FROM notify_log')
+ except sqlite3.OperationalError:
+ logger.debug(u"Altering database. Updating database table notify_log.")
+ c_db.execute(
+ 'ALTER TABLE notify_log ADD COLUMN notifier_id INTEGER'
+ )
+
# Upgrade library_sections table from earlier versions (remove UNIQUE constraint on section_id)
try:
result = c_db.execute('SELECT SQL FROM sqlite_master WHERE type="table" AND name="library_sections"').fetchone()
diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py
index 313fef77..401a7d31 100644
--- a/plexpy/activity_handler.py
+++ b/plexpy/activity_handler.py
@@ -74,35 +74,16 @@ class ActivityHandler(object):
session = self.get_live_session()
- # Check if any notification agents have notifications enabled
- if any(d['on_play'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=session, notify_action='play')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=session, notify_action='on_play'))
# Write the new session to our temp session table
self.update_db_session(session=session)
- # Check if any notification agents have notifications enabled
- if any(d['on_concurrent'] for d in notifiers.available_notification_agents()):
- # Check if any concurrent streams by the user
- ip = True if plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP else None
- ap = activity_processor.ActivityProcessor()
- user_sessions = ap.get_session_by_user_id(user_id=session['user_id'], ip_address=ip)
- if len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD:
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=session, notify_action='concurrent')).start()
-
- # Check if any notification agents have notifications enabled
- if any(d['on_newdevice'] for d in notifiers.available_notification_agents()):
- # Check if any concurrent streams by the user
- data_factory = datafactory.DataFactory()
- user_devices = data_factory.get_user_devices(user_id=session['user_id'])
- if session['machine_id'] not in user_devices:
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=session, notify_action='newdevice')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=session, notify_action='on_concurrent'))
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=session, notify_action='on_newdevice'))
def on_stop(self, force_stop=False):
if self.is_valid_session():
@@ -123,11 +104,8 @@ class ActivityHandler(object):
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
- # Check if any notification agents have notifications enabled
- if any(d['on_stop'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=db_session, notify_action='stop')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=db_session, notify_action='on_stop'))
# Write it to the history table
monitor_proc = activity_processor.ActivityProcessor()
@@ -154,11 +132,8 @@ class ActivityHandler(object):
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
- # Check if any notification agents have notifications enabled
- if any(d['on_pause'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=db_session, notify_action='pause')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=db_session, notify_action='on_pause'))
def on_resume(self):
if self.is_valid_session():
@@ -176,11 +151,8 @@ class ActivityHandler(object):
# Retrieve the session data from our temp table
db_session = ap.get_session_by_key(session_key=self.get_session_key())
- # Check if any notification agents have notifications enabled
- if any(d['on_resume'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=db_session, notify_action='resume')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=db_session, notify_action='on_resume'))
def on_buffer(self):
if self.is_valid_session():
@@ -209,10 +181,8 @@ class ActivityHandler(object):
time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT):
ap.set_session_buffer_trigger_time(session_key=self.get_session_key())
- # Check if any notification agents have notifications enabled
- if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=db_stream, notify_action='buffer')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=db_session, notify_action='on_buffer'))
# This function receives events from our websocket connection
def process(self):
@@ -254,17 +224,9 @@ class ActivityHandler(object):
# Monitor if the stream has reached the watch percentage for notifications
# The only purpose of this is for notifications
- # Check if any notification agents have notifications enabled
- notify_agents = [d['id'] for d in notifiers.available_notification_agents() if d['on_watched']]
- # Get the current states for notifications from our db
- notified_agents = [d['agent_id'] for d in notification_handler.get_notify_state(session=db_session)
- if d['notify_action'] == 'watched'] if notify_agents else []
-
- if any(a not in notified_agents for a in notify_agents):
- progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
- if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering':
- # Rather not put this on it's own thread so we know it completes before our next event.
- notification_handler.notify(stream_data=db_session, notify_action='watched')
+ if this_state != 'buffering':
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=db_session, notify_action='on_watched'))
else:
# We don't have this session in our table yet, start a new one.
diff --git a/plexpy/activity_pinger.py b/plexpy/activity_pinger.py
index 98127b7f..214f64a8 100644
--- a/plexpy/activity_pinger.py
+++ b/plexpy/activity_pinger.py
@@ -48,11 +48,9 @@ def check_active_sessions(ws_request=False):
if int_ping_count >= 3:
logger.info(u"PlexPy Monitor :: The Plex Media Server is back up.")
- # Check if any notification agents have notifications enabled
- if any(d['on_intup'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(notify_action='intup')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ notify_action='on_intup'))
+
int_ping_count = 0
media_container = session_list['sessions']
@@ -72,22 +70,14 @@ def check_active_sessions(ws_request=False):
if session['state'] == 'paused':
logger.debug(u"PlexPy Monitor :: Session %s has been paused." % stream['session_key'])
- # Check if any notification agents have notifications enabled
- if any(d['on_pause'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='pause')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_pause'))
if session['state'] == 'playing' and stream['state'] == 'paused':
logger.debug(u"PlexPy Monitor :: Session %s has been resumed." % stream['session_key'])
- # Check if any notification agents have notifications enabled
- if any(d['on_resume'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='resume')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_resume'))
if stream['state'] == 'paused' and not ws_request:
# The stream is still paused so we need to increment the paused_counter
@@ -125,12 +115,9 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['session_key'], stream['rating_key']])
- # Check if any notification agents have notifications enabled
- if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='buffer')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_buffer'))
+
else:
# Subsequent buffer notifications after wait time
if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
@@ -143,12 +130,8 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['session_key'], stream['rating_key']])
- # Check if any notification agents have notifications enabled
- if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='buffer')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_buffer'))
logger.debug(u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
% (stream['session_key'],
@@ -158,15 +141,8 @@ def check_active_sessions(ws_request=False):
# Check if the user has reached the offset in the media we defined as the "watched" percent
# Don't trigger if state is buffer as some clients push the progress to the end when
# buffering on start.
- if session['view_offset'] and session['duration'] and session['state'] != 'buffering':
- if helpers.get_percent(session['view_offset'],
- session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
- # Check if any notification agents have notifications enabled
- if any(d['on_watched'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='watched')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_watched'))
else:
# The user has stopped playing a stream
@@ -180,22 +156,11 @@ def check_active_sessions(ws_request=False):
'WHERE session_key = ? AND rating_key = ?',
[stream['stopped'], 'stopped', stream['session_key'], stream['rating_key']])
- # Check if the user has reached the offset in the media we defined as the "watched" percent
- if stream['view_offset'] and stream['duration']:
- if helpers.get_percent(stream['view_offset'],
- stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
- # Check if any notification agents have notifications enabled
- if any(d['on_watched'] for d in notifiers.available_notification_agents()):
- # Push any notifications -
- # Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='watched')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_watched'))
- # Check if any notification agents have notifications enabled
- if any(d['on_stop'] for d in notifiers.available_notification_agents()):
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=stream, notify_action='stop')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=stream, notify_action='on_stop'))
# Write the item history on playback stop
success = monitor_process.write_session_history(session=stream)
@@ -247,11 +212,8 @@ def check_active_sessions(ws_request=False):
% str(int_ping_count))
if int_ping_count == 3:
- # Check if any notification agents have notifications enabled
- if any(d['on_intdown'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(notify_action='intdown')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ notify_action='on_intdown'))
def check_recently_added():
@@ -304,11 +266,8 @@ def check_recently_added():
if 0 < time_threshold - int(item['added_at']) <= time_interval:
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
- # Check if any notification agents have notifications enabled
- if any(d['on_created'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(timeline_data=item, notify_action='created')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ timeline_data=item, notify_action='on_created'))
else:
item = max(metadata, key=lambda x:x['added_at'])
@@ -326,10 +285,9 @@ def check_recently_added():
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
# Check if any notification agents have notifications enabled
- if any(d['on_created'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(timeline_data=item, notify_action='created')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ timeline_data=item, notify_action='on_created'))
+
def check_server_response():
@@ -360,19 +318,14 @@ def check_server_response():
if ext_ping_count >= 3:
logger.info(u"PlexPy Monitor :: Plex remote access is back up.")
- # Check if any notification agents have notifications enabled
- if any(d['on_extup'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(notify_action='extup')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ notify_action='on_extup'))
+
ext_ping_count = 0
if ext_ping_count == 3:
- # Check if any notification agents have notifications enabled
- if any(d['on_extdown'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(notify_action='extdown')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ notify_action='on_extdown'))
def check_server_updates():
@@ -389,10 +342,8 @@ def check_server_updates():
if download_info['update_available']:
logger.info(u"PlexPy Monitor :: PMS update available version: %s", download_info['version'])
- # Check if any notification agents have notifications enabled
- if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()):
- # Fire off notifications
- threading.Thread(target=notification_handler.notify_timeline,
- kwargs=dict(notify_action='pmsupdate')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ notify_action='on_pmsupdate'))
+
else:
logger.info(u"PlexPy Monitor :: No PMS update available.")
\ No newline at end of file
diff --git a/plexpy/activity_processor.py b/plexpy/activity_processor.py
index dabe91e3..907fead3 100644
--- a/plexpy/activity_processor.py
+++ b/plexpy/activity_processor.py
@@ -97,11 +97,10 @@ class ActivityProcessor(object):
if result == 'insert':
# Check if any notification agents have notifications enabled
- if notify and any(d['on_play'] for d in notifiers.available_notification_agents()):
+ if notify:
values.update({'ip_address': session['ip_address']})
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=values, notify_action='play')).start()
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=values, notify_action='on_play'))
# If it's our first write then time stamp it.
started = int(time.time())
@@ -116,25 +115,11 @@ class ActivityProcessor(object):
ip_address = {'ip_address': ip_address}
self.db.upsert('sessions', ip_address, keys)
- # Check if any notification agents have notifications enabled
- if notify and any(d['on_concurrent'] for d in notifiers.available_notification_agents()):
- # Check if any concurrent streams by the user
- user_sessions = self.get_session_by_user_id(user_id=session['user_id'],
- ip_address=plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP)
- if len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD:
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=values, notify_action='concurrent')).start()
-
- # Check if any notification agents have notifications enabled
- if notify and any(d['on_newdevice'] for d in notifiers.available_notification_agents()):
- # Check if any concurrent streams by the user
- data_factory = datafactory.DataFactory()
- user_devices = data_factory.get_user_devices(user_id=session['user_id'])
- if session['machine_id'] not in user_devices:
- # Push any notifications - Push it on it's own thread so we don't hold up our db actions
- threading.Thread(target=notification_handler.notify,
- kwargs=dict(stream_data=values, notify_action='newdevice')).start()
+ if notify:
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=values, notify_action='on_concurrent'))
+ plexpy.NOTIFY_QUEUE.put(notification_handler.add_to_notify_queue(
+ stream_data=values, notify_action='on_newdevice'))
return True
diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py
index e5b128a9..8212fe3c 100644
--- a/plexpy/notification_handler.py
+++ b/plexpy/notification_handler.py
@@ -22,6 +22,7 @@ import threading
import time
import plexpy
+import activity_processor
import database
import datafactory
import libraries
@@ -32,8 +33,43 @@ import plextv
import pmsconnect
import users
-def notify(stream_data=None, notify_action=None):
- if stream_data and notify_action:
+def process_queue():
+ queue = plexpy.NOTIFY_QUEUE
+ while True:
+ queue.get()
+ queue.task_done()
+
+
+def start_thread(num_threads=1):
+ for x in range(num_threads):
+ thread = threading.Thread(target=process_queue)
+ thread.daemon = True
+ thread.start()
+
+
+def add_to_notify_queue(notify_action=None, stream_data=None, timeline_data=None):
+ if not notify_action:
+ logger.debug(u"PlexPy NotificationHandler :: Notify called but no action received.")
+ return
+
+ # Check if any notification agents have notifications enabled for the action
+ notifiers_enabled = notifiers.get_notifiers(notify_action=notify_action)
+
+ if notifiers_enabled:
+ for notifier in notifiers_enabled:
+ # Check if notification conditions are satisfied
+ conditions = notify_conditions(notifier=notifier,
+ notify_action=notify_action,
+ stream_data=stream_data,
+ timeline_data=timeline_data)
+ if conditions:
+ plexpy.NOTIFY_QUEUE.put(notify(notifier_id=notifier['id'],
+ notify_action=notify_action,
+ stream_data=stream_data,
+ timeline_data=timeline_data))
+
+def notify_conditions(notifier=None, notify_action=None, stream_data=None, timeline_data=None):
+ if stream_data:
# Check if notifications enabled for user and library
user_data = users.Users()
user_details = user_data.get_details(user_id=stream_data['user_id'])
@@ -43,444 +79,87 @@ def notify(stream_data=None, notify_action=None):
if not user_details['do_notify']:
# logger.debug(u"PlexPy NotificationHandler :: Notifications for user '%s' is disabled." % user_details['username'])
- return
+ return False
elif not library_details['do_notify']:
# logger.debug(u"PlexPy NotificationHandler :: Notifications for library '%s' is disabled." % library_details['section_name'])
- return
+ return False
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'])
- for agent in notifiers.available_notification_agents():
- if agent['on_play'] and notify_action == 'play':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
+ ap = activity_processor.ActivityProcessor()
+ user_sessions = ap.get_session_by_user_id(user_id=stream_data['user_id'],
+ ip_address=plexpy.CONFIG.NOTIFY_CONCURRENT_BY_IP)
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
+ data_factory = datafactory.DataFactory()
+ user_devices = data_factory.get_user_devices(user_id=stream_data['user_id'])
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
+ conditions = \
+ {'on_stop': plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT,
+ 'on_resume': plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99,
+ 'on_watched': progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and \
+ not any(d['agent_id'] == notifier['agent_id'] and d['notify_action'] == notify_action
+ for d in get_notify_state(session=stream_data)),
+ 'on_concurrent': len(user_sessions) >= plexpy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD,
+ 'on_newdevice': stream_data['machine_id'] not in user_devices
+ }
- 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, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_pause'] and notify_action == 'pause' \
- and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_resume'] and notify_action == 'resume' \
- and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_buffer'] and notify_action == 'buffer':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- 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'] and d['notify_action'] == notify_action for d in notify_states):
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_concurrent'] and notify_action == 'concurrent':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_newdevice'] and notify_action == 'newdevice':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
+ return conditions.get(notify_action, True)
elif (stream_data['media_type'] == 'track' and 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, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_stop'] and notify_action == 'stop':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_pause'] and notify_action == 'pause':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_resume'] and notify_action == 'resume':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_buffer'] and notify_action == 'buffer':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_concurrent'] and notify_action == 'concurrent':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif agent['on_newdevice'] and notify_action == 'newdevice':
- # Build and send notification
- notify_strings, metadata = build_notify_text(session=stream_data,
- notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=stream_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif stream_data['media_type'] == 'clip':
- pass
+ return True
else:
- #logger.debug(u"PlexPy NotificationHandler :: Notify called with unsupported media type.")
- pass
+ return False
else:
- logger.debug(u"PlexPy NotificationHandler :: Notify called but incomplete data received.")
+ return True
-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, metadata = build_notify_text(timeline=timeline_data,
- notify_action=notify_action,
- agent_id=agent['id'])
+def notify(notifier_id=None, notify_action=None, stream_data=None, timeline_data=None):
+ notifier_config = notifiers.get_notifier_config(notifier_id=notifier_id)
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action,
- metadata=metadata)
-
- # Set the notification state in the db
- set_notify_state(session=timeline_data,
- notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings,
- metadata=metadata)
-
- elif not timeline_data and notify_action:
- for agent in notifiers.available_notification_agents():
- if agent['on_extdown'] and notify_action == 'extdown':
- # Build and send notification
- notify_strings = build_server_notify_text(notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action)
-
- # Set the notification state in the db
- set_notify_state(notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings)
-
- if agent['on_intdown'] and notify_action == 'intdown':
- # Build and send notification
- notify_strings = build_server_notify_text(notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action)
-
- # Set the notification state in the db
- set_notify_state(notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings)
-
- if agent['on_extup'] and notify_action == 'extup':
- # Build and send notification
- notify_strings = build_server_notify_text(notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action)
-
- # Set the notification state in the db
- set_notify_state(notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings)
-
- if agent['on_intup'] and notify_action == 'intup':
- # Build and send notification
- notify_strings = build_server_notify_text(notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action)
-
- # Set the notification state in the db
- set_notify_state(notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings)
-
- if agent['on_pmsupdate'] and notify_action == 'pmsupdate':
- # Build and send notification
- notify_strings = build_server_notify_text(notify_action=notify_action,
- agent_id=agent['id'])
-
- notifiers.send_notification(agent_id=agent['id'],
- subject=notify_strings[0],
- body=notify_strings[1],
- script_args=notify_strings[2],
- notify_action=notify_action)
-
- # Set the notification state in the db
- set_notify_state(notify_action=notify_action,
- agent_info=agent,
- notify_strings=notify_strings)
+ if not notifier_config:
+ return
+ if stream_data or timeline_data:
+ # Build the notification parameters
+ parameters, metadata = build_media_notify_params(notify_action=notify_action,
+ session=stream_data,
+ timeline=timeline_data)
else:
- logger.debug(u"PlexPy NotificationHandler :: Notify timeline called but incomplete data received.")
+ # Build the notification parameters
+ parameters, metadata = build_server_notify_params(notify_action=notify_action)
+
+ if not parameters:
+ logger.error(u"PlexPy NotificationHandler :: Failed to build notification parameters.")
+ return
+
+ # Get the subject and body strings
+ subject_string = notifier_config['notify_text'][notify_action]['subject']
+ body_string = notifier_config['notify_text'][notify_action]['body']
+
+ # Format the subject and body strings
+ subject, body = build_notify_text(subject=subject_string,
+ body=body_string,
+ notify_action=notify_action,
+ parameters=parameters,
+ agent_id=notifier_config['agent_id'])
+
+ # Send the notification
+ notifiers.send_notification(notifier_id=notifier_config['id'],
+ subject=subject,
+ body=body,
+ notify_action=notify_action,
+ metadata=metadata)
+
+ # Set the notification state in the db
+ set_notify_state(session=stream_data,
+ notify_action=notify_action,
+ notifier=notifier_config,
+ subject=subject,
+ body=body,
+ metadata=metadata)
def get_notify_state(session):
@@ -502,33 +181,28 @@ def get_notify_state(session):
return notify_states
-def set_notify_state(notify_action, agent_info, notify_strings, session=None, metadata=None):
+def set_notify_state(notify_action, notifier, subject, body, session=None, metadata=None):
- if notify_action and agent_info:
+ if notify_action and notifier:
monitor_db = database.MonitorDatabase()
session = session or {}
metadata = metadata or {}
- if notify_strings[2]:
- script_args = '[' + ', '.join(notify_strings[2]) + ']'
- else:
- script_args = None
-
keys = {'timestamp': int(time.time()),
'session_key': session.get('session_key', None),
'rating_key': session.get('rating_key', None),
'user_id': session.get('user_id', None),
- 'agent_id': agent_info['id'],
- 'notify_action': notify_action}
+ 'notifier_id': notifier['id'],
+ 'agent_id': notifier['agent_id'],
+ 'notify_action': notify_action.split('on_')[-1]}
values = {'parent_rating_key': session.get('parent_rating_key', None),
'grandparent_rating_key': session.get('grandparent_rating_key', None),
'user': session.get('user', None),
- 'agent_name': agent_info['name'],
- 'subject_text': notify_strings[0],
- 'body_text': notify_strings[1],
- 'script_args': script_args,
+ 'agent_name': notifier['agent_name'],
+ 'subject_text': subject,
+ 'body_text': body,
'poster_url': metadata.get('poster_url', None)}
monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values)
@@ -536,7 +210,7 @@ def set_notify_state(notify_action, agent_info, notify_strings, session=None, me
logger.error(u"PlexPy NotificationHandler :: Unable to set notify state.")
-def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=None):
+def build_media_notify_params(notify_action=None, session=None, timeline=None):
# Get time formats
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','')
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','')
@@ -574,65 +248,7 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=
metadata = metadata_list['metadata']
else:
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
- return [None, None, None], None
-
- # Check for exclusion tags
- if metadata['media_type'] == 'movie':
- # Regex pattern to remove the text in the tags we don't want
- pattern = re.compile(r'||.*?|.*?', re.IGNORECASE | re.DOTALL)
- elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
- # Regex pattern to remove the text in the tags we don't want
- pattern = re.compile(r'.*?|||.*?', re.IGNORECASE | re.DOTALL)
- elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
- # Regex pattern to remove the text in the tags we don't want
- pattern = re.compile(r'.*?|.*?||', re.IGNORECASE | re.DOTALL)
- else:
- pattern = None
-
- if metadata['media_type'] == 'movie' \
- or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \
- or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
- and pattern:
- # Remove the unwanted tags and strip any unmatch tags too.
- on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT), agent_id)
- on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT), agent_id)
- on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT), agent_id)
- on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT), agent_id)
- on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT), agent_id)
- on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT), agent_id)
- on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT), agent_id)
- on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT), agent_id)
- on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT), agent_id)
- on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT), agent_id)
- on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT), agent_id)
- on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT), agent_id)
- on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT), agent_id)
- on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT), agent_id)
- on_concurrent_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CONCURRENT_SUBJECT_TEXT), agent_id)
- on_concurrent_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CONCURRENT_BODY_TEXT), agent_id)
- on_newdevice_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT), agent_id)
- on_newdevice_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_NEWDEVICE_BODY_TEXT), agent_id)
- script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT), agent_id)
- else:
- on_start_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT, agent_id)
- on_start_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT, agent_id)
- on_stop_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT, agent_id)
- on_stop_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT, agent_id)
- on_pause_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT, agent_id)
- on_pause_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT, agent_id)
- on_resume_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT, agent_id)
- on_resume_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT, agent_id)
- on_buffer_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT, agent_id)
- on_buffer_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT, agent_id)
- on_watched_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT, agent_id)
- on_watched_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT, agent_id)
- on_created_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT, agent_id)
- on_created_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT, agent_id)
- on_concurrent_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_CONCURRENT_SUBJECT_TEXT, agent_id)
- on_concurrent_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_CONCURRENT_BODY_TEXT, agent_id)
- on_newdevice_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT, agent_id)
- on_newdevice_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_NEWDEVICE_BODY_TEXT, agent_id)
- script_args_text = strip_tag(plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT, agent_id)
+ return None, None
# Create a title
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
@@ -855,237 +471,10 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=
'grandparent_rating_key': metadata['grandparent_rating_key']
}
- # Default subject text
- subject_text = 'PlexPy (%s)' % server_name
-
- # Default scripts args
- script_args = []
-
- if script_args_text:
- try:
- script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in script argument. Using fallback." % e)
- except Exception as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom script arguments %s. Using fallback." % e)
-
- if notify_action == 'play':
- # Default body text
- body_text = '%s (%s) started playing %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_start_subject and on_start_body:
- try:
- subject_text = unicode(on_start_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_start_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'stop':
- # Default body text
- body_text = '%s (%s) has stopped %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_stop_subject and on_stop_body:
- try:
- subject_text = unicode(on_stop_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_stop_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'pause':
- # Default body text
- body_text = '%s (%s) has paused %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_pause_subject and on_pause_body:
- try:
- subject_text = unicode(on_pause_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_pause_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'resume':
- # Default body text
- body_text = '%s (%s) has resumed %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_resume_subject and on_resume_body:
- try:
- subject_text = unicode(on_resume_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_resume_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'buffer':
- # Default body text
- body_text = '%s (%s) is buffering %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_buffer_subject and on_buffer_body:
- try:
- subject_text = unicode(on_buffer_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_buffer_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'watched':
- # Default body text
- body_text = '%s (%s) has watched %s' % (session['friendly_name'],
- session['player'],
- full_title)
-
- if on_watched_subject and on_watched_body:
- try:
- subject_text = unicode(on_watched_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_watched_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'created':
- # Default body text
- body_text = '%s was recently added to Plex.' % full_title
-
- if on_created_subject and on_created_body:
- try:
- subject_text = unicode(on_created_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_created_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'concurrent':
- # Default body text
- body_text = '%s has %s concurrent streams.' % (session['friendly_name'],
- user_stream_count)
-
- if on_concurrent_subject and on_concurrent_body:
- try:
- subject_text = unicode(on_concurrent_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_concurrent_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- elif notify_action == 'newdevice':
- # Default body text
- body_text = '%s is streaming from a new device: %s.' % (session['friendly_name'],
- session['player'])
-
- if on_newdevice_subject and on_newdevice_body:
- try:
- subject_text = unicode(on_newdevice_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_newdevice_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args], metadata
- else:
- return [subject_text, body_text, script_args], metadata
- else:
- return [None, None, None], None
+ return available_params, metadata
-def build_server_notify_text(notify_action=None, agent_id=None):
+def build_server_notify_params(notify_action=None):
# Get time formats
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','')
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','')
@@ -1108,20 +497,6 @@ def build_server_notify_text(notify_action=None, agent_id=None):
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
server_uptime = 'N/A'
- pattern = re.compile(r'.*?|.*?|.*?', re.IGNORECASE | re.DOTALL)
-
- on_extdown_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT, agent_id)
- on_extdown_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT, agent_id)
- on_intdown_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT, agent_id)
- on_intdown_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT, agent_id)
- on_extup_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT, agent_id)
- on_extup_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT, agent_id)
- on_intup_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT, agent_id)
- on_intup_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT, agent_id)
- on_pmsupdate_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT, agent_id)
- on_pmsupdate_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_BODY_TEXT, agent_id)
- script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT), agent_id)
-
available_params = {# Global paramaters
'server_name': server_name,
'server_uptime': server_uptime,
@@ -1143,135 +518,55 @@ def build_server_notify_text(notify_action=None, agent_id=None):
'update_changelog_added': update_status.get('changelog_added',''),
'update_changelog_fixed': update_status.get('changelog_fixed','')}
- # Default text
- subject_text = 'PlexPy (%s)' % server_name
+ return available_params, None
- # Default scripts args
- script_args = []
-
- if script_args_text:
- try:
- script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in script argument. Using fallback." % e)
- except Exception as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom script arguments %s. Using fallback." % e)
-
- if notify_action == 'extdown':
- # Default body text
- body_text = 'The Plex Media Server remote access is down.'
-
- if on_extdown_subject and on_extdown_body:
- try:
- subject_text = unicode(on_extdown_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_extdown_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args]
- else:
- return [subject_text, body_text, script_args]
-
- elif notify_action == 'intdown':
- # Default body text
- body_text = 'The Plex Media Server is down.'
-
- if on_intdown_subject and on_intdown_body:
- try:
- subject_text = unicode(on_intdown_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_intdown_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args]
- else:
- return [subject_text, body_text, script_args]
- if notify_action == 'extup':
- # Default body text
- body_text = 'The Plex Media Server remote access is back up.'
-
- if on_extup_subject and on_extup_body:
- try:
- subject_text = unicode(on_extup_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_extup_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args]
- else:
- return [subject_text, body_text, script_args]
- elif notify_action == 'intup':
- # Default body text
- body_text = 'The Plex Media Server is back up.'
-
- if on_intup_subject and on_intup_body:
- try:
- subject_text = unicode(on_intup_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_intup_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args]
- else:
- return [subject_text, body_text, script_args]
-
- elif notify_action == 'pmsupdate':
- # Default body text
- body_text = 'An update is available for the Plex Media Server (version %s).' % available_params['update_version']
-
- if on_pmsupdate_subject and on_pmsupdate_body:
- try:
- subject_text = unicode(on_pmsupdate_subject).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
-
- try:
- body_text = unicode(on_pmsupdate_body).format(**available_params)
- except LookupError as e:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
- except:
- logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
-
- return [subject_text, body_text, script_args]
- else:
- return [subject_text, body_text, script_args]
+def build_notify_text(subject='', body='', notify_action=None, parameters=None, agent_id=None):
+ # Check for exclusion tags
+ if parameters['media_type'] == 'movie':
+ # Regex pattern to remove the text in the tags we don't want
+ pattern = re.compile(r'||.*?|.*?', re.IGNORECASE | re.DOTALL)
+ elif parameters['media_type'] == 'show' or parameters['media_type'] == 'episode':
+ # Regex pattern to remove the text in the tags we don't want
+ pattern = re.compile(r'.*?|||.*?', re.IGNORECASE | re.DOTALL)
+ elif parameters['media_type'] == 'artist' or parameters['media_type'] == 'track':
+ # Regex pattern to remove the text in the tags we don't want
+ pattern = re.compile(r'.*?|.*?||', re.IGNORECASE | re.DOTALL)
else:
- return None
+ pattern = None
+
+ if pattern:
+ # Remove the unwanted tags and strip any unmatch tags too.
+ subject = strip_tag(re.sub(pattern, '', subject), agent_id)
+ body = strip_tag(re.sub(pattern, '', body), agent_id)
+ else:
+ subject = strip_tag(subject, agent_id)
+ body = strip_tag(body, agent_id)
+
+ # Default subject and body text
+ default_action = next((a for a in notifiers.available_notification_actions() if a['name'] == notify_action), {})
+ default_subject = default_action.get('subject', '')
+ default_body = default_action.get('body', '')
+
+ try:
+ subject = unicode(subject).format(**parameters)
+ except LookupError as e:
+ logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
+ subject = unicode(default_subject).format(**parameters)
+ except:
+ logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
+ subject = unicode(default_subject).format(**parameters)
+
+ try:
+ body = unicode(body).format(**parameters)
+ except LookupError as e:
+ logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
+ subject = unicode(default_body).format(**parameters)
+ except:
+ logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
+ subject = unicode(default_body).format(**parameters)
+
+ return subject, body
def strip_tag(data, agent_id=None):
diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py
index 508b0952..26c208ed 100644
--- a/plexpy/notifiers.py
+++ b/plexpy/notifiers.py
@@ -339,7 +339,7 @@ def get_notifiers(notifier_id=None, notify_action=None):
for item in result:
item['active'] = int(any([item.pop(k) for k in item.keys() if k in notify_actions]))
- return sorted(result, key=lambda k: (k['agent_label'], k['id']))
+ return result
def delete_notifier(notifier_id=None):
@@ -357,7 +357,7 @@ def get_notifier_config(notifier_id=None):
if str(notifier_id).isdigit():
notifier_id = int(notifier_id)
else:
- logger.error(u"PlexPy Notifiers :: Unable to retrieve notifier config: invalid notifier_id.")
+ logger.error(u"PlexPy Notifiers :: Unable to retrieve notifier config: invalid notifier_id %s." % notifier_id)
return None
monitor_db = database.MonitorDatabase()
@@ -381,7 +381,6 @@ def get_notifier_config(notifier_id=None):
notifier_text[k] = {'subject': result.pop(k + '_subject'),
'body': result.pop(k + '_body')}
- result['agent'] = notifier_agent
result['config'] = notifier_config
result['actions'] = notifier_actions
result['notify_text'] = notifier_text
@@ -393,13 +392,13 @@ def add_notifier_config(agent_id=None, **kwargs):
if str(agent_id).isdigit():
agent_id = int(agent_id)
else:
- logger.error(u"PlexPy Notifiers :: Unable to add new notifier: invalid agent_id.")
+ logger.error(u"PlexPy Notifiers :: Unable to add new notifier: invalid agent_id %s." % agent_id)
return False
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
if not agent:
- logger.error(u"PlexPy Notifiers :: Unable to retrieve new notification agent: invalid agent_id.")
+ logger.error(u"PlexPy Notifiers :: Unable to retrieve new notification agent: invalid agent_id %s." % agent_id)
return False
keys = {'id': None}
@@ -433,13 +432,13 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
if str(agent_id).isdigit():
agent_id = int(agent_id)
else:
- logger.error(u"PlexPy Notifiers :: Unable to set exisiting notifier: invalid agent_id.")
+ logger.error(u"PlexPy Notifiers :: Unable to set exisiting notifier: invalid agent_id %s." % agent_id)
return False
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
if not agent:
- logger.error(u"PlexPy Notifiers :: Unable to retrieve existing notification agent: invalid agent_id.")
+ logger.error(u"PlexPy Notifiers :: Unable to retrieve existing notification agent: invalid agent_id %s." % agent_id)
return False
notify_actions = get_notify_actions()
@@ -479,7 +478,7 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
def send_notification(notifier_id=None, subject='', body='', notify_action='', **kwargs):
notifier_config = get_notifier_config(notifier_id=notifier_id)
if notifier_config:
- agent = notifier_config['agent']
+ agent = get_agent_class(notifier_config['agent_id'])
return agent.notify(subject=subject,
body=body,
action=notify_action,