From 523e6421bea688a1185fd453e122220b7aa51779 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 12 Apr 2020 20:49:45 -0700 Subject: [PATCH 1/4] Don't delete library history if server_id doesn't match --- plexpy/database.py | 39 +++++++++++++++++++++++---------------- plexpy/libraries.py | 13 ++++++++++--- plexpy/users.py | 7 ++++--- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/plexpy/database.py b/plexpy/database.py index 19d0b6e9..8eb6f7ce 100644 --- a/plexpy/database.py +++ b/plexpy/database.py @@ -62,18 +62,26 @@ def delete_rows_from_table(table, row_ids): if row_ids and isinstance(row_ids, basestring): row_ids = map(helpers.cast_to_int, row_ids.split(',')) - logger.info(u"Tautulli Database :: Deleting row ids %s from %s database table", row_ids, table) - query = "DELETE FROM " + table + " WHERE id IN (%s) " % ','.join(['?'] * len(row_ids)) - monitor_db = MonitorDatabase() - monitor_db.action(query, row_ids) + if row_ids: + logger.info(u"Tautulli Database :: Deleting row ids %s from %s database table", row_ids, table) + query = "DELETE FROM " + table + " WHERE id IN (%s) " % ','.join(['?'] * len(row_ids)) + monitor_db = MonitorDatabase() + + try: + monitor_db.action(query, row_ids) + return True + except Exception as e: + logger.error(u"Tautulli Database :: Failed to delete rows from %s database table: %s" % (table, row_ids)) + return False + + return True def delete_session_history_rows(row_ids=None): - if row_ids: - for table in ('session_history', 'session_history_media_info', 'session_history_metadata'): - delete_rows_from_table(table=table, row_ids=row_ids) - return True - return False + success = [] + for table in ('session_history', 'session_history_media_info', 'session_history_metadata'): + success.append(delete_rows_from_table(table=table, row_ids=row_ids)) + return all(success) def delete_user_history(user_id=None): @@ -89,19 +97,18 @@ def delete_user_history(user_id=None): return delete_session_history_rows(row_ids=row_ids) -def delete_library_history(server_id=None, section_id=None): - if server_id and str(section_id).isdigit(): +def delete_library_history(section_id=None): + if str(section_id).isdigit(): monitor_db = MonitorDatabase() - # Get all history associated with the server_id and section_id + # Get all history associated with the section_id result = monitor_db.select('SELECT session_history.id FROM session_history ' 'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' - 'WHERE session_history.server_id = ? AND session_history_metadata.section_id = ?', - [server_id, section_id]) + 'WHERE session_history_metadata.section_id = ?', + [section_id]) row_ids = [row['id'] for row in result] - logger.info(u"Tautulli Database :: Deleting all history for library server_id %s and section_id %s from database." - % (server_id, section_id)) + logger.info(u"Tautulli Database :: Deleting all history for library section_id %s from database." % section_id) return delete_session_history_rows(row_ids=row_ids) diff --git a/plexpy/libraries.py b/plexpy/libraries.py index 1a063f5d..abda93be 100644 --- a/plexpy/libraries.py +++ b/plexpy/libraries.py @@ -1042,9 +1042,16 @@ class Libraries(object): elif str(section_id).isdigit(): server_id = server_id or plexpy.CONFIG.PMS_IDENTIFIER - database.delete_library_history(server_id=server_id, section_id=section_id) + if server_id == plexpy.CONFIG.PMS_IDENTIFIER: + delete_success = database.delete_library_history(section_id=section_id) + else: + logger.warn(u"Tautulli Libraries :: Library history not deleted for library section_id %s " + u"because library server_id %s does not match Plex server identifier %s." + % (section_id, server_id, plexpy.CONFIG.PMS_IDENTIFIER)) + delete_success = True + if purge_only: - return True + return delete_success else: logger.info(u"Tautulli Libraries :: Deleting library with server_id %s and section_id %s from database." % (server_id, section_id)) @@ -1052,7 +1059,7 @@ class Libraries(object): monitor_db.action('UPDATE library_sections ' 'SET deleted_section = 1, keep_history = 0, do_notify = 0, do_notify_created = 0 ' 'WHERE server_id = ? AND section_id = ?', [server_id, section_id]) - return True + return delete_success except Exception as e: logger.warn(u"Tautulli Libraries :: Unable to execute database query for delete: %s." % e) diff --git a/plexpy/users.py b/plexpy/users.py index 51fa6903..0c4df0f6 100644 --- a/plexpy/users.py +++ b/plexpy/users.py @@ -681,9 +681,10 @@ class Users(object): return all(success) elif str(user_id).isdigit(): - database.delete_user_history(user_id=user_id) + delete_success = database.delete_user_history(user_id=user_id) + if purge_only: - return True + return delete_success else: logger.info(u"Tautulli Users :: Deleting user with user_id %s from database." % user_id) @@ -691,7 +692,7 @@ class Users(object): monitor_db.action('UPDATE users ' 'SET deleted_user = 1, keep_history = 0, do_notify = 0 ' 'WHERE user_id = ?', [user_id]) - return True + return delete_success except Exception as e: logger.warn(u"Tautulli Users :: Unable to execute database query for delete: %s." % e) From b7d03a4f31ac557dacc262a4b3a9f18f202857d1 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 12 Apr 2020 20:51:22 -0700 Subject: [PATCH 2/4] Fix refreshing libraries and users table after deleting --- data/interfaces/default/libraries.html | 25 +++++++++++++------------ data/interfaces/default/users.html | 25 +++++++++++++------------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/data/interfaces/default/libraries.html b/data/interfaces/default/libraries.html index f4983904..d7360bf3 100644 --- a/data/interfaces/default/libraries.html +++ b/data/interfaces/default/libraries.html @@ -131,17 +131,6 @@ $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - $.ajax({ - url: 'delete_library', - type: 'POST', - data: { row_ids: libraries_to_delete.join(',') }, - cache: false, - async: true, - success: function (data) { - var msg = "Library deleted"; - showMsg(msg, false, true, 2000); - } - }); $.ajax({ url: 'delete_all_library_history', type: 'POST', @@ -151,9 +140,21 @@ success: function (data) { var msg = "Library history purged"; showMsg(msg, false, true, 2000); + libraries_list_table.draw(); + } + }); + $.ajax({ + url: 'delete_library', + type: 'POST', + data: { row_ids: libraries_to_delete.join(',') }, + cache: false, + async: true, + success: function (data) { + var msg = "Library deleted"; + showMsg(msg, false, true, 2000); + libraries_list_table.draw(); } }); - libraries_list_table.draw(); }); } diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html index f3595148..4d471d03 100644 --- a/data/interfaces/default/users.html +++ b/data/interfaces/default/users.html @@ -134,17 +134,6 @@ $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - $.ajax({ - url: 'delete_user', - type: 'POST', - data: { row_ids: users_to_delete.join(',') }, - cache: false, - async: true, - success: function (data) { - var msg = "User deleted"; - showMsg(msg, false, true, 2000); - } - }); $.ajax({ url: 'delete_all_user_history', type: 'POST', @@ -154,9 +143,21 @@ success: function (data) { var msg = "User history purged"; showMsg(msg, false, true, 2000); + users_list_table.draw(); + } + }); + $.ajax({ + url: 'delete_user', + type: 'POST', + data: { row_ids: users_to_delete.join(',') }, + cache: false, + async: true, + success: function (data) { + var msg = "User deleted"; + showMsg(msg, false, true, 2000); + users_list_table.draw(); } }); - users_list_table.draw(); }); } From 400a189455e8df374a41148b0264bd04e93294a6 Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 12 Apr 2020 21:20:14 -0700 Subject: [PATCH 3/4] Invalidate temporary mobile app token after 5 minutes --- plexpy/api2.py | 4 ++-- plexpy/mobile_app.py | 19 +++++++++++++++++++ plexpy/webserve.py | 6 +++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plexpy/api2.py b/plexpy/api2.py index eb3ced99..4b561774 100644 --- a/plexpy/api2.py +++ b/plexpy/api2.py @@ -120,7 +120,7 @@ class API2: self._api_app = True if plexpy.CONFIG.API_ENABLED and not self._api_msg or self._api_cmd in ('get_apikey', 'docs', 'docs_md'): - if self._api_apikey == plexpy.CONFIG.API_KEY or (self._api_app and self._api_apikey == mobile_app.TEMP_DEVICE_TOKEN): + if self._api_apikey == plexpy.CONFIG.API_KEY or (self._api_app and self._api_apikey == mobile_app.get_temp_device_token()): self._api_authenticated = True elif self._api_app and mobile_app.get_mobile_device_by_token(self._api_apikey): @@ -404,7 +404,7 @@ class API2: if result: self._api_msg = 'Device registration successful.' self._api_result_type = 'success' - mobile_app.TEMP_DEVICE_TOKEN = None + mobile_app.set_temp_device_token(None) else: self._api_msg = 'Device registartion failed: database error.' self._api_result_type = 'error' diff --git a/plexpy/mobile_app.py b/plexpy/mobile_app.py index af565cac..38c6d2b7 100644 --- a/plexpy/mobile_app.py +++ b/plexpy/mobile_app.py @@ -14,6 +14,7 @@ # along with Tautulli. If not, see . import time +import threading import plexpy import database @@ -22,6 +23,24 @@ import logger TEMP_DEVICE_TOKEN = None +INVALIDATE_TIMER = None + + +def set_temp_device_token(token=None): + global TEMP_DEVICE_TOKEN + TEMP_DEVICE_TOKEN = token + + if TEMP_DEVICE_TOKEN is not None: + global INVALIDATE_TIMER + if INVALIDATE_TIMER: + INVALIDATE_TIMER.cancel() + invalidate_time = 5 * 60 # 5 minutes + INVALIDATE_TIMER = threading.Timer(invalidate_time, set_temp_device_token, args=[None]) + INVALIDATE_TIMER.start() + + +def get_temp_device_token(): + return TEMP_DEVICE_TOKEN def get_mobile_devices(device_id=None, device_token=None): diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 7389ceaa..adce6be2 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -3587,12 +3587,12 @@ class WebInterface(object): @requireAuth(member_of("admin")) def verify_mobile_device(self, device_token='', cancel=False, **kwargs): if helpers.bool_true(cancel): - mobile_app.TEMP_DEVICE_TOKEN = None + mobile_app.set_temp_device_token(None) return {'result': 'error', 'message': 'Device registration cancelled.'} result = mobile_app.get_mobile_device_by_token(device_token) if result: - mobile_app.TEMP_DEVICE_TOKEN = None + mobile_app.set_temp_device_token(None) return {'result': 'success', 'message': 'Device registered successfully.', 'data': result} else: return {'result': 'error', 'message': 'Device not registered.'} @@ -3879,7 +3879,7 @@ class WebInterface(object): logger._BLACKLIST_WORDS.add(apikey) if helpers.bool_true(device): - mobile_app.TEMP_DEVICE_TOKEN = apikey + mobile_app.set_temp_device_token(apikey) return apikey From 6d5c3207011e221b8b6aa915c333f08d375c800b Mon Sep 17 00:00:00 2001 From: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> Date: Sun, 12 Apr 2020 21:27:01 -0700 Subject: [PATCH 4/4] v2.2.2-beta --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ plexpy/version.py | 4 ++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49b37825..625cca89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## v2.2.2-beta (2020-04-12) + +* Notifications: + * New: Added notification trigger for Tautulli database corruption. + * New: Added TAUTULLI_PYTHON_VERSION to script notification environment variables. + * Fix: Notification grouping by season/album and show/artist not enabled by default. + * Change: The file size notification parameter is now reported in SI units. (Thanks @aaronldunlap) +* UI: + * Fix: Delete lookup info from the media info page failing. + * New: Added icon on the users table to indicate if the user is not on the Plex server. + * New: Added icon on the libraries table to indicate if the library is not on the Plex server. + * Fix: XBMC platform icon not being redirected to the Kodi platform icon. + * Change: Improved deleting libraries so libraries with the same section ID are not also deleted. +* API: + * Fix: Returning XML for the API failing due to unicode characters. + * Fix: Grouping parameter for various API commands not falling back to default setting. + * New: Added time_queries parameter to get_library_watch_time_stats and get_user_watch_time_stats API command. (Thanks @KaasKop97) + * New: Added an "is_active" return value to the get_user, get_users, get_library, and get_libraries API commands which indicates if the user or library is on the Plex server. + * New: Added delete_history API command. + * Change: Added optional parameter for row_ids for delete_library, delete_user, delete_all_library_history, and delete_all_user_history API commands. +* Mobile App: + * Fix: Temporary device token not being invalidated after cancelling device registration. +* Other: + * Fix: Update failing on CentOS due to an older git version. + * Fix: Manifest file for creating a web app had incorrect info. + * New: Docker images updated to support ARM platforms. + + ## v2.2.1 (2020-03-28) * Notifications: diff --git a/plexpy/version.py b/plexpy/version.py index 01a5ad0b..a01a016d 100644 --- a/plexpy/version.py +++ b/plexpy/version.py @@ -1,2 +1,2 @@ -PLEXPY_BRANCH = "master" -PLEXPY_RELEASE_VERSION = "v2.2.1" +PLEXPY_BRANCH = "beta" +PLEXPY_RELEASE_VERSION = "v2.2.2-beta"