Update fetchItem to search all subitems as well

This commit is contained in:
Michael Shepanski 2017-02-09 16:29:23 -05:00
parent 08e61960e7
commit ebf18ba020
2 changed files with 73 additions and 44 deletions

View file

@ -169,40 +169,58 @@ class PlexObject(object):
return self return self
def _checkAttrs(self, elem, **kwargs): def _checkAttrs(self, elem, **kwargs):
for kwarg, query in kwargs.items(): logme = elem.attrib.get('ratingKey') == '746'
# strip underscore from special cased attrs attrsFound = {}
if kwarg in ('_key', '_cls', '_tag'): for attr, query in kwargs.items():
kwarg = kwarg[1:] attr, op, operator = self._getAttrOperator(attr)
# extract the kwarg operator if present values = self._getAttrValue(elem, attr)
op, operator = 'exact', OPERATORS['exact'] if logme: log.debug('Check %s.%s__%s=%s (value=%s)', elem.tag, attr, op, str(query)[:20], str(values)[:20])
if '__' in kwarg: # special case ismissing operator
kwarg, op = kwarg.rsplit('__', 1)
if op not in OPERATORS:
raise BadRequest('Invalid filter operator: __%s' % op)
operator = OPERATORS[op]
# get value from elem and check ismissing operator
value = elem.attrib.get(kwarg)
log.debug("Checking %s.%s__%s=%s (value=%s)", elem.tag, kwarg, op,
str(query)[:20], str(value)[:20])
if op == 'ismissing': if op == 'ismissing':
if query not in (True, False): if query not in (True, False):
raise BadRequest('Value when using __ismissing must be in (True, False).') raise BadRequest('Value when using __ismissing must be in (True, False).')
if (query is True and value) or (query is False and not value): if (query is True and values) or (query is False and not values):
return False return False
# special case query=None,0,'' to include missing attr # special case query in (None,0,'') to include missing attr
if op == 'exact' and query in (None, 0, '') and value is None: if op == 'exact' and query in (None, 0, '') and not values:
return True return True
# return if attr were looking for is missing # return if attr were looking for is missing
if not value: attrsFound[attr] = False
return False for value in values:
# cast value to the same type as query if isinstance(query, int): value = int(value)
if isinstance(query, int): value = int(value) if isinstance(query, float): value = float(value)
if isinstance(query, float): value = float(value) if isinstance(query, bool): value = bool(int(value))
if isinstance(query, bool): value = bool(int(value)) if logme: log.info('%s %s %s', value, op, query)
# perform the comparison if operator(value, query):
if not operator(value, query): attrsFound[attr] = True
return False break
return True if logme: log.info(attrsFound)
return all(attrsFound.values())
def _getAttrOperator(self, attr):
attr = attr.lstrip('_')
for op, operator in OPERATORS.items():
if attr.endswith('__%s' % op):
attr = attr.rsplit('__', 1)[0]
return attr, op, operator
# default to exact match
return attr, 'exact', OPERATORS['exact']
def _getAttrValue(self, elem, attrstr, results=None):
#log.debug('Fetching %s in %s', attrstr, elem.tag)
parts = attrstr.split('__', 1)
attr = parts[0]
attrstr = parts[1] if len(parts) == 2 else None
if attrstr:
results = [] if results is None else results
for child in [c for c in elem if c.tag.lower() == attr.lower()]:
results += self._getAttrValue(child, attrstr, results)
return [r for r in results if r is not None]
# loop through attrs so we can perform case-insensative match
for _attr, value in elem.attrib.items():
if attr.lower() == _attr.lower():
return [value]
return []
def _loadData(self, data): def _loadData(self, data):
raise NotImplementedError('Abstract method not implemented.') raise NotImplementedError('Abstract method not implemented.')

View file

