mirror of
https://github.com/pkkid/python-plexapi
synced 2024-11-26 05:30:20 +00:00
Update fetchItem to search all subitems as well
This commit is contained in:
parent
08e61960e7
commit
ebf18ba020
2 changed files with 73 additions and 44 deletions
|
@ -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.')
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in a new issue