Merge branch 'nightly' into python3

# Conflicts:
#	plexpy/database.py
#	plexpy/version.py
This commit is contained in:
JonnyWong16 2020-04-12 21:35:29 -07:00
commit 3ca4351aeb
No known key found for this signature in database
GPG key ID: B1F1F9807184697A
10 changed files with 116 additions and 53 deletions

View file

@ -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:

View file

@ -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();
}
});
});
}

View file

@ -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();
}
});
});
}

View file

@ -136,7 +136,7 @@ class API2(object):
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):
@ -420,7 +420,7 @@ class API2(object):
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'

View file

@ -70,18 +70,26 @@ def delete_rows_from_table(table, row_ids):
if row_ids and isinstance(row_ids, str):
row_ids = list(map(cast_to_int, row_ids.split(',')))
if row_ids:
logger.info("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("Tautulli Database :: Failed to delete rows from %s database table: %s" % (table, e))
return False
return True
def delete_session_history_rows(row_ids=None):
if row_ids:
success = []
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.append(delete_rows_from_table(table=table, row_ids=row_ids))
return all(success)
def delete_user_history(user_id=None):
@ -97,19 +105,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("Tautulli Database :: Deleting all history for library server_id %s and section_id %s from database."
% (server_id, section_id))
logger.info("Tautulli Database :: Deleting all history for library section_id %s from database." % section_id)
return delete_session_history_rows(row_ids=row_ids)

View file

@ -1058,9 +1058,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("Tautulli Libraries :: Library history not deleted for library section_id %s "
"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("Tautulli Libraries :: Deleting library with server_id %s and section_id %s from database."
% (server_id, section_id))
@ -1068,7 +1075,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("Tautulli Libraries :: Unable to execute database query for delete: %s." % e)

View file

@ -18,7 +18,7 @@
from __future__ import unicode_literals
from future.builtins import str
import time
import threading
import plexpy
if plexpy.PYTHON2:
@ -32,6 +32,24 @@ else:
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):

View file

@ -698,9 +698,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("Tautulli Users :: Deleting user with user_id %s from database."
% user_id)
@ -708,7 +709,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("Tautulli Users :: Unable to execute database query for delete: %s." % e)

View file

@ -18,4 +18,4 @@
from __future__ import unicode_literals
PLEXPY_BRANCH = "python3"
PLEXPY_RELEASE_VERSION = "v2.2.1"
PLEXPY_RELEASE_VERSION = "v2.2.2-beta"

View file

@ -3674,12 +3674,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.'}
@ -3966,7 +3966,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