mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-14 09:12:58 -07:00
Add zip file download for export with images
This commit is contained in:
parent
b1eab8bb0d
commit
068cb51635
2 changed files with 51 additions and 23 deletions
|
@ -69,7 +69,6 @@ class Export(object):
|
||||||
self.items = []
|
self.items = []
|
||||||
|
|
||||||
self.filename = None
|
self.filename = None
|
||||||
self.filename_ext = None
|
|
||||||
self.export_id = None
|
self.export_id = None
|
||||||
self.file_size = None
|
self.file_size = None
|
||||||
self.success = False
|
self.success = False
|
||||||
|
@ -1205,8 +1204,9 @@ class Export(object):
|
||||||
|
|
||||||
if self.rating_key:
|
if self.rating_key:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Tautulli Exporter :: Export called with rating_key %s, metadata_level %d, media_info_level %d",
|
"Tautulli Exporter :: Export called with rating_key %s, "
|
||||||
self.rating_key, self.metadata_level, self.media_info_level)
|
"metadata_level %d, media_info_level %d, include_images %s",
|
||||||
|
self.rating_key, self.metadata_level, self.media_info_level, self.include_images)
|
||||||
|
|
||||||
item = plex.get_item(self.rating_key)
|
item = plex.get_item(self.rating_key)
|
||||||
self.media_type = item.type
|
self.media_type = item.type
|
||||||
|
@ -1290,8 +1290,7 @@ class Export(object):
|
||||||
|
|
||||||
export_attrs = reduce(helpers.dict_merge, export_attrs_list)
|
export_attrs = reduce(helpers.dict_merge, export_attrs_list)
|
||||||
|
|
||||||
self.filename = helpers.clean_filename(filename)
|
self.filename = '{}.{}'.format(helpers.clean_filename(filename), self.file_format)
|
||||||
self.filename_ext = '{}.{}'.format(self.filename, self.file_format)
|
|
||||||
|
|
||||||
self.export_id = self.add_export()
|
self.export_id = self.add_export()
|
||||||
|
|
||||||
|
@ -1305,9 +1304,9 @@ class Export(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _real_export(self, attrs):
|
def _real_export(self, attrs):
|
||||||
logger.info("Tautulli Exporter :: Starting export for '%s'...", self.filename_ext)
|
logger.info("Tautulli Exporter :: Starting export for '%s'...", self.filename)
|
||||||
|
|
||||||
filepath = get_export_filepath(self.filename_ext)
|
filepath = get_export_filepath(self.filename)
|
||||||
|
|
||||||
part = partial(helpers.get_attrs_to_dict, attrs=attrs)
|
part = partial(helpers.get_attrs_to_dict, attrs=attrs)
|
||||||
pool = ThreadPool(processes=4)
|
pool = ThreadPool(processes=4)
|
||||||
|
@ -1331,7 +1330,7 @@ class Export(object):
|
||||||
self.file_size = os.path.getsize(filepath)
|
self.file_size = os.path.getsize(filepath)
|
||||||
|
|
||||||
if self.include_images:
|
if self.include_images:
|
||||||
images_folder = get_export_filepath('{}.images'.format(self.filename))
|
images_folder = get_export_filepath(self.filename, images=True)
|
||||||
for f in os.listdir(images_folder):
|
for f in os.listdir(images_folder):
|
||||||
image_path = os.path.join(images_folder, f)
|
image_path = os.path.join(images_folder, f)
|
||||||
if os.path.isfile(image_path):
|
if os.path.isfile(image_path):
|
||||||
|
@ -1341,7 +1340,7 @@ class Export(object):
|
||||||
logger.info("Tautulli Exporter :: Successfully exported to '%s'", filepath)
|
logger.info("Tautulli Exporter :: Successfully exported to '%s'", filepath)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Tautulli Exporter :: Failed to export '%s': %s", self.filename_ext, e)
|
logger.error("Tautulli Exporter :: Failed to export '%s': %s", self.filename, e)
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
@ -1357,7 +1356,7 @@ class Export(object):
|
||||||
'media_type': self.media_type}
|
'media_type': self.media_type}
|
||||||
|
|
||||||
values = {'file_format': self.file_format,
|
values = {'file_format': self.file_format,
|
||||||
'filename': self.filename_ext,
|
'filename': self.filename,
|
||||||
'include_images': self.include_images}
|
'include_images': self.include_images}
|
||||||
|
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
@ -1397,8 +1396,10 @@ def get_image(item, image, export_filename):
|
||||||
else:
|
else:
|
||||||
item_title = item.title
|
item_title = item.title
|
||||||
|
|
||||||
folder = get_export_filepath('{}.images'.format(export_filename))
|
folder = get_export_filepath(export_filename, images=True)
|
||||||
filepath = os.path.join(folder, '{} [{}].{}.jpg'.format(item_title, rating_key, image))
|
filename = helpers.clean_filename('{} [{}].{}.jpg'.format(item_title, rating_key, image))
|
||||||
|
filepath = os.path.join(folder, filename)
|
||||||
|
|
||||||
if not os.path.exists(folder):
|
if not os.path.exists(folder):
|
||||||
os.makedirs(folder)
|
os.makedirs(folder)
|
||||||
|
|
||||||
|
@ -1422,7 +1423,7 @@ def get_image(item, image, export_filename):
|
||||||
|
|
||||||
def get_export(export_id):
|
def get_export(export_id):
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = db.select_single('SELECT filename, file_format, complete '
|
result = db.select_single('SELECT filename, file_format, include_images, complete '
|
||||||
'FROM exports WHERE id = ?',
|
'FROM exports WHERE id = ?',
|
||||||
[export_id])
|
[export_id])
|
||||||
|
|
||||||
|
@ -1445,9 +1446,10 @@ def delete_export(export_id):
|
||||||
logger.info("Tautulli Exporter :: Deleting exported file from '%s'.", filepath)
|
logger.info("Tautulli Exporter :: Deleting exported file from '%s'.", filepath)
|
||||||
try:
|
try:
|
||||||
os.remove(filepath)
|
os.remove(filepath)
|
||||||
folder = '{}.images'.format(os.path.splitext(filepath)[0])
|
if export_data['include_images']:
|
||||||
if os.path.exists(folder):
|
images_folder = get_export_filepath(export_data['filename'], images=True)
|
||||||
shutil.rmtree(folder)
|
if os.path.exists(images_folder):
|
||||||
|
shutil.rmtree(images_folder)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error("Tautulli Exporter :: Failed to delete exported file '%s': %s", filepath, e)
|
logger.error("Tautulli Exporter :: Failed to delete exported file '%s': %s", filepath, e)
|
||||||
return True
|
return True
|
||||||
|
@ -1457,7 +1459,7 @@ def delete_export(export_id):
|
||||||
|
|
||||||
def delete_all_exports():
|
def delete_all_exports():
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
result = db.select('SELECT filename FROM exports')
|
result = db.select('SELECT filename, include_images FROM exports')
|
||||||
|
|
||||||
logger.info("Tautulli Exporter :: Deleting all exports from the database.")
|
logger.info("Tautulli Exporter :: Deleting all exports from the database.")
|
||||||
|
|
||||||
|
@ -1467,9 +1469,10 @@ def delete_all_exports():
|
||||||
filepath = get_export_filepath(row['filename'])
|
filepath = get_export_filepath(row['filename'])
|
||||||
try:
|
try:
|
||||||
os.remove(filepath)
|
os.remove(filepath)
|
||||||
folder = '{}.images'.format(os.path.splitext(filepath)[0])
|
if row['include_images']:
|
||||||
if os.path.exists(folder):
|
images_folder = get_export_filepath(row['filename'], images=True)
|
||||||
shutil.rmtree(folder)
|
if os.path.exists(images_folder):
|
||||||
|
shutil.rmtree(images_folder)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error("Tautulli Exporter :: Failed to delete exported file '%s': %s", filepath, e)
|
logger.error("Tautulli Exporter :: Failed to delete exported file '%s': %s", filepath, e)
|
||||||
deleted_files = False
|
deleted_files = False
|
||||||
|
@ -1556,7 +1559,10 @@ def get_export_datatable(section_id=None, rating_key=None, kwargs=None):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def get_export_filepath(filename):
|
def get_export_filepath(filename, images=False):
|
||||||
|
if images:
|
||||||
|
images_folder = '{}.images'.format(os.path.splitext(filename)[0])
|
||||||
|
return os.path.join(plexpy.CONFIG.EXPORT_DIR, images_folder)
|
||||||
return os.path.join(plexpy.CONFIG.EXPORT_DIR, filename)
|
return os.path.join(plexpy.CONFIG.EXPORT_DIR, filename)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ from future.builtins import object
|
||||||
from future.builtins import str
|
from future.builtins import str
|
||||||
from backports import csv
|
from backports import csv
|
||||||
|
|
||||||
from io import open
|
from io import open, BytesIO
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import linecache
|
import linecache
|
||||||
|
@ -29,10 +29,11 @@ import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
import zipfile
|
||||||
from future.moves.urllib.parse import urlencode
|
from future.moves.urllib.parse import urlencode
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from cherrypy.lib.static import serve_file, serve_download
|
from cherrypy.lib.static import serve_file, serve_fileobj, serve_download
|
||||||
from cherrypy._cperror import NotFound
|
from cherrypy._cperror import NotFound
|
||||||
|
|
||||||
from hashing_passwords import make_hash
|
from hashing_passwords import make_hash
|
||||||
|
@ -6594,6 +6595,27 @@ class WebInterface(object):
|
||||||
result = exporter.get_export(export_id=export_id)
|
result = exporter.get_export(export_id=export_id)
|
||||||
|
|
||||||
if result and result['complete'] == 1 and result['exists']:
|
if result and result['complete'] == 1 and result['exists']:
|
||||||
|
export_filepath = exporter.get_export_filepath(result['filename'])
|
||||||
|
|
||||||
|
if result['include_images']:
|
||||||
|
zip_filename = '{}.zip'.format(os.path.splitext(result['filename'])[0])
|
||||||
|
images_folder = exporter.get_export_filepath(result['filename'], images=True)
|
||||||
|
|
||||||
|
if os.path.exists(images_folder):
|
||||||
|
buffer = BytesIO()
|
||||||
|
temp_zip = zipfile.ZipFile(buffer, 'w')
|
||||||
|
temp_zip.write(export_filepath, arcname=result['filename'])
|
||||||
|
|
||||||
|
_images_folder = os.path.basename(images_folder)
|
||||||
|
|
||||||
|
for f in os.listdir(images_folder):
|
||||||
|
image_path = os.path.join(images_folder, f)
|
||||||
|
temp_zip.write(image_path, arcname=os.path.join(_images_folder, f))
|
||||||
|
|
||||||
|
temp_zip.close()
|
||||||
|
return serve_fileobj(buffer.getvalue(), content_type='application/zip',
|
||||||
|
disposition='attachment', name=zip_filename)
|
||||||
|
|
||||||
return serve_download(exporter.get_export_filepath(result['filename']), name=result['filename'])
|
return serve_download(exporter.get_export_filepath(result['filename']), name=result['filename'])
|
||||||
else:
|
else:
|
||||||
if result and result.get('complete') == 0:
|
if result and result.get('complete') == 0:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue