mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-14 01:02:59 -07:00
Separate metadata and media export levels
This commit is contained in:
parent
35cdef1340
commit
ca06154805
3 changed files with 133 additions and 89 deletions
|
@ -27,22 +27,34 @@ DOCUMENTATION :: END
|
|||
<input type="hidden" id="section_id" name="section_id" value="${section_id or ''}" />
|
||||
<input type="hidden" id="rating_key" name="rating_key" value="${rating_key or ''}" />
|
||||
<div class="form-group">
|
||||
<label for="export_level_select">Export Level</label>
|
||||
<label for="metadata_export_level_select">Metadata Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="export_level_select" name="export_level_select">
|
||||
<select class="form-control" id="metadata_export_level_select" name="metadata_export_level_select">
|
||||
<option value="1">Level 1 - Basic Metadata</option>
|
||||
<option value="2">Level 2 - Extended Metadata</option>
|
||||
<option value="3">Level 3 - All Metadata</option>
|
||||
<option value="4">Level 4 - Basic Media Info</option>
|
||||
<option value="5">Level 5 - Extended Media Info</option>
|
||||
<option value="6">Level 6 - All Media Info</option>
|
||||
<option value="9">Level 9 - Everything</option>
|
||||
<option value="-999">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the export level.</p>
|
||||
<p class="help-block">Select the metadata export level.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="media_info_export_level_select">Media Info Export Level</label>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<select class="form-control" id="media_info_export_level_select" name="media_info_export_level_select">
|
||||
<option value="1">Level 1 - Basic Media Info</option>
|
||||
<option value="2">Level 2 - Extended Media Info</option>
|
||||
<option value="3">Level 3 - All Media Info</option>
|
||||
<option value="9">Level 9 - Everything</option>
|
||||
<option value="-999">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Select the media info export level.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="file_format_select">File Format</label>
|
||||
|
@ -69,7 +81,8 @@ DOCUMENTATION :: END
|
|||
$("#export_metadata").click(function() {
|
||||
var section_id = $('#section_id').val();
|
||||
var rating_key = $('#rating_key').val();
|
||||
var export_level = $('#export_level_select option:selected').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();
|
||||
|
||||
$.ajax({
|
||||
|
@ -77,7 +90,8 @@ DOCUMENTATION :: END
|
|||
data: {
|
||||
section_id: section_id,
|
||||
rating_key: rating_key,
|
||||
export_level: export_level,
|
||||
metadata_level: metadata_export_level,
|
||||
media_info_level: media_info_export_level,
|
||||
file_format: file_format
|
||||
},
|
||||
async: true,
|
||||
|
|
|
@ -23,6 +23,7 @@ import json
|
|||
import os
|
||||
import threading
|
||||
|
||||
from copy import deepcopy
|
||||
from functools import partial, reduce
|
||||
from io import open
|
||||
from multiprocessing.dummy import Pool as ThreadPool
|
||||
|
@ -859,7 +860,8 @@ PLAYLIST_ATTRS = {
|
|||
'items': lambda e: helpers.get_attrs_to_dict(e, MEDIA_TYPES[e.type][0])
|
||||
}
|
||||
|
||||
MOVIE_LEVELS = {
|
||||
MOVIE_LEVELS = [
|
||||
{
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'originalTitle', 'originallyAvailableAt', 'year',
|
||||
'rating', 'ratingImage', 'audienceRating', 'audienceRatingImage', 'userRating', 'contentRating',
|
||||
|
@ -873,20 +875,22 @@ MOVIE_LEVELS = {
|
|||
'art', 'thumb', 'key', 'chapterSource',
|
||||
'chapters.tag', 'chapters.index', 'chapters.start', 'chapters.end', 'chapters.thumb',
|
||||
'updatedAt', 'lastViewedAt', 'viewCount'
|
||||
],
|
||||
4: [
|
||||
]
|
||||
},
|
||||
{
|
||||
1: [
|
||||
'locations', 'media.aspectRatio', 'media.audioChannels', 'media.audioCodec', 'media.audioProfile',
|
||||
'media.bitrate', 'media.container', 'media.duration', 'media.height', 'media.width',
|
||||
'media.videoCodec', 'media.videoFrameRate', 'media.videoProfile', 'media.videoResolution',
|
||||
'media.optimizedVersion', 'media.hdr'
|
||||
],
|
||||
5: [
|
||||
2: [
|
||||
'media.parts.accessible', 'media.parts.exists', 'media.parts.file', 'media.parts.duration',
|
||||
'media.parts.container', 'media.parts.indexes', 'media.parts.size', 'media.parts.sizeHuman',
|
||||
'media.parts.audioProfile', 'media.parts.videoProfile',
|
||||
'media.parts.optimizedForStreaming', 'media.parts.deepAnalysisVersion'
|
||||
],
|
||||
6: [
|
||||
3: [
|
||||
'media.parts.videoStreams.codec', 'media.parts.videoStreams.bitrate',
|
||||
'media.parts.videoStreams.language', 'media.parts.videoStreams.languageCode',
|
||||
'media.parts.videoStreams.title', 'media.parts.videoStreams.displayTitle',
|
||||
|
@ -910,6 +914,7 @@ MOVIE_LEVELS = {
|
|||
'media.parts.subtitleStreams.default'
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
SHOW_LEVELS = {}
|
||||
|
||||
|
@ -952,9 +957,11 @@ def get_any_hdr(obj, root):
|
|||
return any(vs.get('hdr') for p in media.get('parts', []) for vs in p.get('videoStreams', []))
|
||||
|
||||
|
||||
def export(section_id=None, rating_key=None, file_format='json', metadata_level=1, media_info_level=1):
|
||||
timestamp = helpers.timestamp()
|
||||
|
||||
level = helpers.cast_to_int(level)
|
||||
metadata_level = helpers.cast_to_int(metadata_level)
|
||||
media_info_level = helpers.cast_to_int(media_info_level)
|
||||
|
||||
if not section_id and not rating_key:
|
||||
logger.error("Tautulli Exporter :: Export called but no section_id or rating_key provided.")
|
||||
|
@ -965,8 +972,11 @@ def get_any_hdr(obj, root):
|
|||
elif section_id and not str(section_id).isdigit():
|
||||
logger.error("Tautulli Exporter :: Export called with invalid section_id '%s'.", section_id)
|
||||
return
|
||||
elif not level:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid level '%s'.", level)
|
||||
elif not metadata_level:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid metadata_level '%s'.", metadata_level)
|
||||
return
|
||||
elif not media_info_level:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid media_info_level '%s'.", media_info_level)
|
||||
return
|
||||
elif file_format not in ('json', 'csv'):
|
||||
logger.error("Tautulli Exporter :: Export called but invalid file_format '%s' provided.", file_format)
|
||||
|
@ -975,7 +985,8 @@ def get_any_hdr(obj, root):
|
|||
plex = Plex(plexpy.CONFIG.PMS_URL, plexpy.CONFIG.PMS_TOKEN)
|
||||
|
||||
if rating_key:
|
||||
logger.debug("Tautulli Exporter :: Export called with rating_key %s, level %d", rating_key, level)
|
||||
logger.debug("Tautulli Exporter :: Export called with rating_key %s, metadata_level %d, media_info_level %d",
|
||||
rating_key, metadata_level, media_info_level)
|
||||
|
||||
item = plex.get_item(helpers.cast_to_int(rating_key))
|
||||
media_type = item.type
|
||||
|
@ -997,7 +1008,8 @@ def get_any_hdr(obj, root):
|
|||
items = [item]
|
||||
|
||||
elif section_id:
|
||||
logger.debug("Tautulli Exporter :: Export called with section_id %s, level %d", section_id, level)
|
||||
logger.debug("Tautulli Exporter :: Export called with section_id %s, metadata_level %d, media_info_level %d",
|
||||
rating_key, metadata_level, media_info_level)
|
||||
|
||||
library = plex.get_library(section_id)
|
||||
media_type = library.type
|
||||
|
@ -1013,21 +1025,35 @@ def get_any_hdr(obj, root):
|
|||
logger.error("Tautulli Exporter :: Cannot export media type '%s'", media_type)
|
||||
return
|
||||
|
||||
media_attrs, level_attrs = MEDIA_TYPES[media_type]
|
||||
media_attrs, (metadata_level_attrs, media_info_level_attrs) = MEDIA_TYPES[media_type]
|
||||
|
||||
if level == 9:
|
||||
export_attrs = media_attrs
|
||||
else:
|
||||
if level not in level_attrs:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid level '%s'.", level)
|
||||
if metadata_level != 9 and metadata_level not in metadata_level_attrs:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid metadata_level '%s'.", metadata_level)
|
||||
return
|
||||
elif media_info_level != 9 and media_info_level not in media_info_level_attrs:
|
||||
logger.error("Tautulli Exporter :: Export called with invalid media_info_level '%s'.", media_info_level)
|
||||
return
|
||||
|
||||
export_attrs_set = set()
|
||||
_levels = sorted(level_attrs.keys())
|
||||
for _level in _levels[:_levels.index(level) + 1]:
|
||||
export_attrs_set.update(level_attrs[_level])
|
||||
|
||||
export_attrs_list = []
|
||||
export_attrs_set = set()
|
||||
|
||||
if metadata_level == 9:
|
||||
metadata_export_attrs = deepcopy(media_attrs)
|
||||
del metadata_export_attrs['media']
|
||||
export_attrs_list.append(metadata_export_attrs)
|
||||
else:
|
||||
_metadata_levels = sorted(metadata_level_attrs.keys())
|
||||
for _metadata_level in _metadata_levels[:_metadata_levels.index(metadata_level) + 1]:
|
||||
export_attrs_set.update(metadata_level_attrs[_metadata_level])
|
||||
|
||||
if media_info_level == 9:
|
||||
media_info_export_attrs = {'media': deepcopy(media_attrs['media'])}
|
||||
export_attrs_list.append(media_info_export_attrs)
|
||||
else:
|
||||
_media_info_levels = sorted(media_info_level_attrs.keys())
|
||||
for _media_info_level in _media_info_levels[:_media_info_levels.index(media_info_level) + 1]:
|
||||
export_attrs_set.update(media_info_level_attrs[_media_info_level])
|
||||
|
||||
for attr in export_attrs_set:
|
||||
try:
|
||||
value = helpers.get_dict_value_by_path(media_attrs, attr)
|
||||
|
@ -1091,6 +1117,8 @@ def _real_export(export_id, items, attrs, file_format, filename):
|
|||
except Exception as e:
|
||||
set_export_state(export_id=export_id, success=False)
|
||||
logger.error("Tautulli Exporter :: Failed to export '%s': %s", filename, e)
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
success = False
|
||||
|
||||
finally:
|
||||
|
|
|
@ -6491,7 +6491,7 @@ class WebInterface(object):
|
|||
@requireAuth(member_of("admin"))
|
||||
@addtoapi()
|
||||
def export_metadata(self, section_id=None, rating_key=None, file_format='json',
|
||||
export_level=1, **kwargs):
|
||||
metadata_level=1, media_info_level=1, **kwargs):
|
||||
""" Export library or media metadata to a file
|
||||
|
||||
```
|
||||
|
@ -6501,7 +6501,8 @@ class WebInterface(object):
|
|||
|
||||
Optional parameters:
|
||||
file_format (str): 'json' (default) or 'csv'
|
||||
export_level (int): The level of metadata to export
|
||||
metadata_level (int): The level of metadata to export (default 1)
|
||||
media_info_level (int): The level of media info to export (default 1)
|
||||
|
||||
Returns:
|
||||
json:
|
||||
|
@ -6513,7 +6514,8 @@ class WebInterface(object):
|
|||
result = exporter.export(section_id=section_id,
|
||||
rating_key=rating_key,
|
||||
file_format=file_format,
|
||||
level=export_level)
|
||||
metadata_level=metadata_level,
|
||||
media_info_level=media_info_level)
|
||||
|
||||
if result:
|
||||
return {'result': 'success', 'message': 'Metadata export has started.'}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue