diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 2a464062..981818bb 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -687,20 +687,21 @@ def dbcheck(): 'CREATE TABLE IF NOT EXISTS notifiers (id INTEGER PRIMARY KEY AUTOINCREMENT, ' 'agent_id INTEGER, agent_name TEXT, agent_label TEXT, friendly_name TEXT, notifier_config TEXT, ' 'on_play INTEGER DEFAULT 0, on_stop INTEGER DEFAULT 0, on_pause INTEGER DEFAULT 0, ' - 'on_resume INTEGER DEFAULT 0, on_change INTEGER DEFAULT 0, on_buffer INTEGER DEFAULT 0, on_watched INTEGER DEFAULT 0, ' - 'on_created INTEGER DEFAULT 0, on_extdown INTEGER DEFAULT 0, on_intdown INTEGER DEFAULT 0, ' + 'on_resume INTEGER DEFAULT 0, on_change INTEGER DEFAULT 0, on_buffer INTEGER DEFAULT 0, ' + 'on_error INTEGER DEFAULT 0, on_watched INTEGER DEFAULT 0, on_created INTEGER DEFAULT 0, ' + 'on_extdown INTEGER DEFAULT 0, on_intdown INTEGER DEFAULT 0, ' 'on_extup INTEGER DEFAULT 0, on_intup INTEGER DEFAULT 0, on_pmsupdate INTEGER DEFAULT 0, ' 'on_concurrent INTEGER DEFAULT 0, on_newdevice INTEGER DEFAULT 0, on_plexpyupdate INTEGER DEFAULT 0, ' 'on_plexpydbcorrupt INTEGER DEFAULT 0, ' 'on_play_subject TEXT, on_stop_subject TEXT, on_pause_subject TEXT, ' - 'on_resume_subject TEXT, on_change_subject TEXT, on_buffer_subject TEXT, on_watched_subject TEXT, ' - 'on_created_subject TEXT, on_extdown_subject TEXT, on_intdown_subject TEXT, ' + 'on_resume_subject TEXT, on_change_subject TEXT, on_buffer_subject TEXT, on_error_subject TEXT, ' + 'on_watched_subject TEXT, on_created_subject TEXT, on_extdown_subject TEXT, on_intdown_subject TEXT, ' 'on_extup_subject TEXT, on_intup_subject TEXT, on_pmsupdate_subject TEXT, ' 'on_concurrent_subject TEXT, on_newdevice_subject TEXT, on_plexpyupdate_subject TEXT, ' 'on_plexpydbcorrupt_subject TEXT, ' 'on_play_body TEXT, on_stop_body TEXT, on_pause_body TEXT, ' - 'on_resume_body TEXT, on_change_body TEXT, on_buffer_body TEXT, on_watched_body TEXT, ' - 'on_created_body TEXT, on_extdown_body TEXT, on_intdown_body TEXT, ' + 'on_resume_body TEXT, on_change_body TEXT, on_buffer_body TEXT, on_error_body TEXT, ' + 'on_watched_body TEXT, on_created_body TEXT, on_extdown_body TEXT, on_intdown_body TEXT, ' 'on_extup_body TEXT, on_intup_body TEXT, on_pmsupdate_body TEXT, ' 'on_concurrent_body TEXT, on_newdevice_body TEXT, on_plexpyupdate_body TEXT, ' 'on_plexpydbcorrupt_body TEXT, ' @@ -2065,6 +2066,21 @@ def dbcheck(): 'ALTER TABLE notifiers ADD COLUMN on_plexpydbcorrupt_body TEXT' ) + # Upgrade notifiers table from earlier versions + try: + c_db.execute('SELECT on_error FROM notifiers') + except sqlite3.OperationalError: + logger.debug("Altering database. Updating database table notifiers.") + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_error INTEGER DEFAULT 0' + ) + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_error_subject TEXT' + ) + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_error_body TEXT' + ) + # Upgrade tvmaze_lookup table from earlier versions try: c_db.execute('SELECT rating_key FROM tvmaze_lookup') diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py index 1763313b..b51724dc 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -264,6 +264,19 @@ class ActivityHandler(object): plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_buffer'}) + def on_error(self): + if self.is_valid_session(): + logger.debug("Tautulli ActivityHandler :: Session %s encountered an error." % str(self.get_session_key())) + + # Update the session state and viewOffset + self.update_db_session() + + # Retrieve the session data from our temp table + ap = activity_processor.ActivityProcessor() + db_session = ap.get_session_by_key(session_key=self.get_session_key()) + + plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_error'}) + # This function receives events from our websocket connection def process(self): if self.is_valid_session(): @@ -321,6 +334,8 @@ class ActivityHandler(object): self.on_resume() elif this_state == 'stopped': self.on_stop() + elif this_state == 'error': + self.on_error() elif this_state == 'paused': # Update the session last_paused timestamp diff --git a/plexpy/activity_pinger.py b/plexpy/activity_pinger.py index 38960d7c..e667e943 100644 --- a/plexpy/activity_pinger.py +++ b/plexpy/activity_pinger.py @@ -89,6 +89,11 @@ def check_active_sessions(ws_request=False): plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_resume'}) + if session['state'] == 'error': + logger.debug("Tautulli Monitor :: Session %s encountered an error." % stream['session_key']) + + plexpy.NOTIFY_QUEUE.put({'stream_data': stream.copy(), 'notify_action': 'on_error'}) + if stream['state'] == 'paused' and not ws_request: # The stream is still paused so we need to increment the paused_counter # Using the set config parameter as the interval, probably not the most accurate but diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 0cb42e94..5c2c2e1c 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -295,6 +295,14 @@ def available_notification_actions(agent_id=None): 'icon': 'fa-play', 'media_types': ('movie', 'episode', 'track') }, + {'label': 'Playback Error', + 'name': 'on_error', + 'description': 'Trigger a notification when a stream encounters an error.', + 'subject': 'Tautulli ({server_name})', + 'body': '{user} ({player}) encountered an error trying to play {title}.', + 'icon': 'fa-exclamation-triangle', + 'media_types': ('movie', 'episode', 'track') + }, {'label': 'Transcode Decision Change', 'name': 'on_change', 'description': 'Trigger a notification when a stream changes transcode decision.',