From 599c54c9e10ce7293319f172fab4def78702a86b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Thu, 16 Feb 2023 17:02:30 -0800 Subject: [PATCH] Refactor activity handler --- plexpy/activity_handler.py | 482 ++++++++++++++++++------------------- 1 file changed, 229 insertions(+), 253 deletions(-) diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py index 3b5a283f..5ed69e10 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -53,38 +53,33 @@ class ActivityHandler(object): def __init__(self, timeline): self.ap = activity_processor.ActivityProcessor() self.timeline = timeline + + self.session_key = None + self.rating_key = None + + self.is_valid_session = ('sessionKey' in self.timeline and str(self.timeline['sessionKey']).isdigit()) + if self.is_valid_session: + self.session_key = int(self.timeline['sessionKey']) + self.rating_key = str(self.timeline['ratingKey']) + + self.key = self.timeline.get('key') + self.state = self.timeline.get('state') + self.view_offset = self.timeline.get('viewOffset') + self.transcode_key = self.timeline.get('transcodeSession', '') + self.db_session = None self.session = None self.metadata = None - def is_valid_session(self): - if 'sessionKey' in self.timeline: - if str(self.timeline['sessionKey']).isdigit(): - return True - - return False - - def get_session_key(self): - if self.is_valid_session(): - return int(self.timeline['sessionKey']) - - return None - - def get_rating_key(self): - if self.is_valid_session(): - return self.timeline['ratingKey'] - - return None - def get_db_session(self): # Retrieve the session data from our temp table - self.db_session = self.ap.get_session_by_key(session_key=self.get_session_key()) + self.db_session = self.ap.get_session_by_key(session_key=self.session_key) def get_metadata(self, skip_cache=False): if self.metadata is None: - cache_key = None if skip_cache else self.get_session_key() + cache_key = None if skip_cache else self.session_key pms_connect = pmsconnect.PmsConnect() - metadata = pms_connect.get_metadata_details(rating_key=self.get_rating_key(), cache_key=cache_key) + metadata = pms_connect.get_metadata_details(rating_key=self.rating_key, cache_key=cache_key) if metadata: self.metadata = metadata @@ -95,12 +90,12 @@ class ActivityHandler(object): if session_list: for session in session_list['sessions']: - if int(session['session_key']) == self.get_session_key(): + if int(session['session_key']) == self.session_key: # Live sessions don't have rating keys in sessions # Get it from the websocket data if not session['rating_key']: - session['rating_key'] = self.get_rating_key() - session['rating_key_websocket'] = self.get_rating_key() + session['rating_key'] = self.rating_key + session['rating_key_websocket'] = self.rating_key self.session = session return session @@ -116,9 +111,9 @@ class ActivityHandler(object): self.get_db_session() def set_session_state(self): - self.ap.set_session_state(session_key=self.get_session_key(), - state=self.timeline['state'], - view_offset=self.timeline['viewOffset'], + self.ap.set_session_state(session_key=self.session_key, + state=self.state, + view_offset=self.view_offset, stopped=helpers.timestamp()) def put_notification(self, notify_action, **kwargs): @@ -148,19 +143,19 @@ class ActivityHandler(object): self.update_db_session(notify=True) # Schedule a callback to force stop a stale stream 5 minutes later - schedule_callback('session_key-{}'.format(self.get_session_key()), + schedule_callback('session_key-{}'.format(self.session_key), func=force_stop_stream, - args=[self.get_session_key(), self.session['full_title'], self.session['username']], + args=[self.session_key, self.session['full_title'], self.session['username']], minutes=5) self.check_markers() def on_stop(self, force_stop=False): logger.debug("Tautulli ActivityHandler :: Session %s %sstopped." - % (str(self.get_session_key()), 'force ' if force_stop else '')) + % (str(self.session_key), 'force ' if force_stop else '')) # Set the session last_paused timestamp - self.ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=None) + self.ap.set_session_last_paused(session_key=self.session_key, timestamp=None) # Update the session state and viewOffset # Set force_stop to true to disable the state set @@ -173,25 +168,25 @@ class ActivityHandler(object): if row_id: self.put_notification('on_stop') - schedule_callback('session_key-{}'.format(self.get_session_key()), remove_job=True) + schedule_callback('session_key-{}'.format(self.session_key), remove_job=True) # Remove the session from our temp session table logger.debug("Tautulli ActivityHandler :: Removing sessionKey %s ratingKey %s from session queue" - % (str(self.get_session_key()), str(self.get_rating_key()))) + % (str(self.session_key), str(self.rating_key))) self.ap.delete_session(row_id=row_id) - delete_metadata_cache(self.get_session_key()) + delete_metadata_cache(self.session_key) else: - schedule_callback('session_key-{}'.format(self.get_session_key()), + schedule_callback('session_key-{}'.format(self.session_key), func=force_stop_stream, - args=[self.get_session_key(), self.db_session['full_title'], self.db_session['user']], + args=[self.session_key, self.db_session['full_title'], self.db_session['user']], seconds=30) def on_pause(self, still_paused=False): if not still_paused: - logger.debug("Tautulli ActivityHandler :: Session %s paused." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s paused." % str(self.session_key)) # Set the session last_paused timestamp - self.ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=helpers.timestamp()) + self.ap.set_session_last_paused(session_key=self.session_key, timestamp=helpers.timestamp()) self.update_db_session() @@ -199,52 +194,52 @@ class ActivityHandler(object): self.put_notification('on_pause') def on_resume(self): - logger.debug("Tautulli ActivityHandler :: Session %s resumed." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s resumed." % str(self.session_key)) # Set the session last_paused timestamp - self.ap.set_session_last_paused(session_key=self.get_session_key(), timestamp=None) + self.ap.set_session_last_paused(session_key=self.session_key, timestamp=None) self.update_db_session() self.put_notification('on_resume') def on_buffer(self): - logger.debug("Tautulli ActivityHandler :: Session %s is buffering." % self.get_session_key()) + logger.debug("Tautulli ActivityHandler :: Session %s is buffering." % self.session_key) # Increment our buffer count - self.ap.increment_session_buffer_count(session_key=self.get_session_key()) + self.ap.increment_session_buffer_count(session_key=self.session_key) # Get our current buffer count - current_buffer_count = self.ap.get_session_buffer_count(self.get_session_key()) + current_buffer_count = self.ap.get_session_buffer_count(self.session_key) logger.debug("Tautulli ActivityHandler :: Session %s buffer count is %s." % - (self.get_session_key(), current_buffer_count)) + (self.session_key, current_buffer_count)) # Get our last triggered time - buffer_last_triggered = self.ap.get_session_buffer_trigger_time(self.get_session_key()) + buffer_last_triggered = self.ap.get_session_buffer_trigger_time(self.session_key) self.update_db_session() time_since_last_trigger = 0 if buffer_last_triggered: logger.debug("Tautulli ActivityHandler :: Session %s buffer last triggered at %s." % - (self.get_session_key(), buffer_last_triggered)) + (self.session_key, buffer_last_triggered)) time_since_last_trigger = helpers.timestamp() - int(buffer_last_triggered) if current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and time_since_last_trigger == 0 or \ time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT: - self.ap.set_session_buffer_trigger_time(session_key=self.get_session_key()) + self.ap.set_session_buffer_trigger_time(session_key=self.session_key) self.put_notification('on_buffer') def on_error(self): - logger.debug("Tautulli ActivityHandler :: Session %s encountered an error." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s encountered an error." % str(self.session_key)) self.update_db_session() self.put_notification('on_error') def on_change(self): - logger.debug("Tautulli ActivityHandler :: Session %s has changed transcode decision." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s has changed transcode decision." % str(self.session_key)) self.update_db_session() @@ -252,17 +247,17 @@ class ActivityHandler(object): def on_intro(self, marker): if self.get_live_session(): - logger.debug("Tautulli ActivityHandler :: Session %s intro marker reached." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s intro marker reached." % str(self.session_key)) self.put_notification('on_intro', marker=marker) def on_credits(self, marker): if self.get_live_session(): - logger.debug("Tautulli ActivityHandler :: Session %s credits marker reached." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s credits marker reached." % str(self.session_key)) self.put_notification('on_credits', marker=marker) def on_watched(self): - logger.debug("Tautulli ActivityHandler :: Session %s watched." % str(self.get_session_key())) + logger.debug("Tautulli ActivityHandler :: Session %s watched." % str(self.session_key)) watched_notifiers = notification_handler.get_notify_state_enabled( session=self.db_session, notify_action='on_watched', notified=False) @@ -272,88 +267,85 @@ class ActivityHandler(object): # This function receives events from our websocket connection def process(self): - if self.is_valid_session(): - self.get_db_session() + if not self.is_valid_session: + return + + self.get_db_session() - this_state = self.timeline['state'] - this_rating_key = str(self.timeline['ratingKey']) - this_key = self.timeline['key'] - this_transcode_key = self.timeline.get('transcodeSession', '') + if not self.db_session: + # We don't have this session in our table yet, start a new one. + if self.state != 'buffering': + self.on_start() + return - # Get the live tv session uuid - this_live_uuid = this_key.split('/')[-1] if this_key.startswith('/livetv/sessions') else None + # If we already have this session in the temp table, check for state changes + # Re-schedule the callback to reset the 5 minutes timer + schedule_callback('session_key-{}'.format(self.session_key), + func=force_stop_stream, + args=[self.session_key, self.db_session['full_title'], self.db_session['user']], + minutes=5) - # If we already have this session in the temp table, check for state changes - if self.db_session: - # Re-schedule the callback to reset the 5 minutes timer - schedule_callback('session_key-{}'.format(self.get_session_key()), - func=force_stop_stream, - args=[self.get_session_key(), self.db_session['full_title'], self.db_session['user']], - minutes=5) + last_state = self.db_session['state'] + last_rating_key = str(self.db_session['rating_key']) + last_live_uuid = self.db_session['live_uuid'] + last_transcode_key = self.db_session['transcode_key'].split('/')[-1] + last_paused = self.db_session['last_paused'] + last_rating_key_websocket = self.db_session['rating_key_websocket'] + last_guid = self.db_session['guid'] - last_state = self.db_session['state'] - last_rating_key = str(self.db_session['rating_key']) - last_live_uuid = self.db_session['live_uuid'] - last_transcode_key = self.db_session['transcode_key'].split('/')[-1] - last_paused = self.db_session['last_paused'] - last_rating_key_websocket = self.db_session['rating_key_websocket'] - last_guid = self.db_session['guid'] + # Get the live tv session uuid + this_live_uuid = self.key.split('/')[-1] if self.key.startswith('/livetv/sessions') else None - this_guid = last_guid - # Check guid for live TV metadata every 60 seconds - if self.db_session['live'] and helpers.timestamp() - self.db_session['stopped'] > 60: - self.get_metadata(skip_cache=True) - if self.metadata: - this_guid = self.metadata['guid'] + this_guid = last_guid + # Check guid for live TV metadata every 60 seconds + if self.db_session['live'] and helpers.timestamp() - self.db_session['stopped'] > 60: + self.get_metadata(skip_cache=True) + if self.metadata: + this_guid = self.metadata['guid'] - # Make sure the same item is being played - if (this_rating_key == last_rating_key - or this_rating_key == last_rating_key_websocket - or this_live_uuid == last_live_uuid) \ - and this_guid == last_guid: - # 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 60 seconds - if helpers.timestamp() - self.db_session['stopped'] > 60: - self.update_db_session() + # Make sure the same item is being played + if (self.rating_key == last_rating_key + or self.rating_key == last_rating_key_websocket + or this_live_uuid == last_live_uuid) \ + and this_guid == last_guid: + # Update the session state and viewOffset + if self.state == 'playing': + # Update the session in our temp session table + # if the last set temporary stopped time exceeds 60 seconds + if helpers.timestamp() - self.db_session['stopped'] > 60: + self.update_db_session() - # Start our state checks - if this_state != last_state: - if this_state == 'paused': - self.on_pause() - elif last_paused and this_state == 'playing': - self.on_resume() - elif this_state == 'stopped': - self.on_stop() - elif this_state == 'error': - self.on_error() + # Start our state checks + if self.state != last_state: + if self.state == 'paused': + self.on_pause() + elif last_paused and self.state == 'playing': + self.on_resume() + elif self.state == 'stopped': + self.on_stop() + elif self.state == 'error': + self.on_error() - elif this_state == 'paused': - # Update the session last_paused timestamp - self.on_pause(still_paused=True) + elif self.state == 'paused': + # Update the session last_paused timestamp + self.on_pause(still_paused=True) - if this_state == 'buffering': - self.on_buffer() + if self.state == 'buffering': + self.on_buffer() - if this_transcode_key != last_transcode_key and this_state != 'stopped': - self.on_change() + if self.transcode_key != last_transcode_key and self.state != 'stopped': + 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 - # Set force_stop so that we don't overwrite our last viewOffset - self.on_stop(force_stop=True) - self.on_start() + # 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 + # Set force_stop so that we don't overwrite our last viewOffset + self.on_stop(force_stop=True) + self.on_start() - # Check for stream offset notifications - self.check_markers() - self.check_watched() - - else: - # We don't have this session in our table yet, start a new one. - if this_state != 'buffering': - self.on_start() + # Check for stream offset notifications + self.check_markers() + self.check_watched() def check_markers(self): # Monitor if the stream has reached the intro or credit marker offsets @@ -364,20 +356,20 @@ class ActivityHandler(object): for marker_idx, marker in enumerate(self.metadata['markers'], start=1): # Websocket events only fire every 10 seconds # Check if the marker is within 10 seconds of the current viewOffset - if marker['start_time_offset'] - 10000 <= self.timeline['viewOffset'] <= marker['end_time_offset']: + if marker['start_time_offset'] - 10000 <= self.view_offset <= marker['end_time_offset']: marker_flag = True if self.db_session['marker'] != marker_idx: - self.ap.set_marker(session_key=self.get_session_key(), marker_idx=marker_idx, marker_type=marker['type']) + self.ap.set_marker(session_key=self.session_key, marker_idx=marker_idx, marker_type=marker['type']) callback_func = getattr(self, 'on_{}'.format(marker['type'])) - if self.timeline['viewOffset'] < marker['start_time_offset']: + if self.view_offset < marker['start_time_offset']: # Schedule a callback for the exact offset of the marker schedule_callback( - 'session_key-{}-marker-{}'.format(self.get_session_key(), marker_idx), + 'session_key-{}-marker-{}'.format(self.session_key, marker_idx), func=callback_func, args=[marker], - milliseconds=marker['start_time_offset'] - self.timeline['viewOffset'] + milliseconds=marker['start_time_offset'] - self.view_offset ) else: callback_func(marker) @@ -385,7 +377,7 @@ class ActivityHandler(object): break if not marker_flag: - self.ap.set_marker(session_key=self.get_session_key(), marker_idx=0) + self.ap.set_marker(session_key=self.session_key, marker_idx=0) def check_watched(self): # Monitor if the stream has reached the watch percentage for notifications @@ -399,7 +391,7 @@ class ActivityHandler(object): } if progress_percent >= watched_percent.get(self.db_session['media_type'], 101): - self.ap.set_watched(session_key=self.get_session_key()) + self.ap.set_watched(session_key=self.session_key) self.on_watched() @@ -408,121 +400,106 @@ class TimelineHandler(object): def __init__(self, timeline): self.timeline = timeline - def is_item(self): - if 'itemID' in self.timeline: - return True + self.rating_key = None - return False + self.is_item = ('itemID' in self.timeline) + if self.is_item: + self.rating_key = int(self.timeline['itemID']) - def get_rating_key(self): - if self.is_item(): - return int(self.timeline['itemID']) - - return None - - def get_metadata(self): - pms_connect = pmsconnect.PmsConnect() - metadata = pms_connect.get_metadata_details(self.get_rating_key()) - - if metadata: - return metadata - - return None + self.parent_rating_key = helpers.cast_to_int(self.timeline.get('parentItemID')) or None + self.grandparent_rating_key = helpers.cast_to_int(self.timeline.get('rootItemID')) or None + self.identifier = self.timeline.get('identifier') + self.state_type = self.timeline.get('state') + self.media_type = common.MEDIA_TYPE_VALUES.get(self.timeline.get('type')) + self.section_id = helpers.cast_to_int(self.timeline.get('sectionID', 0)) + self.title = self.timeline.get('title', 'Unknown') + self.metadata_state = self.timeline.get('metadataState') + self.media_state = self.timeline.get('mediaState') + self.queue_size = self.timeline.get('queueSize') # This function receives events from our websocket connection def process(self): - if self.is_item(): - global RECENTLY_ADDED_QUEUE + if not self.is_item: + return + + # Return if it is not a library event (i.e. DVR EPG event) + if self.identifier != 'com.plexapp.plugins.library': + return - rating_key = self.get_rating_key() - parent_rating_key = helpers.cast_to_int(self.timeline.get('parentItemID')) or None - grandparent_rating_key = helpers.cast_to_int(self.timeline.get('rootItemID')) or None + global RECENTLY_ADDED_QUEUE - identifier = self.timeline.get('identifier') - state_type = self.timeline.get('state') - media_type = common.MEDIA_TYPE_VALUES.get(self.timeline.get('type')) - section_id = helpers.cast_to_int(self.timeline.get('sectionID', 0)) - title = self.timeline.get('title', 'Unknown') - metadata_state = self.timeline.get('metadataState') - media_state = self.timeline.get('mediaState') - queue_size = self.timeline.get('queueSize') + # Add a new media item to the recently added queue + if self.media_type and self.section_id > 0 and self.state_type == 0 and self.metadata_state == 'created': - # Return if it is not a library event (i.e. DVR EPG event) - if identifier != 'com.plexapp.plugins.library': - return + if self.media_type in ('episode', 'track'): + grandparent_set = RECENTLY_ADDED_QUEUE.get(self.grandparent_rating_key, set()) + grandparent_set.add(self.parent_rating_key) + RECENTLY_ADDED_QUEUE[self.grandparent_rating_key] = grandparent_set - # Add a new media item to the recently added queue - if media_type and section_id > 0 and state_type == 0 and metadata_state == 'created': + parent_set = RECENTLY_ADDED_QUEUE.get(self.parent_rating_key, set()) + parent_set.add(self.rating_key) + RECENTLY_ADDED_QUEUE[self.parent_rating_key] = parent_set - if media_type in ('episode', 'track'): - grandparent_set = RECENTLY_ADDED_QUEUE.get(grandparent_rating_key, set()) - grandparent_set.add(parent_rating_key) - RECENTLY_ADDED_QUEUE[grandparent_rating_key] = grandparent_set + RECENTLY_ADDED_QUEUE[self.rating_key] = {self.grandparent_rating_key} - parent_set = RECENTLY_ADDED_QUEUE.get(parent_rating_key, set()) - parent_set.add(rating_key) - RECENTLY_ADDED_QUEUE[parent_rating_key] = parent_set + logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s, grandparent %s) " + "added to recently added queue." + % (self.title, str(self.rating_key), str(self.grandparent_rating_key))) - RECENTLY_ADDED_QUEUE[rating_key] = {grandparent_rating_key} + # Schedule a callback to clear the recently added queue + schedule_callback('rating_key-{}'.format(self.grandparent_rating_key), + func=clear_recently_added_queue, + args=[self.grandparent_rating_key, self.title], + seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) - logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s, grandparent %s) " - "added to recently added queue." - % (title, str(rating_key), str(grandparent_rating_key))) + elif self.media_type in ('season', 'album'): + parent_set = RECENTLY_ADDED_QUEUE.get(self.parent_rating_key, set()) + parent_set.add(self.rating_key) + RECENTLY_ADDED_QUEUE[self.parent_rating_key] = parent_set - # Schedule a callback to clear the recently added queue - schedule_callback('rating_key-{}'.format(grandparent_rating_key), - func=clear_recently_added_queue, - args=[grandparent_rating_key, title], - seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) + logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s , parent %s) " + "added to recently added queue." + % (self.title, str(self.rating_key), str(self.parent_rating_key))) - elif media_type in ('season', 'album'): - parent_set = RECENTLY_ADDED_QUEUE.get(parent_rating_key, set()) - parent_set.add(rating_key) - RECENTLY_ADDED_QUEUE[parent_rating_key] = parent_set + # Schedule a callback to clear the recently added queue + schedule_callback('rating_key-{}'.format(self.parent_rating_key), + func=clear_recently_added_queue, + args=[self.parent_rating_key, self.title], + seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) - logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s , parent %s) " - "added to recently added queue." - % (title, str(rating_key), str(parent_rating_key))) - - # Schedule a callback to clear the recently added queue - schedule_callback('rating_key-{}'.format(parent_rating_key), - func=clear_recently_added_queue, - args=[parent_rating_key, title], - seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) - - elif media_type in ('movie', 'show', 'artist'): - queue_set = RECENTLY_ADDED_QUEUE.get(rating_key, set()) - RECENTLY_ADDED_QUEUE[rating_key] = queue_set - - logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s) " - "added to recently added queue." - % (title, str(rating_key))) - - # Schedule a callback to clear the recently added queue - schedule_callback('rating_key-{}'.format(rating_key), - func=clear_recently_added_queue, - args=[rating_key, title], - seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) - - # A movie, show, or artist is done processing - elif media_type in ('movie', 'show', 'artist') and section_id > 0 and \ - state_type == 5 and metadata_state is None and queue_size is None and \ - rating_key in RECENTLY_ADDED_QUEUE: + elif self.media_type in ('movie', 'show', 'artist'): + queue_set = RECENTLY_ADDED_QUEUE.get(self.rating_key, set()) + RECENTLY_ADDED_QUEUE[self.rating_key] = queue_set logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s) " - "done processing metadata." - % (title, str(rating_key))) + "added to recently added queue." + % (self.title, str(self.rating_key))) - # An item was deleted, make sure it is removed from the queue - elif state_type == 9 and metadata_state == 'deleted': - if rating_key in RECENTLY_ADDED_QUEUE and not RECENTLY_ADDED_QUEUE[rating_key]: - logger.debug("Tautulli TimelineHandler :: Library item %s " - "removed from recently added queue." - % str(rating_key)) - del_keys(rating_key) + # Schedule a callback to clear the recently added queue + schedule_callback('rating_key-{}'.format(self.rating_key), + func=clear_recently_added_queue, + args=[self.rating_key, self.title], + seconds=plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_DELAY) - # Remove the callback if the item is removed - schedule_callback('rating_key-{}'.format(rating_key), remove_job=True) + # A movie, show, or artist is done processing + elif self.media_type in ('movie', 'show', 'artist') and self.section_id > 0 and \ + self.state_type == 5 and self.metadata_state is None and self.queue_size is None and \ + self.rating_key in RECENTLY_ADDED_QUEUE: + + logger.debug("Tautulli TimelineHandler :: Library item '%s' (%s) " + "done processing metadata." + % (self.title, str(self.rating_key))) + + # An item was deleted, make sure it is removed from the queue + elif self.state_type == 9 and self.metadata_state == 'deleted': + if self.rating_key in RECENTLY_ADDED_QUEUE and not RECENTLY_ADDED_QUEUE[self.rating_key]: + logger.debug("Tautulli TimelineHandler :: Library item %s " + "removed from recently added queue." + % str(self.rating_key)) + del_keys(self.rating_key) + + # Remove the callback if the item is removed + schedule_callback('rating_key-{}'.format(self.rating_key), remove_job=True) class ReachabilityHandler(object): @@ -530,10 +507,7 @@ class ReachabilityHandler(object): def __init__(self, data): self.data = data - def is_reachable(self): - if 'reachability' in self.data: - return self.data['reachability'] - return False + self.is_reachable = self.data.get('reachable', False) def remote_access_enabled(self): pms_connect = pmsconnect.PmsConnect() @@ -552,42 +526,44 @@ class ReachabilityHandler(object): return # Do nothing if remote access is still up and hasn't changed - if self.is_reachable() and plexpy.PLEX_REMOTE_ACCESS_UP: + if self.is_reachable and plexpy.PLEX_REMOTE_ACCESS_UP: return pms_connect = pmsconnect.PmsConnect() server_response = pms_connect.get_server_response() - if server_response: - # Waiting for port mapping - if server_response['mapping_state'] == 'waiting': - logger.warn("Tautulli ReachabilityHandler :: Remote access waiting for port mapping.") + if not server_response: + return - elif plexpy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']: - logger.warn("Tautulli ReachabilityHandler :: Remote access failed: %s" % server_response['reason']) - logger.info("Tautulli ReachabilityHandler :: Plex remote access is down.") + # Waiting for port mapping + if server_response['mapping_state'] == 'waiting': + logger.warn("Tautulli ReachabilityHandler :: Remote access waiting for port mapping.") - plexpy.PLEX_REMOTE_ACCESS_UP = False + elif plexpy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']: + logger.warn("Tautulli ReachabilityHandler :: Remote access failed: %s" % server_response['reason']) + logger.info("Tautulli ReachabilityHandler :: Plex remote access is down.") - if not ACTIVITY_SCHED.get_job('on_extdown'): - logger.debug("Tautulli ReachabilityHandler :: Scheduling remote access down callback in %d seconds.", - plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD) - schedule_callback('on_extdown', func=self.on_extdown, args=[server_response], - seconds=plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD) + plexpy.PLEX_REMOTE_ACCESS_UP = False - elif plexpy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']: - logger.info("Tautulli ReachabilityHandler :: Plex remote access is back up.") + if not ACTIVITY_SCHED.get_job('on_extdown'): + logger.debug("Tautulli ReachabilityHandler :: Scheduling remote access down callback in %d seconds.", + plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD) + schedule_callback('on_extdown', func=self.on_extdown, args=[server_response], + seconds=plexpy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD) - plexpy.PLEX_REMOTE_ACCESS_UP = True + elif plexpy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']: + logger.info("Tautulli ReachabilityHandler :: Plex remote access is back up.") - if ACTIVITY_SCHED.get_job('on_extdown'): - logger.debug("Tautulli ReachabilityHandler :: Cancelling scheduled remote access down callback.") - schedule_callback('on_extdown', remove_job=True) - else: - self.on_extup(server_response) + plexpy.PLEX_REMOTE_ACCESS_UP = True - elif plexpy.PLEX_REMOTE_ACCESS_UP is None: - plexpy.PLEX_REMOTE_ACCESS_UP = self.is_reachable() + if ACTIVITY_SCHED.get_job('on_extdown'): + logger.debug("Tautulli ReachabilityHandler :: Cancelling scheduled remote access down callback.") + schedule_callback('on_extdown', remove_job=True) + else: + self.on_extup(server_response) + + elif plexpy.PLEX_REMOTE_ACCESS_UP is None: + plexpy.PLEX_REMOTE_ACCESS_UP = self.is_reachable def del_keys(key):