@ -173,7 +173,7 @@ class PlexAttributes():
self._load_attrs(playqueue, 'pq') self._load_attrs(playqueue, 'pq')
def _parse_sync(self): def _parse_sync(self):
# TODO: Get this working.. # TODO: Get plexattrs._parse_sync() working.
pass pass
def _load_attrs(self, obj, cat=None): def _load_attrs(self, obj, cat=None):
@ -229,29 +229,39 @@ class PlexAttributes():
def print_report(self): def print_report(self):
total_attrs = 0 total_attrs = 0
for clsname in sorted(self.attrs.keys()): for clsname in sorted(self.attrs.keys()):
meta = self.attrs[clsname] if self._clsname_match(clsname):
count = meta['total'] meta = self.attrs[clsname]
print(_('\n%s (%s)\n%s' % (clsname, count, '-'*30), 'yellow')) count = meta['total']
attrs = sorted(set(list(meta['xml'].keys()) + list(meta['obj'].keys()))) print(_('\n%s (%s)\n%s' % (clsname, count, '-'*30), 'yellow'))
for attr in attrs: attrs = sorted(set(list(meta['xml'].keys()) + list(meta['obj'].keys())))
state = self._attr_state(clsname, attr, meta) for attr in attrs:
count = meta['xml'].get(attr, 0) state = self._attr_state(clsname, attr, meta)
categories = ','.join(meta['categories'].get(attr, ['--'])) count = meta['xml'].get(attr, 0)
examples = '; '.join(list(meta['examples'].get(attr, ['--']))[:3])[:80] categories = ','.join(meta['categories'].get(attr, ['--']))
print('%7s %3s %-30s %-20s %s' % (count, state, attr, categories, examples)) examples = '; '.join(list(meta['examples'].get(attr, ['--']))[:3])[:80]
total_attrs += count print('%7s %3s %-30s %-20s %s' % (count, state, attr, categories, examples))
total_attrs += count
print(_('\nSUMMARY\n%s' % ('-'*30), 'yellow')) print(_('\nSUMMARY\n%s' % ('-'*30), 'yellow'))
print('%7s %3s %3s %-20s %s' % ('total', 'new', 'old', 'categories', 'clsname')) print('%7s %3s %3s %-20s %s' % ('total', 'new', 'old', 'categories', 'clsname'))
for clsname in sorted(self.attrs.keys()): for clsname in sorted(self.attrs.keys()):
print('%7s %12s %12s %s' % (self.attrs[clsname]['total'], if self._clsname_match(clsname):
_(self.attrs[clsname]['new'] or '', 'cyan'), print('%7s %12s %12s %s' % (self.attrs[clsname]['total'],
_(self.attrs[clsname]['old'] or '', 'red'), _(self.attrs[clsname]['new'] or '', 'cyan'),
clsname)) _(self.attrs[clsname]['old'] or '', 'red'),
clsname))
print('\nPlex Version %s' % self.plex.version) print('\nPlex Version %s' % self.plex.version)
print('PlexAPI Version %s' % plexapi.VERSION) print('PlexAPI Version %s' % plexapi.VERSION)
print('Total Objects %s' % sum([x['total'] for x in self.attrs.values()])) print('Total Objects %s' % sum([x['total'] for x in self.attrs.values()]))
print('Runtime %s min\n' % self.runtime) print('Runtime %s min\n' % self.runtime)
def _clsname_match(self, clsname):
if not self.clsnames:
return True
for cname in self.clsnames:
if cname.lower() in clsname.lower():
return True
return False
def _attr_state(self, clsname, attr, meta): def _attr_state(self, clsname, attr, meta):
if attr in meta['xml'].keys() and attr not in meta['obj'].keys(): if attr in meta['xml'].keys() and attr not in meta['obj'].keys():
self.attrs[clsname]['new'] += 1 self.attrs[clsname]['new'] += 1
@ -280,6 +290,7 @@ if __name__ == '__main__':
if not opts.force and os.path.exists(CACHEPATH): if not opts.force and os.path.exists(CACHEPATH):
with open(CACHEPATH, 'rb') as handle: with open(CACHEPATH, 'rb') as handle:
plexattrs = pickle.load(handle) plexattrs = pickle.load(handle)
plexattrs.clsnames = [c for c in opts.clsnames.split(',') if c]
if not plexattrs: if not plexattrs:
plexattrs = PlexAttributes(opts).run() plexattrs = PlexAttributes(opts).run()
with open(CACHEPATH, 'wb') as handle: with open(CACHEPATH, 'wb') as handle: