mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-14 01:02:59 -07:00
Add export for all collections and all playlists
This commit is contained in:
parent
d1172f4975
commit
2803a6095b
5 changed files with 98 additions and 61 deletions
|
@ -28,6 +28,7 @@ DOCUMENTATION :: END
|
|||
<input type="hidden" id="export_rating_key" name="export_rating_key" value="${rating_key or ''}" />
|
||||
<input type="hidden" id="export_media_type" name="export_media_type" value="${media_type or ''}" />
|
||||
<input type="hidden" id="export_sub_media_type" name="export_sub_media_type" value="${sub_media_type or ''}" />
|
||||
<input type="hidden" id="export_library_export" name="export_library_export" value="${library_export or ''}" />
|
||||
<div class="form-group">
|
||||
<label for="metadata_export_level_select">Metadata Export Level</label>
|
||||
<div class="row">
|
||||
|
@ -194,6 +195,7 @@ DOCUMENTATION :: END
|
|||
$('#export_custom_metadata_fields').val(),
|
||||
$('#export_custom_media_info_fields').val()
|
||||
].filter(Boolean).join(',');
|
||||
var library_export = $('#export_library_export').val()
|
||||
|
||||
$.ajax({
|
||||
url: 'export_metadata',
|
||||
|
@ -205,7 +207,8 @@ DOCUMENTATION :: END
|
|||
file_format: file_format,
|
||||
include_thumb: include_thumb,
|
||||
include_art: include_art,
|
||||
custom_fields: custom_fields
|
||||
custom_fields: custom_fields,
|
||||
library_export: library_export
|
||||
},
|
||||
async: true,
|
||||
success: function (data) {
|
||||
|
|
|
@ -614,8 +614,8 @@ DOCUMENTATION :: END
|
|||
<div class="btn-group">
|
||||
<button class="btn btn-dark export-button" id="toggle-export-modal" data-toggle="modal" data-target="#export-modal"
|
||||
data-section_id="${data['section_id']}" data-rating_key="${data['rating_key']}"
|
||||
data-media_type="${data['media_type']}" data-sub_media_type="${data['sub_media_type'] or ''}">
|
||||
<i class="fa fa-file-export"></i> Export Metadata
|
||||
data-media_type="${data['media_type']}" data-sub_media_type="${data['sub_media_type'] or data['playlist_type'] or ''}">
|
||||
<i class="fa fa-file-export"></i> Export metadata
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
|
|
|
@ -322,6 +322,13 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
<div class="button-bar">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark export-button" id="toggle-export-modal" data-toggle="modal" data-target="#export-modal"
|
||||
data-section_id="${data['section_id']}" data-media_type="collection" data-sub_media_type="${data['section_type']}"
|
||||
data-library_export="collection">
|
||||
<i class="fa fa-file-export"></i> Export collections
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-collections-table-button" id="refresh-collections-table">
|
||||
<i class="fa fa-refresh"></i> Refresh collections
|
||||
|
@ -362,6 +369,14 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
<div class="button-bar">
|
||||
% if _session['user_group'] == 'admin':
|
||||
<% playlist_sub_media_type = {'movie': 'video', 'show': 'video', 'artist': 'audio', 'photo': 'photo'} %>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark export-button" id="toggle-export-modal" data-toggle="modal" data-target="#export-modal"
|
||||
data-section_id="${data['section_id']}" data-media_type="playlist" data-sub_media_type="${playlist_sub_media_type[data['section_type']]}"
|
||||
data-library_export="playlist">
|
||||
<i class="fa fa-file-export"></i> Export playlists
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark refresh-playlists-table-button" id="refresh-playlists-table">
|
||||
<i class="fa fa-refresh"></i> Refresh playlists
|
||||
|
@ -403,8 +418,9 @@ DOCUMENTATION :: END
|
|||
% if _session['user_group'] == 'admin':
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-dark export-button" id="toggle-export-modal" data-toggle="modal" data-target="#export-modal"
|
||||
data-section_id="${data['section_id']}" data-media_type="${'photoalbum' if data['section_type'] == 'photo' else data['section_type']}">
|
||||
<i class="fa fa-file-export"></i> Export Metadata
|
||||
data-section_id="${data['section_id']}" data-media_type="${'photoalbum' if data['section_type'] == 'photo' else data['section_type']}"
|
||||
data-library_export="all">
|
||||
<i class="fa fa-file-export"></i> Export metadata
|
||||
</button>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
|
@ -705,12 +721,14 @@ DOCUMENTATION :: END
|
|||
});
|
||||
});
|
||||
|
||||
$("#toggle-export-modal").click(function() {
|
||||
$(".export-button").click(function() {
|
||||
$.ajax({
|
||||
url: 'export_metadata_modal',
|
||||
data: {
|
||||
section_id: $(this).data('section_id'),
|
||||
media_type: $(this).data('media_type')
|
||||
media_type: $(this).data('media_type'),
|
||||
sub_media_type: $(this).data('sub_media_type'),
|
||||
library_export: $(this).data('library_export')
|
||||
},
|
||||
cache: false,
|
||||
async: true,
|
||||
|
|
|
@ -90,11 +90,12 @@ class Export(object):
|
|||
METADATA_LEVELS = (0, 1, 2, 3, 9)
|
||||
MEDIA_INFO_LEVELS = (0, 1, 2, 3, 9)
|
||||
FILE_FORMATS = ('csv', 'json', 'xml')
|
||||
LIBRARY_EXPORTS = ('all', 'collection', 'playlist')
|
||||
|
||||
def __init__(self, section_id=None, rating_key=None, file_format='csv',
|
||||
metadata_level=1, media_info_level=1,
|
||||
include_thumb=False, include_art=False,
|
||||
custom_fields=''):
|
||||
custom_fields='', library_export=None):
|
||||
self.section_id = helpers.cast_to_int(section_id) or None
|
||||
self.rating_key = helpers.cast_to_int(rating_key) or None
|
||||
self.file_format = file_format
|
||||
|
@ -104,6 +105,7 @@ class Export(object):
|
|||
self.include_art = include_art
|
||||
self.custom_fields = custom_fields.replace(' ', '')
|
||||
self._custom_fields = {}
|
||||
self.library_export = library_export or 'all'
|
||||
|
||||
self.timestamp = helpers.timestamp()
|
||||
|
||||
|
@ -1080,13 +1082,11 @@ class Export(object):
|
|||
def show_levels():
|
||||
_media_type = 'show'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'seasons'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'originallyAvailableAt', 'year', 'addedAt',
|
||||
'rating', 'userRating', 'contentRating',
|
||||
'studio', 'summary', 'guid', 'duration', 'durationHuman', 'type', 'childCount'
|
||||
'studio', 'summary', 'guid', 'duration', 'durationHuman', 'type', 'childCount',
|
||||
'seasons'
|
||||
],
|
||||
2: [
|
||||
'roles.tag', 'roles.role',
|
||||
|
@ -1105,14 +1105,12 @@ class Export(object):
|
|||
def season_levels():
|
||||
_media_type = 'season'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'episodes'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'addedAt',
|
||||
'userRating',
|
||||
'summary', 'guid', 'type', 'index',
|
||||
'parentTitle', 'parentRatingKey', 'parentGuid'
|
||||
'parentTitle', 'parentRatingKey', 'parentGuid',
|
||||
'episodes'
|
||||
],
|
||||
2: [
|
||||
'fields.name', 'fields.locked'
|
||||
|
@ -1194,13 +1192,11 @@ class Export(object):
|
|||
def artist_levels():
|
||||
_media_type = 'artist'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'albums'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'addedAt',
|
||||
'rating', 'userRating',
|
||||
'summary', 'guid', 'type'
|
||||
'summary', 'guid', 'type',
|
||||
'albums'
|
||||
],
|
||||
2: [
|
||||
'collections.tag', 'genres.tag', 'countries.tag', 'moods.tag', 'styles.tag',
|
||||
|
@ -1218,14 +1214,12 @@ class Export(object):
|
|||
def album_levels():
|
||||
_media_type = 'album'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'tracks'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'originallyAvailableAt', 'addedAt',
|
||||
'rating', 'userRating',
|
||||
'summary', 'guid', 'type', 'index',
|
||||
'parentTitle', 'parentRatingKey', 'parentGuid'
|
||||
'parentTitle', 'parentRatingKey', 'parentGuid',
|
||||
'tracks'
|
||||
],
|
||||
2: [
|
||||
'collections.tag', 'genres.tag', 'labels.tag', 'moods.tag', 'styles.tag',
|
||||
|
@ -1302,12 +1296,10 @@ class Export(object):
|
|||
def photo_album_levels():
|
||||
_media_type = 'photoalbum'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'photos'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'addedAt',
|
||||
'summary', 'guid', 'type', 'index',
|
||||
'photos'
|
||||
],
|
||||
2: [
|
||||
'fields.name', 'fields.locked'
|
||||
|
@ -1361,14 +1353,12 @@ class Export(object):
|
|||
def collection_levels():
|
||||
_media_type = 'collection'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'children'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'titleSort', 'minYear', 'maxYear', 'addedAt',
|
||||
'contentRating',
|
||||
'summary', 'guid', 'type', 'subtype', 'childCount',
|
||||
'collectionMode', 'collectionSort'
|
||||
'collectionMode', 'collectionSort',
|
||||
'children'
|
||||
],
|
||||
2: [
|
||||
'labels.tag',
|
||||
|
@ -1386,13 +1376,11 @@ class Export(object):
|
|||
def playlist_levels():
|
||||
_media_type = 'playlist'
|
||||
_metadata_levels = {
|
||||
0: [
|
||||
'items'
|
||||
],
|
||||
1: [
|
||||
'ratingKey', 'title', 'addedAt',
|
||||
'summary', 'guid', 'type', 'duration', 'durationHuman',
|
||||
'playlistType', 'smart'
|
||||
'playlistType', 'smart',
|
||||
'items'
|
||||
],
|
||||
2: [
|
||||
],
|
||||
|
@ -1459,6 +1447,8 @@ class Export(object):
|
|||
msg = "Export called with invalid media_info_level '{}'.".format(self.media_info_level)
|
||||
elif self.file_format not in self.FILE_FORMATS:
|
||||
msg = "Export called with invalid file_format '{}'.".format(self.file_format)
|
||||
elif self.library_export not in self.LIBRARY_EXPORTS:
|
||||
msg = "Export called with invalid library_export '{}'.".format(self.library_export)
|
||||
|
||||
if msg:
|
||||
logger.error("Tautulli Exporter :: %s", msg)
|
||||
|
@ -1494,12 +1484,17 @@ class Export(object):
|
|||
elif self.section_id:
|
||||
logger.debug(
|
||||
"Tautulli Exporter :: Export called with section_id %s, "
|
||||
"metadata_level %d, media_info_level %d, include_thumb %s, include_art %s",
|
||||
"metadata_level %d, media_info_level %d, include_thumb %s, include_art %s, "
|
||||
"library_export %s",
|
||||
self.section_id, self.metadata_level, self.media_info_level,
|
||||
self.include_thumb, self.include_art)
|
||||
self.include_thumb, self.include_art, self.library_export)
|
||||
|
||||
self.obj = plex.get_library(str(self.section_id))
|
||||
if self.library_export == 'all':
|
||||
self.media_type = self.obj.type
|
||||
else:
|
||||
self.media_type = self.library_export
|
||||
|
||||
library_title = self.obj.title
|
||||
|
||||
filename = 'Library - {} [{}].{}'.format(
|
||||
|
@ -1574,10 +1569,15 @@ class Export(object):
|
|||
filepath = get_export_filepath(self.filename)
|
||||
images_folder = get_export_filepath(self.filename, images=True)
|
||||
|
||||
if hasattr(self.obj, 'all'):
|
||||
items = self.obj.all()
|
||||
else:
|
||||
if self.rating_key:
|
||||
items = [self.obj]
|
||||
else:
|
||||
if self.library_export == 'collection':
|
||||
items = self.obj.collection()
|
||||
elif self.library_export == 'playlist':
|
||||
items = self.obj.playlist()
|
||||
else:
|
||||
items = self.obj.all()
|
||||
|
||||
pool = ThreadPool(processes=4)
|
||||
|
||||
|
@ -1910,11 +1910,21 @@ def get_custom_fields(media_type, sub_media_type=None):
|
|||
|
||||
if media_type not in export.MEDIA_TYPES:
|
||||
return custom_fields
|
||||
elif media_type in ('collection', 'playlist') and sub_media_type not in export.MEDIA_TYPES:
|
||||
elif media_type == 'collection' and sub_media_type not in ('movie', 'show', 'artist', 'album', 'photoalbum'):
|
||||
return custom_fields
|
||||
elif media_type == 'playlist' and sub_media_type not in ('video', 'audio', 'photo'):
|
||||
return custom_fields
|
||||
|
||||
if media_type == 'playlist' and sub_media_type == 'video':
|
||||
sub_media_types = ['movie', 'episode']
|
||||
elif media_type == 'playlist' and sub_media_type == 'audio':
|
||||
sub_media_types = ['track']
|
||||
else:
|
||||
sub_media_types = [sub_media_type]
|
||||
|
||||
metadata_levels_map, media_info_levels_map = export.return_attrs_level_map(media_type)
|
||||
|
||||
for sub_media_type in sub_media_types:
|
||||
prefix = ''
|
||||
child_media_type = export.CHILD_MEDIA_TYPES[media_type]
|
||||
|
||||
|
|
|
@ -6557,13 +6557,14 @@ class WebInterface(object):
|
|||
@cherrypy.expose
|
||||
@requireAuth(member_of("admin"))
|
||||
def export_metadata_modal(self, section_id=None, rating_key=None,
|
||||
media_type=None, sub_media_type=None, **kwargs):
|
||||
media_type=None, sub_media_type=None,
|
||||
library_export=None, **kwargs):
|
||||
file_formats = exporter.Export.FILE_FORMATS
|
||||
|
||||
return serve_template(templatename="export_modal.html", title="Export Metadata",
|
||||
section_id=section_id, rating_key=rating_key,
|
||||
media_type=media_type, sub_media_type=sub_media_type,
|
||||
file_formats=file_formats)
|
||||
library_export=library_export, file_formats=file_formats)
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
|
@ -6577,7 +6578,9 @@ class WebInterface(object):
|
|||
media_type (str): The media type of the fields to return
|
||||
|
||||
Optional parameters:
|
||||
sub_media_type (str): The child media type for collections or playlists
|
||||
sub_media_type (str): The child media type for
|
||||
collections (movie, show, artist, album, photoalbum),
|
||||
or playlists (video, audio, photo)
|
||||
|
||||
Returns:
|
||||
json:
|
||||
|
@ -6604,12 +6607,12 @@ class WebInterface(object):
|
|||
def export_metadata(self, section_id=None, rating_key=None, file_format='csv',
|
||||
metadata_level=1, media_info_level=1,
|
||||
include_thumb=False, include_art=False,
|
||||
custom_fields='', **kwargs):
|
||||
custom_fields='', library_export=None, **kwargs):
|
||||
""" Export library or media metadata to a file
|
||||
|
||||
```
|
||||
Required parameters:
|
||||
section_id (int): The section id of the library to export, OR
|
||||
section_id (int): The section id of the library items to export, OR
|
||||
rating_key (int): The rating key of the media item to export
|
||||
|
||||
Optional parameters:
|
||||
|
@ -6620,6 +6623,8 @@ class WebInterface(object):
|
|||
include_art (bool): True to export background artwork images
|
||||
custom_fields (str): Comma separated list of custom fields to export
|
||||
in addition to the export level selected
|
||||
library_export (str): collection or playlist for library export,
|
||||
otherwise default to all library items
|
||||
|
||||
Returns:
|
||||
json:
|
||||
|
@ -6635,7 +6640,8 @@ class WebInterface(object):
|
|||
media_info_level=media_info_level,
|
||||
include_thumb=helpers.bool_true(include_thumb),
|
||||
include_art=helpers.bool_true(include_art),
|
||||
custom_fields=custom_fields).export()
|
||||
custom_fields=custom_fields,
|
||||
library_export=library_export).export()
|
||||
|
||||
if result is True:
|
||||
return {'result': 'success', 'message': 'Metadata export has started.'}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue