diff --git a/data/interfaces/default/history.html b/data/interfaces/default/history.html index a6929143..7bc6bb78 100644 --- a/data/interfaces/default/history.html +++ b/data/interfaces/default/history.html @@ -45,6 +45,9 @@ Music +
+ +
@@ -169,17 +172,18 @@ $('#deleteCount').text(history_to_delete.length); $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < history_to_delete.length; i++) { + history_to_delete.forEach(function(row, idx) { $.ajax({ url: 'delete_history_rows', - data: { row_id: history_to_delete[i] }, + type: 'POST', + data: { row_id: row }, async: true, success: function (data) { var msg = "History deleted"; showMsg(msg, false, true, 2000); } }); - } + }); history_table.draw(); }); } @@ -199,5 +203,9 @@ }); % endif }); + + $("#refresh-history-list").click(function() { + history_table.draw(); + }); diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index 9c156a79..f497aed1 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -392,6 +392,9 @@ DOCUMENTATION :: END % endif +
+ +
@@ -576,17 +579,18 @@ DOCUMENTATION :: END $('#deleteCount').text(history_to_delete.length); $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < history_to_delete.length; i++) { + history_to_delete.forEach(function (row, idx) { $.ajax({ url: 'delete_history_rows', - data: { row_id: history_to_delete[i] }, + type: 'POST', + data: { row_id: row }, async: true, success: function (data) { var msg = "History deleted"; showMsg(msg, false, true, 2000); } }); - } + }); history_table.draw(); }); } @@ -606,6 +610,10 @@ DOCUMENTATION :: END }); }); + $("#refresh-history-list").click(function () { + history_table.draw(); + }); + // Send recently added notification $('#send-recently-added-notification').on('click', function () { var rating_key = $(this).data('id'); diff --git a/data/interfaces/default/js/tables/sync_table.js b/data/interfaces/default/js/tables/sync_table.js index a39fd841..5e113944 100644 --- a/data/interfaces/default/js/tables/sync_table.js +++ b/data/interfaces/default/js/tables/sync_table.js @@ -1,3 +1,5 @@ +var syncs_to_delete = []; + sync_table_options = { "processing": false, "serverSide": false, @@ -19,6 +21,19 @@ sync_table_options = { "columnDefs": [ { "targets": [0], + "data": null, + "createdCell": function (td, cellData, rowData, row, col) { + $(td).html('
' + + ' ' + + '
'); + }, + "width": "7%", + "className": "delete-control no-wrap hidden", + "searchable": false, + "orderable": false + }, + { + "targets": [1], "data": "state", "createdCell": function (td, cellData, rowData, row, col) { if (cellData === 'pending') { @@ -31,7 +46,7 @@ sync_table_options = { "className": "no-wrap" }, { - "targets": [1], + "targets": [2], "data": "friendly_name", "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { @@ -47,7 +62,7 @@ sync_table_options = { "className": "no-wrap" }, { - "targets": [2], + "targets": [3], "data": "title", "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { @@ -61,7 +76,7 @@ sync_table_options = { "className": "datatable-wrap" }, { - "targets": [3], + "targets": [4], "data": "metadata_type", "render": function ( data, type, full ) { return data.toProperCase(); @@ -69,17 +84,17 @@ sync_table_options = { "className": "no-wrap" }, { - "targets": [4], + "targets": [5], "data": "platform", "className": "no-wrap" }, { - "targets": [5], + "targets": [6], "data": "device_name", "className": "no-wrap" }, { - "targets": [6], + "targets": [7], "data": "total_size", "createdCell": function (td, cellData, rowData, row, col) { if (cellData > 0 ) { @@ -92,22 +107,22 @@ sync_table_options = { "className": "no-wrap" }, { - "targets": [7], + "targets": [8], "data": "item_count", "className": "no-wrap" }, { - "targets": [8], + "targets": [9], "data": "item_complete_count", "className": "no-wrap" }, { - "targets": [9], + "targets": [10], "data": "item_downloaded_count", "className": "no-wrap" }, { - "targets": [10], + "targets": [11], "data": "item_downloaded_percent_complete", "createdCell": function (td, cellData, rowData, row, col) { if (rowData['item_count'] > 0 ) { @@ -130,3 +145,19 @@ sync_table_options = { showMsg(msg, false, false, 0) } } + +$('#sync_table').on('click', 'td.delete-control > .edit-sync-toggles > button.delete-sync', function () { + var tr = $(this).parents('tr'); + var row = sync_table.row(tr); + var rowData = row.data(); + + var index_delete = syncs_to_delete.findIndex(x => x.client_id == rowData['client_id'] && x.sync_id == rowData['sync_id']); + + if (index_delete === -1) { + syncs_to_delete.push({ client_id: rowData['client_id'], sync_id: rowData['sync_id'] }); + } else { + syncs_to_delete.splice(index_delete, 1); + } + + $(this).toggleClass('btn-warning').toggleClass('btn-danger'); +}); diff --git a/data/interfaces/default/libraries.html b/data/interfaces/default/libraries.html index c0a94e61..40143bf4 100644 --- a/data/interfaces/default/libraries.html +++ b/data/interfaces/default/libraries.html @@ -148,10 +148,11 @@ $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < libraries_to_delete.length; i++) { + libraries_to_delete.forEach(function(row, idx) { $.ajax({ url: 'delete_library', - data: { section_id: libraries_to_delete[i] }, + type: 'POST', + data: { section_id: row }, cache: false, async: true, success: function (data) { @@ -159,11 +160,12 @@ showMsg(msg, false, true, 2000); } }); - } - for (var i = 0; i < libraries_to_purge.length; i++) { + }); + libraries_to_purge.forEach(function(row, idx) { $.ajax({ url: 'delete_all_library_history', - data: { section_id: libraries_to_purge[i] }, + type: 'POST', + data: { section_id: row }, cache: false, async: true, success: function (data) { @@ -171,7 +173,7 @@ showMsg(msg, false, true, 2000); } }); - } + }); libraries_list_table.draw(); }); } diff --git a/data/interfaces/default/library.html b/data/interfaces/default/library.html index 5a6eeb9c..dda8f364 100644 --- a/data/interfaces/default/library.html +++ b/data/interfaces/default/library.html @@ -190,6 +190,9 @@ DOCUMENTATION :: END   % endif +
+ +
@@ -471,17 +474,18 @@ DOCUMENTATION :: END $('#deleteCount').text(history_to_delete.length); $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < history_to_delete.length; i++) { + history_to_delete.forEach(function(row, idx) { $.ajax({ url: 'delete_history_rows', - data: { row_id: history_to_delete[i] }, + type: 'POST', + data: { row_id: row }, async: true, success: function (data) { var msg = "History deleted"; showMsg(msg, false, true, 2000); } }); - } + }); history_table.draw(); }); } @@ -501,6 +505,10 @@ DOCUMENTATION :: END }); % endif + $("#refresh-history-list").click(function () { + history_table.draw(); + }); + function recentlyWatched() { // Populate recently watched $.ajax({ diff --git a/data/interfaces/default/sync.html b/data/interfaces/default/sync.html index 41d3ea1f..3ac38bfc 100644 --- a/data/interfaces/default/sync.html +++ b/data/interfaces/default/sync.html @@ -19,6 +19,17 @@ Synced Items
+ % if _session['user_group'] == 'admin': + +
+   +
+ % endif +
+ +
@@ -26,17 +37,18 @@ - - - - - - - - - - - + + + + + + + + + + + + @@ -47,6 +59,24 @@ <%def name="modalIncludes()"> + <%def name="javascriptIncludes()"> @@ -64,10 +94,57 @@ } } sync_table = $('#sync_table').DataTable(sync_table_options); - var colvis = new $.fn.dataTable.ColVis( sync_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark' } ); + var colvis = new $.fn.dataTable.ColVis( sync_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0] } ); $( colvis.button() ).appendTo('div.colvis-button-bar'); clearSearchButton('sync_table', sync_table); + + % if _session['user_group'] == 'admin': + $('#row-edit-mode').on('click', function() { + $('#row-edit-mode-alert').fadeIn(200); + + if ($(this).hasClass('active')) { + if (syncs_to_delete.length > 0) { + $('#deleteCount').text(syncs_to_delete.length); + $('#confirm-modal-delete').modal(); + $('#confirm-modal-delete').one('click', '#confirm-delete', function () { + syncs_to_delete.forEach(function(row, idx) { + $.ajax({ + url: 'delete_sync_rows', + type: 'POST', + data: { + client_id: row.client_id, + sync_id: row.sync_id + }, + async: true, + success: function (data) { + var msg = "Sync deleted"; + showMsg(msg, false, true, 2000); + } + }); + }); + sync_table.draw(); + }); + } + + $('.delete-control').each(function () { + $(this).addClass('hidden'); + $('#row-edit-mode-alert').fadeOut(200); + }); + + } else { + syncs_to_delete = []; + $('.delete-control').each(function() { + $(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger'); + $(this).removeClass('hidden'); + }); + } + }); + % endif + }); + + $("#refresh-syncs-list").click(function() { + sync_table.draw(); }); diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html index 979c1321..2e545596 100644 --- a/data/interfaces/default/user.html +++ b/data/interfaces/default/user.html @@ -169,6 +169,9 @@ DOCUMENTATION :: END Music +
+ +
@@ -517,17 +520,18 @@ DOCUMENTATION :: END $('#deleteCount').text(history_to_delete.length); $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < history_to_delete.length; i++) { + history_to_delete.forEach(function(row, idx) { $.ajax({ url: 'delete_history_rows', - data: { row_id: history_to_delete[i] }, + type: 'POST', + data: { row_id: row }, async: true, success: function (data) { var msg = "History deleted"; showMsg(msg, false, true, 2000); } }); - } + }); history_table.draw(); }); } @@ -547,6 +551,10 @@ DOCUMENTATION :: END }); % endif + $("#refresh-history-list").click(function () { + history_table.draw(); + }); + function recentlyWatched() { // Populate recently watched $.ajax({ diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html index 5f507fab..3f547f87 100644 --- a/data/interfaces/default/users.html +++ b/data/interfaces/default/users.html @@ -134,10 +134,11 @@ $('#confirm-modal-delete').modal(); $('#confirm-modal-delete').one('click', '#confirm-delete', function () { - for (var i = 0; i < users_to_delete.length; i++) { + users_to_delete.forEach(function(row, idx) { $.ajax({ url: 'delete_user', - data: { user_id: users_to_delete[i] }, + type: 'POST', + data: { user_id: row }, cache: false, async: true, success: function (data) { @@ -145,11 +146,12 @@ showMsg(msg, false, true, 2000); } }); - } - for (var i = 0; i < users_to_purge.length; i++) { + }); + users_to_purge.forEach(function(row, idx) { $.ajax({ url: 'delete_all_user_history', - data: { user_id: users_to_purge[i] }, + type: 'POST', + data: { user_id: row }, cache: false, async: true, success: function (data) { @@ -157,7 +159,7 @@ showMsg(msg, false, true, 2000); } }); - } + }); users_list_table.draw(); }); } diff --git a/plexpy/plextv.py b/plexpy/plextv.py index 03de5b31..26cdcc77 100644 --- a/plexpy/plextv.py +++ b/plexpy/plextv.py @@ -296,7 +296,7 @@ class PlexTV(object): return request def get_plextv_sync_lists(self, machine_id='', output_format=''): - uri = '/servers/' + machine_id + '/sync_lists' + uri = '/servers/%s/sync_lists' % machine_id request = self.request_handler.make_request(uri=uri, proto=self.protocol, request_type='GET', @@ -337,6 +337,24 @@ class PlexTV(object): return request + def delete_plextv_device_sync_lists(self, client_id='', output_format=''): + uri = '/devices/%s/sync_items' % client_id + request = self.request_handler.make_request(uri=uri, + proto=self.protocol, + request_type='GET', + output_format=output_format) + + return request + + def delete_plextv_sync(self, client_id='', sync_id='', output_format=''): + uri = '/devices/%s/sync_items/%s' % (client_id, sync_id) + request = self.request_handler.make_request(uri=uri, + proto=self.protocol, + request_type='DELETE', + output_format=output_format) + + return request + def get_full_users_list(self): friends_list = self.get_plextv_friends() own_account = self.get_plextv_user_details() @@ -425,7 +443,8 @@ class PlexTV(object): logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.") else: for a in xml_head: - client_id = helpers.get_xml_attr(a, 'id') + sync_id = helpers.get_xml_attr(a, 'id') + client_id = helpers.get_xml_attr(a, 'clientIdentifier') sync_device = a.getElementsByTagName('Device') for device in sync_device: device_user_id = helpers.get_xml_attr(device, 'userID') @@ -505,6 +524,7 @@ class PlexTV(object): "video_quality": settings_video_quality, "total_size": status_total_size, "failure": status_failure, + "client_id": client_id, "sync_id": sync_id } @@ -512,6 +532,10 @@ class PlexTV(object): return session.filter_session_info(synced_items, filter_key='user_id') + def delete_sync(self, client_id, sync_id): + logger.info(u"PlexPy PlexTV :: Deleting sync item '%s'." % sync_id) + self.delete_plextv_sync(client_id=client_id, sync_id=sync_id) + def get_server_urls(self, include_https=True): if plexpy.CONFIG.PMS_IDENTIFIER: diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 19e65206..4a650a29 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2271,6 +2271,17 @@ class WebInterface(object): return output + @cherrypy.expose + @cherrypy.tools.json_out() + @requireAuth(member_of("admin")) + def delete_sync_rows(self, client_id, sync_id, **kwargs): + if client_id and sync_id: + plex_tv = plextv.PlexTV() + delete_row = plex_tv.delete_sync(client_id=client_id, sync_id=sync_id) + return {'message': 'Sync deleted'} + else: + return {'message': 'no data received'} + ##### Logs ##### @cherrypy.expose
StateUserTitleTypePlatformDeviceTotal SizeTotal ItemsConvertedDownloadedCompleteDeleteStateUserTitleTypePlatformDeviceTotal SizeTotal ItemsConvertedDownloadedComplete