# -*- coding: utf-8 -*- from __future__ import absolute_import, division, unicode_literals from logging import getLogger from . import common from ..plex_api import API from .. import plex_functions as PF, backgroundthread, utils, variables as v LOG = getLogger("PLEX." + __name__) LOCK = backgroundthread.threading.Lock() # List of tuples: (collection index [as in an item's metadata with "Collection # id"], collection plex id) COLLECTION_MATCH = None # Dict with entries of the form : COLLECTION_XMLS = {} def reset_collections(): """ Collections seem unique to Plex sections """ global LOCK, COLLECTION_MATCH, COLLECTION_XMLS with LOCK: COLLECTION_MATCH = None COLLECTION_XMLS = {} class GetMetadataTask(common.libsync_mixin, backgroundthread.Task): """ Threaded download of Plex XML metadata for a certain library item. Fills the queue with the downloaded etree XML objects Input: queue Queue.Queue() object where this thread will store the downloaded metadata XMLs as etree objects """ def __init__(self, queue, plex_id, plex_type, get_children=False): self.queue = queue self.plex_id = plex_id self.plex_type = plex_type self.get_children = get_children super(GetMetadataTask, self).__init__() def _collections(self, item): global COLLECTION_MATCH, COLLECTION_XMLS api = API(item['xml'][0]) if COLLECTION_MATCH is None: COLLECTION_MATCH = PF.collections(api.library_section_id()) if COLLECTION_MATCH is None: LOG.error('Could not download collections') return # Extract what we need to know COLLECTION_MATCH = \ [(utils.cast(int, x.get('index')), utils.cast(int, x.get('ratingKey'))) for x in COLLECTION_MATCH] item['children'] = {} for plex_set_id, set_name in api.collection_list(): if self.isCanceled(): return if plex_set_id not in COLLECTION_XMLS: # Get Plex metadata for collections - a pain for index, collection_plex_id in COLLECTION_MATCH: if index == plex_set_id: collection_xml = PF.GetPlexMetadata(collection_plex_id) try: collection_xml[0].attrib except (TypeError, IndexError, AttributeError): LOG.error('Could not get collection %s %s', collection_plex_id, set_name) continue COLLECTION_XMLS[plex_set_id] = collection_xml break else: LOG.error('Did not find Plex collection %s %s', plex_set_id, set_name) continue item['children'][plex_set_id] = COLLECTION_XMLS[plex_set_id] def run(self): """ Do the work """ if self.isCanceled(): return # Download Metadata item = { 'xml': PF.GetPlexMetadata(self.plex_id), 'children': None } if item['xml'] is None: # Did not receive a valid XML - skip that item for now LOG.error("Could not get metadata for %s. Skipping that item " "for now", self.plex_id) return elif item['xml'] == 401: LOG.error('HTTP 401 returned by PMS. Too much strain? ' 'Cancelling sync for now') utils.window('plex_scancrashed', value='401') return if not self.isCanceled() and self.plex_type == v.PLEX_TYPE_MOVIE: # Check for collections/sets collections = False for child in item['xml'][0]: if child.tag == 'Collection': collections = True break if collections: global LOCK with LOCK: self._collections(item) if not self.isCanceled() and self.get_children: children_xml = PF.GetAllPlexChildren(self.plex_id) try: children_xml[0].attrib except (TypeError, IndexError, AttributeError): LOG.error('Could not get children for Plex id %s', self.plex_id) else: item['children'] = children_xml if not self.isCanceled(): self.queue.put(item)