diff --git a/plexpy/__init__.py b/plexpy/__init__.py index b809c95d..af22e42a 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -662,17 +662,17 @@ 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_buffer INTEGER DEFAULT 0, on_watched 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_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_play_subject TEXT, on_stop_subject TEXT, on_pause_subject TEXT, ' - 'on_resume_subject TEXT, on_buffer_subject TEXT, on_watched_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_extup_subject TEXT, on_intup_subject TEXT, on_pmsupdate_subject TEXT, ' 'on_concurrent_subject TEXT, on_newdevice_subject TEXT, on_plexpyupdate_subject TEXT, ' 'on_play_body TEXT, on_stop_body TEXT, on_pause_body TEXT, ' - 'on_resume_body TEXT, on_buffer_body TEXT, on_watched_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_extup_body TEXT, on_intup_body TEXT, on_pmsupdate_body TEXT, ' 'on_concurrent_body TEXT, on_newdevice_body TEXT, on_plexpyupdate_body TEXT, ' @@ -1733,6 +1733,21 @@ def dbcheck(): 'ALTER TABLE notifiers ADD COLUMN custom_conditions_logic TEXT' ) + # Upgrade notifiers table from earlier versions + try: + c_db.execute('SELECT on_change FROM notifiers') + except sqlite3.OperationalError: + logger.debug(u"Altering database. Updating database table notifiers.") + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_change INTEGER DEFAULT 0' + ) + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_change_subject TEXT' + ) + c_db.execute( + 'ALTER TABLE notifiers ADD COLUMN on_change_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 735d47f7..2c766c55 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -184,6 +184,19 @@ class ActivityHandler(object): plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(), 'notify_action': 'on_resume'}) + def on_change(self): + if self.is_valid_session(): + logger.debug(u"Tautulli ActivityHandler :: Session %s has changed transcode decision." % 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_change'}) + def on_buffer(self): if self.is_valid_session(): logger.debug(u"Tautulli ActivityHandler :: Session %s is buffering." % self.get_session_key()) @@ -228,6 +241,7 @@ class ActivityHandler(object): this_state = self.timeline['state'] this_rating_key = str(self.timeline['ratingKey']) this_key = self.timeline['key'] + this_transcode_key = self.timeline.get('transcodeSession', '') # Get the live tv session uuid this_live_uuid = this_key.split('/')[-1] if this_key.startswith('/livetv/sessions') else None @@ -241,13 +255,14 @@ class ActivityHandler(object): last_state = db_session['state'] last_rating_key = str(db_session['rating_key']) last_live_uuid = db_session['live_uuid'] + last_transcode_key = db_session['transcode_key'].split('/')[-1] # Make sure the same item is being played if this_rating_key == last_rating_key or this_live_uuid == last_live_uuid: # Update the session state and viewOffset if this_state == 'playing': # Update the session in our temp session table - # if the last set temporary stopped time exceeds 15 seconds + # if the last set temporary stopped time exceeds 60 seconds if int(time.time()) - db_session['stopped'] > 60: self.update_db_session() @@ -267,6 +282,9 @@ class ActivityHandler(object): # Update the session last_paused timestamp self.on_pause(still_paused=True) + if this_transcode_key != last_transcode_key and this_state != 'buffering': + self.on_change() + # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed else: # Manually stop and start diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 4ec71672..9c484033 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -244,6 +244,14 @@ def available_notification_actions(): 'icon': 'fa-play', 'media_types': ('movie', 'episode', 'track') }, + {'label': 'Transcode Decision Change', + 'name': 'on_change', + 'description': 'Trigger a notification when a stream changes transcode decision.', + 'subject': 'Tautulli ({server_name})', + 'body': '{user} ({player}) has changed transcode decision for {title}.', + 'icon': 'fa-exchange-alt', + 'media_types': ('movie', 'episode', 'track') + }, {'label': 'Watched', 'name': 'on_watched', 'description': 'Trigger a notification when a video stream reaches the specified watch percentage.', @@ -403,7 +411,9 @@ def get_notify_agents(): return tuple(a['name'] for a in sorted(available_notification_agents(), key=lambda k: k['label'])) -def get_notify_actions(): +def get_notify_actions(return_dict=False): + if return_dict: + return {a.pop('name'): a for a in available_notification_actions()} return tuple(a['name'] for a in available_notification_actions()) @@ -467,15 +477,23 @@ def get_notifier_config(notifier_id=None): logger.error(u"Tautulli Notifiers :: Failed to get notifier config options: %s." % e) return - notify_actions = get_notify_actions() + notify_actions = get_notify_actions(return_dict=True) notifier_actions = {} notifier_text = {} for k in result.keys(): if k in notify_actions: + subject = result.pop(k + '_subject') + body = result.pop(k + '_body') + + if subject is None: + subject = "" if result['agent_name'] in ('scripts', 'webhook') else notify_actions[k]['subject'] + if body is None: + body = "" if result['agent_name'] in ('scripts', 'webhook') else notify_actions[k]['body'] + notifier_actions[k] = helpers.cast_to_int(result.pop(k)) - notifier_text[k] = {'subject': result.pop(k + '_subject'), - 'body': result.pop(k + '_body')} + notifier_text[k] = {'subject': subject, + 'body': body} try: result['custom_conditions'] = json.loads(result['custom_conditions'])