diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py index 65411fae..6c6c1fc0 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -14,7 +14,7 @@ # along with Tautulli. If not, see . import datetime -import threading +import os import time from apscheduler.schedulers.background import BackgroundScheduler @@ -26,7 +26,6 @@ import datafactory import helpers import logger import notification_handler -import notifiers import pmsconnect @@ -75,9 +74,12 @@ class ActivityHandler(object): monitor_proc.write_session(session=session, notify=False) def on_start(self): - if self.is_valid_session() and self.get_live_session(): + if self.is_valid_session(): session = self.get_live_session() - + + if not session: + return + # Some DLNA clients create a new session temporarily when browsing the library # Wait and get session again to make sure it is an actual session if session['platform'] == 'DLNA': @@ -124,6 +126,7 @@ class ActivityHandler(object): logger.debug(u"Tautulli ActivityHandler :: Removing sessionKey %s ratingKey %s from session queue" % (str(self.get_session_key()), str(self.get_rating_key()))) ap.delete_session(session_key=self.get_session_key()) + delete_metadata_cache(self.get_session_key()) def on_pause(self, still_paused=False): if self.is_valid_session(): @@ -449,12 +452,13 @@ def force_stop_stream(session_key): args=[session_key], seconds=30) else: - logger.warn(u"Tautulli Monitor :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \ + logger.warn(u"Tautulli ActivityHandler :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \ "Removing session from the database. Write attempt %s." % (session['session_key'], session['rating_key'], str(session['write_attempts']))) - logger.info(u"Tautulli Monitor :: Removing stale stream with sessionKey %s ratingKey %s from session queue" + logger.info(u"Tautulli ActivityHandler :: Removing stale stream with sessionKey %s ratingKey %s from session queue" % (session['session_key'], session['rating_key'])) ap.delete_session(session_key=session_key) + delete_metadata_cache(session_key) def clear_recently_added_queue(rating_key): @@ -519,3 +523,11 @@ def on_created(rating_key, **kwargs): else: logger.error(u"Tautulli TimelineHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key)) + + +def delete_metadata_cache(session_key): + try: + os.remove(os.path.join(plexpy.CONFIG.CACHE_DIR, 'metadata-sessionKey-%s.json' % session_key)) + except IOError as e: + logger.error(u"Tautulli ActivityHandler :: Failed to remove metadata cache file (sessionKey %s): %s" + % (session_key, e)) diff --git a/plexpy/http_handler.py b/plexpy/http_handler.py index 965b262c..0f62d285 100644 --- a/plexpy/http_handler.py +++ b/plexpy/http_handler.py @@ -154,7 +154,7 @@ class HTTPHandler(object): try: if self.output_format == 'text': output = response_content.decode('utf-8', 'ignore') - if self.output_format == 'dict': + elif self.output_format == 'dict': output = helpers.convert_xml_to_dict(response_content) elif self.output_format == 'json': output = helpers.convert_xml_to_json(response_content) diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index 5a5591e0..853f216b 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -13,6 +13,9 @@ # You should have received a copy of the GNU General Public License # along with Tautulli. If not, see . +import json +import os +import time import urllib import plexpy @@ -519,7 +522,7 @@ class PmsConnect(object): return output - def get_metadata_details(self, rating_key='', sync_id=''): + def get_metadata_details(self, rating_key='', sync_id='', cache_key=None): """ Return processed and validated metadata list for requested item. @@ -527,19 +530,33 @@ class PmsConnect(object): Output: array """ + metadata = {} + + if cache_key: + in_file_path = os.path.join(plexpy.CONFIG.CACHE_DIR, 'metadata-sessionKey-%s.json' % cache_key) + try: + with open(in_file_path, 'r') as inFile: + metadata = json.load(inFile) + except IOError as e: + pass + + if metadata: + _cache_time = metadata.pop('_cache_time', 0) + # Return cached metadata if less than 30 minutes ago + if int(time.time()) - _cache_time <= 1800: + return metadata + if rating_key: - metadata = self.get_metadata(str(rating_key), output_format='xml') + metadata_xml = self.get_metadata(str(rating_key), output_format='xml') elif sync_id: - metadata = self.get_sync_item(str(sync_id), output_format='xml') + metadata_xml = self.get_sync_item(str(sync_id), output_format='xml') try: - xml_head = metadata.getElementsByTagName('MediaContainer') + xml_head = metadata_xml.getElementsByTagName('MediaContainer') except Exception as e: logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_metadata_details: %s." % e) return {} - metadata = {} - for a in xml_head: if a.getAttribute('size'): if a.getAttribute('size') != '1': @@ -1138,6 +1155,17 @@ class PmsConnect(object): metadata['media_info'] = medias if metadata: + metadata['_cache_time'] = int(time.time()) + + if cache_key: + out_file_path = os.path.join(plexpy.CONFIG.CACHE_DIR, 'metadata-sessionKey-%s.json' % cache_key) + try: + with open(out_file_path, 'w') as outFile: + json.dump(metadata, outFile) + except IOError as e: + logger.error(u"Tautulli Pmsconnect :: Unable to create cache file for metadata (sessionKey %s): %s" + % (cache_key, e)) + return metadata else: return {} @@ -1299,6 +1327,7 @@ class PmsConnect(object): # Get the source media type media_type = helpers.get_xml_attr(session, 'type') rating_key = helpers.get_xml_attr(session, 'ratingKey') + session_key = helpers.get_xml_attr(session, 'sessionKey') # Get the user details user_info = session.getElementsByTagName('User')[0] @@ -1613,9 +1642,9 @@ class PmsConnect(object): part_id = helpers.get_xml_attr(stream_media_parts_info, 'id') if sync_id: - metadata_details = self.get_metadata_details(sync_id=sync_id) + metadata_details = self.get_metadata_details(sync_id=sync_id, cache_key=session_key) else: - metadata_details = self.get_metadata_details(rating_key=rating_key) + metadata_details = self.get_metadata_details(rating_key=rating_key, cache_key=session_key) # Get the media info, fallback to first item if match id is not found source_medias = metadata_details.pop('media_info', []) @@ -1728,7 +1757,7 @@ class PmsConnect(object): optimized_version_profile = '' # Entire session output (single dict for backwards compatibility) - session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), + session_output = {'session_key': session_key, 'media_type': media_type, 'view_offset': view_offset, 'progress_percent': str(helpers.get_percent(view_offset, stream_details['stream_duration'])),