Add m3u8 export file format

This commit is contained in:
JonnyWong16 2020-10-02 19:42:24 -07:00
parent be9f06795d
commit 34c9ede9c9
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
6 changed files with 89 additions and 17 deletions

View file

@ -3491,6 +3491,9 @@ pre::-webkit-scrollbar-thumb {
.selectize-input input[type='text'] {
height: 20px;
}
.selectize-input.disabled, .selectize-input.disabled * {
cursor: not-allowed !important;
}
.small-muted {
font-size: small;
color: #777;

View file

@ -79,10 +79,10 @@ DOCUMENTATION :: END
<p class="help-block">Add additional fields to the selected media info export level.</p>
</div>
<div class="form-group">
<label for="file_format_select">File Format</label>
<label for="export_file_format">File Format</label>
<div class="row">
<div class="col-md-12">
<select class="form-control" id="file_format_select" name="file_format_select">
<select class="form-control" id="export_file_format" name="export_file_format">
% for format in file_formats:
<option value="${format}">${format.upper()}</option>
% endfor
@ -184,13 +184,31 @@ DOCUMENTATION :: END
}
getExportFields();
$('#export_file_format').on('change', function() {
if ($(this).val() === 'm3u8') {
$('#metadata_export_level_select').prop('disabled', true);
$('#media_info_export_level_select').prop('disabled', true);
$("#export_include_thumb").prop('disabled', true);
$("#export_include_art").prop('disabled', true);
export_custom_metadata_fields.disable();
export_custom_media_info_fields.disable();
} else {
$('#metadata_export_level_select').prop('disabled', false);
$('#media_info_export_level_select').prop('disabled', false);
$("#export_include_thumb").prop('disabled', false);
$("#export_include_art").prop('disabled', false);
export_custom_metadata_fields.enable();
export_custom_media_info_fields.enable();
}
})
$("#export_metadata").click(function() {
var section_id = $('#export_section_id').val();
var user_id = $('#export_user_id').val();
var rating_key = $('#export_rating_key').val();
var metadata_export_level = $('#metadata_export_level_select option:selected').val();
var media_info_export_level = $('#media_info_export_level_select option:selected').val();
var file_format = $('#file_format_select option:selected').val();
var file_format = $('#export_file_format option:selected').val();
var include_thumb = $("#export_include_thumb").is(':checked') ? 1 : 0;
var include_art = $("#export_include_art").is(':checked') ? 1 : 0;
var custom_fields = [

View file

@ -989,14 +989,14 @@ DOCUMENTATION :: END
clearSearchButton('export_table-RK-${data["rating_key"]}', export_table);
}
$(document).ready(function () {
if ($('#tabs-history').length) {
$('a[href="#tabs-export"]').on('shown.bs.tab', function() {
if (typeof(export_table) === 'undefined') {
loadExportTable();
}
});
} else {
$(document).ready(function () {
if (!($('#tabs-history').length)) {
loadExportTable();
}
});

View file

@ -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()

View file

@ -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))

View file

@ -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.'