Get movie set information asynchronously

This commit is contained in:
croneter 2018-11-07 10:37:32 +01:00
parent e460aea7e8
commit 0db29dd568
4 changed files with 107 additions and 28 deletions

View file

@ -173,13 +173,16 @@ class Movie(ItemBase):
self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, studios) self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, studios)
tags = [section_name] tags = [section_name]
if collections: if collections:
collections_match = api.collections_match()
for plex_set_id, set_name in collections: for plex_set_id, set_name in collections:
tags.append(set_name) tags.append(set_name)
# Add any sets from Plex collection tags # Add any sets from Plex collection tags
kodi_set_id = self.kodi_db.create_collection(set_name) kodi_set_id = self.kodi_db.create_collection(set_name)
self.kodi_db.assign_collection(kodi_set_id, kodi_id) self.kodi_db.assign_collection(kodi_set_id, kodi_id)
for index, coll_plex_id in collections_match: if children is None:
# e.g. when added via websocket
LOG.debug('Costly looking up Plex collection %s: %s',
plex_set_id, set_name)
for index, coll_plex_id in api.collections_match():
# Get Plex artwork for collections - a pain # Get Plex artwork for collections - a pain
if index == plex_set_id: if index == plex_set_id:
set_xml = PF.GetPlexMetadata(coll_plex_id) set_xml = PF.GetPlexMetadata(coll_plex_id)
@ -190,11 +193,16 @@ class Movie(ItemBase):
coll_plex_id) coll_plex_id)
continue continue
set_api = API(set_xml[0]) set_api = API(set_xml[0])
break
elif plex_set_id in children:
# Provided by get_metadata thread
set_api = API(children[plex_set_id][0])
else:
continue
artwork.modify_artwork(set_api.artwork(), artwork.modify_artwork(set_api.artwork(),
kodi_set_id, kodi_set_id,
v.KODI_TYPE_SET, v.KODI_TYPE_SET,
self.kodicursor) self.kodicursor)
break
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags) self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags)
# Process playstate # Process playstate
self.kodi_db.set_resume(file_id, self.kodi_db.set_resume(file_id,

View file

@ -3,7 +3,7 @@
from __future__ import absolute_import, division, unicode_literals from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from .get_metadata import GetMetadataTask from .get_metadata import GetMetadataTask, reset_collections
from . import common, process_metadata, sections from . import common, process_metadata, sections
from .. import utils, backgroundthread, variables as v, state from .. import utils, backgroundthread, variables as v, state
from .. import plex_functions as PF, itemtypes from .. import plex_functions as PF, itemtypes
@ -56,7 +56,7 @@ class FullSync(common.libsync_mixin):
self.current_sync) self.current_sync)
return return
task = GetMetadataTask() task = GetMetadataTask()
task.setup(self.queue, plex_id, self.get_children) task.setup(self.queue, plex_id, self.plex_type, self.get_children)
self.threader.addTask(task) self.threader.addTask(task)
def process_delete(self): def process_delete(self):
@ -119,6 +119,7 @@ class FullSync(common.libsync_mixin):
continue continue
LOG.debug('Waiting for processing thread to finish section') LOG.debug('Waiting for processing thread to finish section')
self.queue.join() self.queue.join()
reset_collections()
try: try:
# Sync playstate of every item # Sync playstate of every item
iterator = PF.SectionItems(section['section_id'], iterator = PF.SectionItems(section['section_id'],

View file

@ -3,13 +3,28 @@ from __future__ import absolute_import, division, unicode_literals
from logging import getLogger from logging import getLogger
from . import common from . import common
from .. import plex_functions as PF, backgroundthread, utils from ..plex_api import API
from .. import plex_functions as PF, backgroundthread, utils, variables as v
###############################################################################
LOG = getLogger("PLEX." + __name__) 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 index>: <collection xml>
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(backgroundthread.Task, common.libsync_mixin): class GetMetadataTask(backgroundthread.Task, common.libsync_mixin):
@ -21,11 +36,47 @@ class GetMetadataTask(backgroundthread.Task, common.libsync_mixin):
queue Queue.Queue() object where this thread will store queue Queue.Queue() object where this thread will store
the downloaded metadata XMLs as etree objects the downloaded metadata XMLs as etree objects
""" """
def setup(self, queue, plex_id, get_children=False): def setup(self, queue, plex_id, plex_type, get_children=False):
self.queue = queue self.queue = queue
self.plex_id = plex_id self.plex_id = plex_id
self.plex_type = plex_type
self.get_children = get_children self.get_children = get_children
def _collections(self, item):
global COLLECTION_MATCH, COLLECTION_XMLS
api = API(item['xml'][0])
if not COLLECTION_MATCH:
COLLECTION_MATCH = PF.collections(api.library_section_id())
if not COLLECTION_MATCH:
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): def run(self):
""" """
Do the work Do the work
@ -47,6 +98,17 @@ class GetMetadataTask(backgroundthread.Task, common.libsync_mixin):
'Cancelling sync for now') 'Cancelling sync for now')
utils.window('plex_scancrashed', value='401') utils.window('plex_scancrashed', value='401')
return 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: if not self.isCanceled() and self.get_children:
children_xml = PF.GetAllPlexChildren(self.plex_id) children_xml = PF.GetAllPlexChildren(self.plex_id)
try: try:

View file

@ -67,6 +67,7 @@ class API(object):
# which media part in the XML response shall we look at? # which media part in the XML response shall we look at?
self.part = 0 self.part = 0
self.mediastream = None self.mediastream = None
self.collections = None
self.server = utils.window('pms_server') self.server = utils.window('pms_server')
def set_part_number(self, number=None): def set_part_number(self, number=None):
@ -345,7 +346,8 @@ class API(object):
collections = [] collections = []
for child in self.item: for child in self.item:
if child.tag == 'Collection': if child.tag == 'Collection':
collections.append((child.get('id'), child.get('tag'))) collections.append((cast(int, child.get('id')),
child.get('tag')))
return collections return collections
def people(self): def people(self):
@ -1270,10 +1272,16 @@ class API(object):
current item's Plex library sectin current item's Plex library sectin
Pass in the collection id of e.g. the movie's metadata Pass in the collection id of e.g. the movie's metadata
""" """
xml = PF.collections(self.library_section_id()) if self.collections is None:
if xml is None: self.collections = PF.collections(self.library_section_id())
if self.collections is None:
LOG.error('Could not download collections for %s',
self.library_section_id())
return [] return []
return [(i.get('index'), i.get('ratingKey')) for i in xml] self.collections = \
[(utils.cast(int, x.get('index')),
utils.cast(int, x.get('ratingKey'))) for x in self.collections]
return self.collections
def set_artwork(self): def set_artwork(self):
""" """