diff --git a/data/interfaces/default/history.html b/data/interfaces/default/history.html index 4e8ad8a3..16f0e338 100644 --- a/data/interfaces/default/history.html +++ b/data/interfaces/default/history.html @@ -30,7 +30,7 @@ from plexpy import helpers ID Time - User + User Platform IP Address Title @@ -41,6 +41,7 @@ from plexpy import helpers Completed RatingKey + diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index 7b571059..fa9deb97 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -189,7 +189,7 @@ from plexpy import helpers ID Time - User + User Platform IP Address Title @@ -200,6 +200,7 @@ from plexpy import helpers Completed RatingKey + diff --git a/data/interfaces/default/js/tables/history_table.js b/data/interfaces/default/js/tables/history_table.js index cac6b59e..e2e0cb3f 100644 --- a/data/interfaces/default/js/tables/history_table.js +++ b/data/interfaces/default/js/tables/history_table.js @@ -53,10 +53,10 @@ history_table_options = { }, { "targets": [2], - "data":"user", + "data":"friendly_name", "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { - $(td).html('' + cellData + ''); + $(td).html('' + cellData + ''); } else { $(td).html(cellData); } @@ -162,7 +162,14 @@ history_table_options = { "data":"xml", "searchable":false, "visible":false + }, + { + "targets": [13], + "data":"user", + "searchable":false, + "visible":false } + ], "drawCallback": function (settings) { // Jump to top of page @@ -187,7 +194,7 @@ $('#history_table').on('click', 'td.modal-control', function () { function showStreamDetails() { $.ajax({ url: 'get_stream_data', - data: {row_id: rowData['id'], user: rowData['user']}, + data: {row_id: rowData['id'], user: rowData['friendly_name']}, cache: false, async: true, complete: function(xhr, status) { diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index e872e6d8..81c6a330 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -18,12 +18,8 @@ users_list_table_options = { "ajax": { "url": "get_user_list" }, - "bLengthChange": true, - "bInfo": true, - "bAutoWidth": true, - "aaSorting": [[ 0, "asc" ]], - "bStateSave": true, - "bSortClasses": true, + "autoWidth": true, + "stateSave": true, "sPaginationType": "bootstrap", "columnDefs": [ { @@ -42,10 +38,10 @@ users_list_table_options = { }, { "targets": [1], - "data": "user", + "data": "friendly_name", "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { - $(td).html('' + cellData + ''); + $(td).html('' + cellData + ''); } else { $(td).html(cellData); } @@ -66,7 +62,14 @@ users_list_table_options = { { "targets": [4], "data": "plays" + }, + { + "targets": [5], + "data": "user", + "searchable": false, + "visible": false } + ], "drawCallback": function (settings) { // Jump to top of page diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html index 54a5ea0d..dd5185e3 100644 --- a/data/interfaces/default/user.html +++ b/data/interfaces/default/user.html @@ -177,7 +177,7 @@ from plexpy import helpers ID Time - User + User Platform IP Address Title @@ -188,6 +188,7 @@ from plexpy import helpers Completed RatingKey + diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html index 744886f4..5b55da1f 100644 --- a/data/interfaces/default/users.html +++ b/data/interfaces/default/users.html @@ -28,10 +28,11 @@ from plexpy import helpers - User + User Last Seen Last Known IP Total Plays + diff --git a/plexpy/datatables.py b/plexpy/datatables.py index f90103f3..5c9d21f3 100644 --- a/plexpy/datatables.py +++ b/plexpy/datatables.py @@ -39,6 +39,9 @@ class DataTables(object): search_regex='', custom_where='', group_by='', + join_type=None, + join_table=None, + join_evals=None, kwargs=None): parameters = self.process_kwargs(kwargs) @@ -50,7 +53,14 @@ class DataTables(object): column_data = self.extract_columns(columns) where = self.construct_where(column_data, search_value, grouping, parameters) - order = self.construct_order(column_data, order_column, order_dir, parameters) + order = self.construct_order(column_data, order_column, order_dir, parameters, table_name, grouping) + join = '' + + if join_type: + if join_type.upper() == 'LEFT OUTER JOIN': + join = 'LEFT OUTER JOIN %s ON %s = %s' % (join_table, join_evals[0], join_evals[1]) + else: + join = '' # TODO: custom_where is ugly and causes issues with reported total results if custom_where != '': @@ -58,21 +68,21 @@ class DataTables(object): if grouping: if custom_where == '': - query = 'SELECT * FROM (SELECT %s FROM %s GROUP BY %s) %s %s' \ - % (column_data['column_string'], table_name, group_by, + query = 'SELECT * FROM (SELECT %s FROM %s %s GROUP BY %s) %s %s' \ + % (column_data['column_string'], table_name, join, group_by, where, order) else: - query = 'SELECT * FROM (SELECT * FROM (SELECT %s FROM %s GROUP BY %s) %s %s) %s' \ - % (column_data['column_string'], table_name, group_by, + query = 'SELECT * FROM (SELECT * FROM (SELECT %s FROM %s %s GROUP BY %s) %s %s) %s' \ + % (column_data['column_string'], table_name, join, group_by, where, order, custom_where) else: if custom_where == '': - query = 'SELECT %s FROM %s %s %s' \ - % (column_data['column_string'], table_name, where, + query = 'SELECT %s FROM %s %s %s %s' \ + % (column_data['column_string'], table_name, join, where, order) else: - query = 'SELECT * FROM (SELECT %s FROM %s %s %s) %s' \ - % (column_data['column_string'], table_name, where, + query = 'SELECT * FROM (SELECT %s FROM %s %s %s %s) %s' \ + % (column_data['column_string'], table_name, join, where, order, custom_where) # logger.debug(u"Query string: %s" % query) @@ -91,16 +101,23 @@ class DataTables(object): return output @staticmethod - def construct_order(column_data, order_column, order_dir, parameters=None): + def construct_order(column_data, order_column, order_dir, parameters=None, table_name=None, grouped=False): order = '' + if grouped: + sort_col = column_data['column_named'][order_column] + else: + sort_col = column_data['column_order'][order_column] if parameters: for parameter in parameters: if parameter['data'] != '': if int(order_column) == parameter['index']: if parameter['data'] in column_data['column_named'] and parameter['orderable'] == 'true': - order = 'ORDER BY %s COLLATE NOCASE %s' % (parameter['data'], order_dir) + if table_name and table_name != '': + order = 'ORDER BY %s COLLATE NOCASE %s' % (sort_col, order_dir) + else: + order = 'ORDER BY %s COLLATE NOCASE %s' % (sort_col, order_dir) else: - order = 'ORDER BY %s COLLATE NOCASE %s' % (column_data['column_named'][order_column], order_dir) + order = 'ORDER BY %s COLLATE NOCASE %s' % (sort_col, order_dir) return order @@ -112,7 +129,7 @@ class DataTables(object): for column in column_data['column_named']: search_skip = False for parameter in parameters: - if column in parameter['data']: + if column.rpartition('.')[-1] in parameter['data']: if parameter['searchable'] == 'true': where += column + ' LIKE "%' + search_value + '%" OR ' search_skip = True @@ -139,6 +156,7 @@ class DataTables(object): columns_string = '' columns_literal = [] columns_named = [] + columns_order = [] for column in columns: columns_string += column @@ -146,23 +164,25 @@ class DataTables(object): # TODO: make this case insensitive if ' as ' in column: columns_literal.append(column.rpartition(' as ')[0]) - columns_named.append(column.rpartition(' as ')[-1]) + columns_named.append(column.rpartition(' as ')[-1].rpartition('.')[-1]) + columns_order.append(column.rpartition(' as ')[-1]) else: columns_literal.append(column) - columns_named.append(column) + columns_named.append(column.rpartition('.')[-1]) + columns_order.append(column) columns_string = columns_string[:-2] column_data = {'column_string': columns_string, 'column_literal': columns_literal, - 'column_named': columns_named + 'column_named': columns_named, + 'column_order': columns_order } return column_data # TODO: Fix this method. Should not break if kwarg list is not sorted. - @staticmethod - def process_kwargs(kwargs): + def process_kwargs(self, kwargs): column_parameters = [] diff --git a/plexpy/plexwatch.py b/plexpy/plexwatch.py index 7f639c0e..3836c2ed 100644 --- a/plexpy/plexwatch.py +++ b/plexpy/plexwatch.py @@ -64,12 +64,16 @@ class PlexWatch(object): if 'search[regex]' in kwargs: search_regex = kwargs.get('search[regex]', "") - columns = ['user', - 'time', - 'ip_address', - 'COUNT(title) as plays'] + t = self.get_history_table_name() + + columns = [t + '.id', + '(case when plexpy_users.friendly_name is null then ' + t + '.user else plexpy_users.friendly_name end) as friendly_name', + t + '.time', + t + '.ip_address', + 'COUNT(' + t + '.title) as plays', + t + '.user'] try: - query = data_tables.ssp_query(table_name=self.get_history_table_name(), + query = data_tables.ssp_query(table_name=t, columns=columns, start=start, length=length, @@ -78,7 +82,10 @@ class PlexWatch(object): search_value=search_value, search_regex=search_regex, custom_where='', - group_by='user', + group_by=(t + '.user'), + join_type='LEFT OUTER JOIN', + join_table='plexpy_users', + join_evals=[t + '.user', 'plexpy_users.username'], kwargs=kwargs) except: logger.warn("Unable to open PlexWatch database.") @@ -94,9 +101,10 @@ class PlexWatch(object): row = {"plays": item['plays'], "time": item['time'], - "user": item["user"], + "friendly_name": item["friendly_name"], "ip_address": item["ip_address"], - "thumb": thumb['user_thumb'] + "thumb": thumb['user_thumb'], + "user": item["user"] } rows.append(row) @@ -132,12 +140,14 @@ class PlexWatch(object): if 'search[regex]' in kwargs: search_regex = kwargs.get('search[regex]', "") - columns = ['time as last_seen', - 'ip_address', - 'COUNT(ip_address) as play_count', - 'platform', - 'user', - 'orig_title as last_watched' + t = self.get_history_table_name() + + columns = [t + '.time as last_seen', + t + '.user', + t + '.ip_address', + 'COUNT(' + t + '.ip_address) as play_count', + t + '.platform', + t + '.title as last_watched' ] try: @@ -150,7 +160,10 @@ class PlexWatch(object): search_value=search_value, search_regex=search_regex, custom_where=custom_where, - group_by='ip_address', + group_by=(t + '.ip_address'), + join_type=None, + join_table=None, + join_evals=None, kwargs=kwargs) except: logger.warn("Unable to open PlexWatch database.") @@ -190,6 +203,8 @@ class PlexWatch(object): order_column = 1 order_dir = "desc" + t = self.get_history_table_name() + if 'order[0][dir]' in kwargs: order_dir = kwargs.get('order[0][dir]', "desc") @@ -202,24 +217,25 @@ class PlexWatch(object): if 'search[regex]' in kwargs: search_regex = kwargs.get('search[regex]', "") - columns = ['id', - 'time as date', - 'user', - 'platform', - 'ip_address', - 'title', - 'time as started', - 'paused_counter', - 'stopped', - 'ratingKey as rating_key', - 'xml', - 'round((julianday(datetime(stopped, "unixepoch", "localtime")) - \ - julianday(datetime(time, "unixepoch", "localtime"))) * 86400) - \ - (case when paused_counter is null then 0 else paused_counter end) as duration', - 'grandparentRatingKey as grandparent_rating_key' + columns = [t + '.id', + t + '.time as date', + '(case when plexpy_users.friendly_name is null then ' + t + '.user else plexpy_users.friendly_name end) as friendly_name', + t + '.platform', + t + '.ip_address', + t + '.title', + t + '.time as started', + t + '.paused_counter', + t + '.stopped', + 'round((julianday(datetime(' + t + '.stopped, "unixepoch", "localtime")) - \ + julianday(datetime(' + t + '.time, "unixepoch", "localtime"))) * 86400) - \ + (case when ' + t + '.paused_counter is null then 0 else ' + t + '.paused_counter end) as duration', + t + '.ratingKey as rating_key', + t + '.xml', + t + '.user', + t + '.grandparentRatingKey as grandparent_rating_key' ] try: - query = data_tables.ssp_query(table_name=self.get_history_table_name(), + query = data_tables.ssp_query(table_name=t, columns=columns, start=start, length=length, @@ -229,6 +245,9 @@ class PlexWatch(object): search_regex=search_regex, custom_where=custom_where, group_by='', + join_type='LEFT OUTER JOIN', + join_table='plexpy_users', + join_evals=[t + '.user', 'plexpy_users.username'], kwargs=kwargs) except: logger.warn("Unable to open PlexWatch database.") @@ -243,7 +262,7 @@ class PlexWatch(object): for item in history: row = {"id": item['id'], "date": item['date'], - "user": item["user"], + "friendly_name": item['friendly_name'], "platform": item["platform"], "ip_address": item["ip_address"], "title": item["title"], @@ -253,7 +272,9 @@ class PlexWatch(object): "rating_key": item["rating_key"], "duration": item["duration"], "percent_complete": 0, - "xml": ""} + "xml": "", + "user": item["user"] + } if item['paused_counter'] > 0: row['paused_counter'] = item['paused_counter']