diff --git a/data/interfaces/default/js/tables/user_ips.js b/data/interfaces/default/js/tables/user_ips.js index 7321e1b3..9c8cc411 100644 --- a/data/interfaces/default/js/tables/user_ips.js +++ b/data/interfaces/default/js/tables/user_ips.js @@ -24,13 +24,11 @@ user_ip_table_options = { }, "searchable": false, "width": "15%", - "className": "no-wrap" + "className": "no-wrap hidden-xs" }, { "targets": [1], - "data":"ip_address", - "width": "15%", - "className": "modal-control no-wrap", + "data": "ip_address", "createdCell": function (td, cellData, rowData, row, col) { if (cellData) { if (isPrivateIP(cellData)) { @@ -46,31 +44,59 @@ user_ip_table_options = { $(td).html('n/a'); } }, - "width": "15%" + "width": "15%", + "className": "no-wrap modal-control-ip" }, { "targets": [2], - "data":"play_count", - "width": "10%", - "className": "hidden-xs" + "data":"platform", + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData) { + $(td).html(' ' + cellData + ''); + } else { + $(td).html('n/a'); + } + }, + "width": "15%", + "className": "no-wrap hidden-md hidden-sm hidden-xs modal-control" }, { "targets": [3], - "data":"platform", - "width": "15%", - "className": "hidden-xs" + "data":"last_watched", + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData !== '') { + if (rowData['media_type'] === 'movie' || rowData['media_type'] === 'episode') { + var transcode_dec = ''; + if (rowData['video_decision'] === 'transcode') { + transcode_dec = ' '; + } + $(td).html('
' + cellData + '
' + transcode_dec + '
'); + } else if (rowData['media_type'] === 'track') { + $(td).html('
' + cellData + '
'); + } else if (rowData['media_type']) { + $(td).html('' + cellData + ''); + } else { + $(td).html('n/a'); + } + } + }, + "className": "hidden-sm hidden-xs" }, { "targets": [4], - "data":"last_watched", - "width": "30%", - "className": "hidden-sm hidden-xs" - } + "data":"play_count", + "searchable": false, + "width": "10%" + } ], "drawCallback": function (settings) { // Jump to top of page // $('html,body').scrollTop(0); $('#ajaxMsg').fadeOut(); + // Create the tooltips. + $('.info-modal').each(function () { + $(this).tooltip(); + }); }, "preDrawCallback": function(settings) { var msg = "
 Fetching rows...
"; @@ -83,6 +109,25 @@ $('#user_ip_table').on('mouseenter', 'td.modal-control span', function () { }); $('#user_ip_table').on('click', 'td.modal-control', function () { + var tr = $(this).parents('tr'); + var row = user_ip_table.row(tr); + var rowData = row.data(); + + function showStreamDetails() { + $.ajax({ + url: 'get_stream_data', + data: { row_id: rowData['id'], user: rowData['friendly_name'] }, + cache: false, + async: true, + complete: function (xhr, status) { + $("#info-modal").html(xhr.responseText); + } + }); + } + showStreamDetails(); +}); + +$('#user_ip_table').on('click', 'td.modal-control-ip', function () { var tr = $(this).parents('tr'); var row = user_ip_table.row( tr ); var rowData = row.data(); diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index 5dba864b..c3e022e3 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -34,7 +34,7 @@ users_list_table_options = { { "targets": [1], "data": "friendly_name", - "createdCell": function (td, cellData, rowData, row, col) { + "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { if (rowData['user_id'] > 0) { $(td).html('' + cellData + ''); @@ -45,6 +45,7 @@ users_list_table_options = { $(td).html(cellData); } }, + "width": "15%" }, { "targets": [2], @@ -57,34 +58,126 @@ users_list_table_options = { } }, "searchable": false, - "className": "hidden-xs", + "width": "15%", + "className": "no-wrap hidden-xs" }, { "targets": [3], "data": "ip_address", - "render": function ( data, type, full ) { - if (data) { - return data; + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData) { + if (isPrivateIP(cellData)) { + if (cellData != '') { + $(td).html(cellData); + } else { + $(td).html('n/a'); + } + } else { + $(td).html(' ' + cellData + ''); + } } else { - return "n/a"; + $(td).html('n/a'); } }, - "className": "hidden-xs", + "width": "15%", + "className": "no-wrap hidden-md hidden-sm hidden-xs modal-control-ip" }, { "targets": [4], + "data":"platform", + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData) { + $(td).html(' ' + cellData + ''); + } else { + $(td).html('n/a'); + } + }, + "width": "15%", + "className": "no-wrap hidden-md hidden-sm hidden-xs modal-control" + }, + { + "targets": [5], + "data":"last_watched", + "createdCell": function (td, cellData, rowData, row, col) { + if (cellData !== '') { + if (rowData['media_type'] === 'movie' || rowData['media_type'] === 'episode') { + var transcode_dec = ''; + if (rowData['video_decision'] === 'transcode') { + transcode_dec = ' '; + } + $(td).html('
' + cellData + '
' + transcode_dec + '
'); + } else if (rowData['media_type'] === 'track') { + $(td).html('
' + cellData + '
'); + } else if (rowData['media_type']) { + $(td).html('' + cellData + ''); + } else { + $(td).html('n/a'); + } + } + }, + "className": "hidden-sm hidden-xs" + }, + { + "targets": [6], "data": "plays", - "searchable": false - } + "searchable": false, + "width": "10%" + } ], "drawCallback": function (settings) { // Jump to top of page //$('html,body').scrollTop(0); $('#ajaxMsg').fadeOut(); + // Create the tooltips. + $('.info-modal').each(function () { + $(this).tooltip(); + }); }, "preDrawCallback": function(settings) { var msg = "
 Fetching rows...
"; showMsg(msg, false, false, 0) } } + +$('#users_list_table').on('click', 'td.modal-control', function () { + var tr = $(this).parents('tr'); + var row = users_list_table.row(tr); + var rowData = row.data(); + + function showStreamDetails() { + $.ajax({ + url: 'get_stream_data', + data: { row_id: rowData['id'], user: rowData['friendly_name'] }, + cache: false, + async: true, + complete: function (xhr, status) { + $("#info-modal").html(xhr.responseText); + } + }); + } + showStreamDetails(); +}); + +$('#users_list_table').on('click', 'td.modal-control-ip', function () { + var tr = $(this).parents('tr'); + var row = users_list_table.row(tr); + var rowData = row.data(); + + function getUserLocation(ip_address) { + if (isPrivateIP(ip_address)) { + return "n/a" + } else { + $.ajax({ + url: 'get_ip_address_details', + data: { ip_address: ip_address }, + async: true, + complete: function (xhr, status) { + $("#ip-info-modal").html(xhr.responseText); + } + }); + } + } + + getUserLocation(rowData['ip_address']); +}); \ No newline at end of file diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html index 366d46dc..4727be64 100644 --- a/data/interfaces/default/user.html +++ b/data/interfaces/default/user.html @@ -131,11 +131,11 @@ from plexpy import helpers - + - - + +
Last seenLast Seen IP AddressPlay CountPlatform (Last Seen)Last Platform Last WatchedPlay Count
@@ -181,7 +181,6 @@ from plexpy import helpers - @@ -224,7 +223,9 @@ from plexpy import helpers - diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html index ddb52843..37cf9bc7 100644 --- a/data/interfaces/default/users.html +++ b/data/interfaces/default/users.html @@ -23,12 +23,18 @@ User Last Seen Last Known IP + Last Platform + Last Watched Total Plays + + diff --git a/plexpy/users.py b/plexpy/users.py index fcc9cf94..fb31916c 100644 --- a/plexpy/users.py +++ b/plexpy/users.py @@ -24,13 +24,19 @@ class Users(object): def get_user_list(self, kwargs=None): data_tables = datatables.DataTables() - columns = ['users.user_id as user_id', + columns = ['session_history.id', + 'users.user_id as user_id', 'users.custom_avatar_url as thumb', '(case when users.friendly_name is null then users.username else \ users.friendly_name end) as friendly_name', 'MAX(session_history.started) as last_seen', 'session_history.ip_address as ip_address', 'COUNT(session_history.id) as plays', + 'session_history.player as platform', + 'session_history_metadata.full_title as last_watched', + 'session_history_metadata.media_type', + 'session_history.rating_key as rating_key', + 'session_history_media_info.video_decision', 'users.username as user' ] try: @@ -38,9 +44,15 @@ class Users(object): columns=columns, custom_where=[], group_by=['users.user_id'], - join_types=['LEFT OUTER JOIN'], - join_tables=['session_history'], - join_evals=[['session_history.user_id', 'users.user_id']], + join_types=['LEFT OUTER JOIN', + 'LEFT OUTER JOIN', + 'LEFT OUTER JOIN'], + join_tables=['session_history', + 'session_history_metadata', + 'session_history_media_info'], + join_evals=[['session_history.user_id', 'users.user_id'], + ['session_history.id', 'session_history_metadata.id'], + ['session_history.id', 'session_history_media_info.id']], kwargs=kwargs) except: logger.warn("Unable to execute database query.") @@ -59,10 +71,16 @@ class Users(object): else: user_thumb = item['thumb'] - row = {"plays": item['plays'], + row = {"id": item['id'], + "plays": item['plays'], "last_seen": item['last_seen'], - "friendly_name": item["friendly_name"], - "ip_address": item["ip_address"], + "friendly_name": item['friendly_name'], + "ip_address": item['ip_address'], + "platform": item['platform'], + "last_watched": item['last_watched'], + "media_type": item['media_type'], + "rating_key": item['rating_key'], + "video_decision": item['video_decision'], "thumb": user_thumb, "user": item["user"], "user_id": item['user_id'] @@ -81,13 +99,22 @@ class Users(object): def get_user_unique_ips(self, kwargs=None, custom_where=None): data_tables = datatables.DataTables() - columns = ['session_history.started as last_seen', + # Change custom_where column name due to ambiguous column name after JOIN + custom_where[0][0] = 'custom_user_id' if custom_where[0][0] == 'user_id' else custom_where[0][0] + + columns = ['session_history.id', + 'session_history.started as last_seen', 'session_history.ip_address as ip_address', 'COUNT(session_history.id) as play_count', 'session_history.player as platform', 'session_history_metadata.full_title as last_watched', + 'session_history_metadata.media_type', + 'session_history.rating_key as rating_key', + 'session_history_media_info.video_decision', 'session_history.user as user', - 'session_history.user_id as user_id' + 'session_history.user_id as custom_user_id', + '(case when users.friendly_name is null then users.username else \ + users.friendly_name end) as friendly_name' ] try: @@ -95,9 +122,15 @@ class Users(object): columns=columns, custom_where=custom_where, group_by=['ip_address'], - join_types=['JOIN'], - join_tables=['session_history_metadata'], - join_evals=[['session_history.id', 'session_history_metadata.id']], + join_types=['JOIN', + 'JOIN', + 'JOIN'], + join_tables=['users', + 'session_history_metadata', + 'session_history_media_info'], + join_evals=[['session_history.user_id', 'users.user_id'], + ['session_history.id', 'session_history_metadata.id'], + ['session_history.id', 'session_history_media_info.id']], kwargs=kwargs) except: logger.warn("Unable to execute database query.") @@ -111,11 +144,16 @@ class Users(object): rows = [] for item in results: - row = {"last_seen": item['last_seen'], + row = {"id": item['id'], + "last_seen": item['last_seen'], "ip_address": item['ip_address'], "play_count": item['play_count'], "platform": item['platform'], - "last_watched": item['last_watched'] + "last_watched": item['last_watched'], + "media_type": item['media_type'], + "rating_key": item['rating_key'], + "video_decision": item['video_decision'], + "friendly_name": item['friendly_name'] } rows.append(row)