mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-16 02:02:58 -07:00
Add m3u8 export file format
This commit is contained in:
parent
be9f06795d
commit
34c9ede9c9
6 changed files with 89 additions and 17 deletions
|
@ -91,7 +91,7 @@ class Export(object):
|
|||
}
|
||||
METADATA_LEVELS = (0, 1, 2, 3, 9)
|
||||
MEDIA_INFO_LEVELS = (0, 1, 2, 3, 9)
|
||||
FILE_FORMATS = ('csv', 'json', 'xml')
|
||||
FILE_FORMATS = ('csv', 'json', 'xml', 'm3u8')
|
||||
EXPORT_TYPES = ('all', 'collection', 'playlist')
|
||||
|
||||
def __init__(self, section_id=None, user_id=None, rating_key=None, file_format='csv',
|
||||
|
@ -101,7 +101,7 @@ class Export(object):
|
|||
self.section_id = helpers.cast_to_int(section_id) or None
|
||||
self.user_id = helpers.cast_to_int(user_id) or None
|
||||
self.rating_key = helpers.cast_to_int(rating_key) or None
|
||||
self.file_format = file_format
|
||||
self.file_format = str(file_format).lower()
|
||||
self.metadata_level = helpers.cast_to_int(metadata_level)
|
||||
self.media_info_level = helpers.cast_to_int(media_info_level)
|
||||
self.include_thumb = include_thumb
|
||||
|
@ -120,6 +120,14 @@ class Export(object):
|
|||
self.file_size = None
|
||||
self.success = False
|
||||
|
||||
# Reset export options for m3u8
|
||||
if self.file_format == 'm3u8':
|
||||
self.metadata_level = 1
|
||||
self.media_info_level = 1
|
||||
self.include_thumb = False
|
||||
self.include_art = False
|
||||
self.custom_fields = ''
|
||||
|
||||
def return_attrs(self, media_type, flatten=False):
|
||||
# o: current object
|
||||
# e: element in object attribute value list
|
||||
|
@ -1629,10 +1637,15 @@ class Export(object):
|
|||
outfile.write(json_data)
|
||||
|
||||
elif self.file_format == 'xml':
|
||||
xml_data = helpers.dict2xml({self.media_type: result}, root_node='export')
|
||||
xml_data = helpers.dict_to_xml({self.media_type: result}, root_node='export')
|
||||
with open(filepath, 'w', encoding='utf-8') as outfile:
|
||||
outfile.write(xml_data)
|
||||
|
||||
elif self.file_format == 'm3u8':
|
||||
m3u8_data = self.dict_to_m3u8(result)
|
||||
with open(filepath, 'w', encoding='utf-8') as outfile:
|
||||
outfile.write(m3u8_data)
|
||||
|
||||
self.file_size = os.path.getsize(filepath)
|
||||
|
||||
if os.path.exists(images_folder):
|
||||
|
@ -1773,6 +1786,41 @@ class Export(object):
|
|||
def is_media_info_attr(attr):
|
||||
return attr.startswith('media.') or attr == 'locations'
|
||||
|
||||
def dict_to_m3u8(self, data):
|
||||
items = self._get_m3u8_items(data)
|
||||
|
||||
m3u8 = '#EXTM3U\n'
|
||||
m3u8 += '# Playlist: {}\n\n'.format(self.filename)
|
||||
m3u8_item_template = '# ratingKey: {ratingKey}\n#EXTINF:{duration},{title}\n{location}\n'
|
||||
m3u8_items = []
|
||||
|
||||
for item in items:
|
||||
m3u8_items.append(m3u8_item_template.format(**item))
|
||||
|
||||
m3u8 = m3u8 + '\n'.join(m3u8_items)
|
||||
|
||||
return m3u8
|
||||
|
||||
def _get_m3u8_items(self, data):
|
||||
items = []
|
||||
|
||||
for d in data:
|
||||
if 'locations' in d:
|
||||
location = {
|
||||
'ratingKey': d['ratingKey'],
|
||||
'duration': d['duration'],
|
||||
'title': d['title'],
|
||||
'location': d['locations'][0]
|
||||
}
|
||||
items.append(location)
|
||||
|
||||
child_media_type = self.CHILD_MEDIA_TYPES[d['type']]
|
||||
if child_media_type:
|
||||
child_locations = self._get_m3u8_items(d[self.PLURAL_MEDIA_TYPES[child_media_type]])
|
||||
items.extend(child_locations)
|
||||
|
||||
return items
|
||||
|
||||
|
||||
def get_export(export_id):
|
||||
db = database.MonitorDatabase()
|
||||
|
|
|
@ -1385,7 +1385,7 @@ def escape_xml(value):
|
|||
|
||||
|
||||
# https://gist.github.com/reimund/5435343/
|
||||
def dict2xml(d, root_node=None, indent=4, level=0):
|
||||
def dict_to_xml(d, root_node=None, indent=4, level=0):
|
||||
wrap = not bool(root_node is None or isinstance(d, list))
|
||||
root = root_node or 'objects'
|
||||
root_singular = root[:-1] if root.endswith('s') and isinstance(d, list) else root
|
||||
|
@ -1395,9 +1395,9 @@ def dict2xml(d, root_node=None, indent=4, level=0):
|
|||
if isinstance(d, dict):
|
||||
for key, value in sorted(d.items()):
|
||||
if isinstance(value, dict):
|
||||
children.append(dict2xml(value, key, level=level + 1))
|
||||
children.append(dict_to_xml(value, key, level=level + 1))
|
||||
elif isinstance(value, list):
|
||||
children.append(dict2xml(value, key, level=level + 1))
|
||||
children.append(dict_to_xml(value, key, level=level + 1))
|
||||
else:
|
||||
xml = '{} {}="{}"'.format(xml, key, escape_xml(value))
|
||||
elif isinstance(d, list):
|
||||
|
@ -1405,7 +1405,7 @@ def dict2xml(d, root_node=None, indent=4, level=0):
|
|||
# Custom tag replacement for collections/playlists
|
||||
if isinstance(value, dict) and root in ('children', 'items'):
|
||||
root_singular = value.get('type', root_singular)
|
||||
children.append(dict2xml(value, root_singular, level=level))
|
||||
children.append(dict_to_xml(value, root_singular, level=level))
|
||||
else:
|
||||
children.append(escape_xml(d))
|
||||
|
||||
|
|
|
@ -6707,6 +6707,9 @@ class WebInterface(object):
|
|||
elif result['file_format'] == 'xml':
|
||||
return serve_file(filepath, name=result['filename'], content_type='application/xml;charset=UTF-8')
|
||||
|
||||
elif result['file_format'] == 'm3u8':
|
||||
return serve_file(filepath, name=result['filename'], content_type='text/plain;charset=UTF-8')
|
||||
|
||||
else:
|
||||
if result and result.get('complete') == 0:
|
||||
msg = 'Export is still being processed.'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue