python-plexapi/tools/findattrs.py

118 lines
4.3 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Find all attributes for each library type
"""
import pickle, os, sys
from collections import defaultdict
from plexapi.server import PlexServer
from xml.etree import ElementTree
MAX_SEEN = 9999
MAX_EXAMPLES = 10
PICKLE_PATH = '/tmp/findattrs.pickle'
ETYPES = ['artist', 'album', 'track', 'movie', 'show', 'season', 'episode']
def find_attrs(plex, key, result, examples, seen, indent=0):
for elem in plex.query(key):
attrs = sorted(elem.attrib.keys())
etype = elem.attrib.get('type')
if not etype or seen[etype] >= MAX_SEEN:
continue
seen[etype] += 1
sys.stdout.write('.'); sys.stdout.flush()
# find all attriutes in this element
for attr in attrs:
result[attr].add(etype)
if elem.attrib[attr] and len(examples[attr]) <= MAX_EXAMPLES:
examples[attr].add(elem.attrib[attr])
# iterate all subelements
for subelem in elem:
if subelem.tag not in ETYPES:
subattr = subelem.tag + '[]'
result[subattr].add(etype)
if len(examples[subattr]) <= MAX_EXAMPLES:
xmlstr = ElementTree.tostring(subelem, encoding='utf8').split('\n')[1]
examples[subattr].add(xmlstr)
# recurse into the main element (loading its key)
if etype in ETYPES:
subkey = elem.attrib['key']
if key != subkey and seen[etype] < MAX_SEEN:
find_attrs(plex, subkey, result, examples, seen, indent+2)
return result
def find_all_attrs():
try:
result = defaultdict(set)
examples = defaultdict(set)
seen = defaultdict(int)
plex = PlexServer()
find_attrs(plex, '/status/sessions', result, examples, seen)
for section in plex.library.sections():
for elem in section.all():
# check weve seen too many of this type of elem
if seen[elem.type] >= MAX_SEEN:
continue
seen[elem.type] += 1
# fetch the xml for this elem
key = elem.key.replace('/children', '')
find_attrs(plex, key, result, examples, seen)
except KeyboardInterrupt:
pass
return result, examples, seen
def print_results(result, examples, seen):
print_general_summary(result, examples)
print_summary_by_etype(result, examples)
print_seen_etypes(seen)
def print_general_summary(result, examples):
print('\n--- general summary ---')
for attr, etypes in sorted(result.items(), key=lambda x: x[0].lower()):
args = [attr]
args += [etype if etype in etypes else '--' for etype in ETYPES]
args.append(list(examples[attr])[0][:30] if examples[attr] else '_NA_')
print('%-23s %-8s %-8s %-8s %-8s %-8s %-8s %-8s %s' % tuple(args))
def print_summary_by_etype(result, examples):
# find super attributes (in all etypes)
result['super'] = set(['librarySectionID', 'index', 'titleSort'])
for attr, etypes in result.items():
if len(etypes) == 7:
result['super'].add(attr)
# print the summary
for etype in ['super'] + ETYPES:
print('\n--- %s ---' % etype)
for attr in sorted(result.keys(), key=lambda x:x[0].lower()):
if (etype in result[attr] and attr not in result['super']) or (etype == 'super' and attr in result['super']):
example = list(examples[attr])[0][:80] if examples[attr] else '_NA_'
print('%-23s %s' % (attr, example))
def print_seen_etypes(seen):
print('\n')
for etype, count in seen.items():
print('%-8s %s' % (etype, count))
def save_pickle(result, examples, seen):
with open(PICKLE_PATH, 'w') as handle:
pickle.dump({'result':result, 'examples':examples, 'seen':seen}, handle)
def load_pickle():
if not os.path.exists(PICKLE_PATH):
return None, None, None
with open(PICKLE_PATH, 'r') as handle:
data = pickle.load(handle)
return data['result'], data['examples'], data['seen']
if __name__ == '__main__':
result, examples, seen = load_pickle()
if not result:
result, examples, seen = find_all_attrs()
save_pickle(result, examples, seen)
print_results(result, examples, seen)