diff --git a/data/interfaces/default/js/script.js b/data/interfaces/default/js/script.js index 68259f6d..4cb6f5e9 100644 --- a/data/interfaces/default/js/script.js +++ b/data/interfaces/default/js/script.js @@ -336,6 +336,18 @@ String.prototype.toProperCase = function () { }); }; +function getPercent(value1, value2) { + value1 = parseFloat(value1) | 0 + value2 = parseFloat(value2) | 0 + + var percent = 0; + if (value1 !== 0 && value2 !== 0) { + percent = (value1 / value2) * 100 + } + + return Math.round(percent) +} + function millisecondsToMinutes(ms, roundToMinute) { if (ms > 0) { var minutes = Math.floor(ms / 60000); diff --git a/data/interfaces/default/js/tables/export_table.js b/data/interfaces/default/js/tables/export_table.js index c7e172be..ce717c78 100644 --- a/data/interfaces/default/js/tables/export_table.js +++ b/data/interfaces/default/js/tables/export_table.js @@ -167,7 +167,8 @@ export_table_options = { var icon = (rowData['thumb_level'] || rowData['art_level'] || rowData['individual_files']) ? 'fa-file-archive' : 'fa-file-download'; $(td).html(''); } else if (cellData === 0) { - $(td).html(' Processing'); + var percent = Math.min(getPercent(rowData['exported_items'], rowData['total_items']), 99) + $(td).html(' ' + percent + '%'); } else if (cellData === -1) { $(td).html(' Failed'); } else { diff --git a/plexpy/__init__.py b/plexpy/__init__.py index cae59fd7..032cd750 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -802,7 +802,8 @@ def dbcheck(): 'metadata_level INTEGER, media_info_level INTEGER, ' 'thumb_level INTEGER DEFAULT 0, art_level INTEGER DEFAULT 0, ' 'custom_fields TEXT, individual_files INTEGER DEFAULT 0, ' - 'file_size INTEGER DEFAULT 0, complete INTEGER DEFAULT 0)' + 'file_size INTEGER DEFAULT 0, complete INTEGER DEFAULT 0, ' + 'exported_items INTEGER DEFAULT 0, total_items INTEGER DEFAULT 0)' ) # Upgrade sessions table from earlier versions @@ -2191,6 +2192,18 @@ def dbcheck(): 'ALTER TABLE exports ADD COLUMN individual_files INTEGER DEFAULT 0' ) + # Upgrade exports table from earlier versions + try: + c_db.execute('SELECT total_items FROM exports') + except sqlite3.OperationalError: + logger.debug("Altering database. Updating database table exports.") + c_db.execute( + 'ALTER TABLE exports ADD COLUMN exported_items INTEGER DEFAULT 0' + ) + c_db.execute( + 'ALTER TABLE exports ADD COLUMN total_items INTEGER DEFAULT 0' + ) + # Add "Local" user to database as default unauthenticated user. result = c_db.execute('SELECT id FROM users WHERE username = "Local"') if not result.fetchone(): diff --git a/plexpy/exporter.py b/plexpy/exporter.py index f44e179e..b20d96d5 100644 --- a/plexpy/exporter.py +++ b/plexpy/exporter.py @@ -112,7 +112,7 @@ class Export(object): self.art_level = helpers.cast_to_int(art_level) self.custom_fields = custom_fields.replace(' ', '') self._custom_fields = {} - self.export_type = str(export_type).lower() + self.export_type = str(export_type).lower() or 'all' self.individual_files = individual_files self.timestamp = helpers.timestamp() @@ -129,8 +129,8 @@ class Export(object): self.exported_thumb = False self.exported_art = False - self._total_items = 0 - self._exported_items = 0 + self.total_items = 0 + self.exported_items = 0 self.success = False # Reset export options for m3u8 @@ -1651,6 +1651,18 @@ class Export(object): db = database.MonitorDatabase() db.upsert(table_name='exports', key_dict=keys, value_dict=values) + def set_export_progress(self): + keys = { + 'id': self.export_id + } + values = { + 'total_items': self.total_items, + 'exported_items': self.exported_items + } + + db = database.MonitorDatabase() + db.upsert(table_name='exports', key_dict=keys, value_dict=values) + def _real_export(self): logger.info("Tautulli Exporter :: Starting export for '%s'...", self.title) @@ -1663,8 +1675,8 @@ class Export(object): method = getattr(self.obj, self.export_type) items = method() - self._total_items = len(items) - logger.info("Tautulli Exporter :: Exporting %d item(s).", self._total_items) + self.total_items = len(items) + logger.info("Tautulli Exporter :: Exporting %d item(s).", self.total_items) pool = ThreadPool(processes=plexpy.CONFIG.EXPORT_THREADS) items = [ExportObject(self, item) for item in items] @@ -1701,7 +1713,8 @@ class Export(object): def _do_export(self, item): result = item._export_obj() - self._exported_items += 1 + self.exported_items += 1 + self.set_export_progress() return result def _save_file(self, result, obj=None): @@ -2117,7 +2130,9 @@ def get_export_datatable(section_id=None, user_id=None, rating_key=None, kwargs= 'exports.custom_fields', 'exports.individual_files', 'exports.file_size', - 'exports.complete' + 'exports.complete', + 'exports.total_items', + 'exports.exported_items' ] try: query = data_tables.ssp_query(table_name='exports', @@ -2161,6 +2176,8 @@ def get_export_datatable(section_id=None, user_id=None, rating_key=None, kwargs= 'individual_files': item['individual_files'], 'file_size': item['file_size'], 'complete': item['complete'], + 'exported_items': item['exported_items'], + 'total_items': item['total_items'], 'exists': exists } diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 542f243c..724f0596 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -6556,14 +6556,27 @@ class WebInterface(object): "recordsTotal": 10, "recordsFiltered": 3, "data": - [{"row_id": 2, - "timestamp": 1596484600, + [{"timestamp": 1602823644, + "art_level": 0, + "complete": 1, + "custom_fields": "", + "exists": true, + "export_id": 42, + "exported_items": 28, + "file_format": "json", + "file_size": 57793562, + "filename": null, + "individual_files": 1, + "media_info_level": 1, + "media_type": "collection", + "media_type_title": "Collection", + "metadata_level": 1, + "rating_key": null, "section_id": 1, - "rating_key": 270716, - "media_type": "movie", - "media_type_title": "Movie", - "filename": "Movie - Frozen II [270716].20200803125640.json", - "complete": 1 + "thumb_level": 2, + "title": "Library - Movies - Collection [1]", + "total_items": 28, + "user_id": null }, {...}, {...}