diff --git a/README.md b/README.md
index f3469fd7..1212e9ab 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ A python based web front-end for plexWatch.
* full user list with general information and comparison stats
-* individual user information **PARTIALLY IMPLEMENTED**
+* individual user information
- username and gravatar (if available)
- daily, weekly, monthly, all time stats for play count and duration length
- individual platform stats for each user
diff --git a/data/interfaces/default/css/plexwatch.css b/data/interfaces/default/css/plexwatch.css
index 6a676997..23a4502b 100644
--- a/data/interfaces/default/css/plexwatch.css
+++ b/data/interfaces/default/css/plexwatch.css
@@ -7635,6 +7635,7 @@ button.close {
}
.user-info-poster-face img {
bottom: 0;
+ margin-right: 15px;
overflow: hidden;
float: left;
background-color: #323232;
@@ -7651,12 +7652,11 @@ button.close {
color: #fff;
position: relative;
top: 27px;
- left: 15px;
}
.user-info-nav {
position: relative;
top: 15px;
- left: 3px;
+ left: -5px;
}
.user-info-nav > .active > a, .nav-tabs > .active > a:hover, .nav-tabs > .active > a:focus {
color: #F9AA03;
diff --git a/data/interfaces/default/js/script.js b/data/interfaces/default/js/script.js
index e156acb9..c031448f 100644
--- a/data/interfaces/default/js/script.js
+++ b/data/interfaces/default/js/script.js
@@ -210,13 +210,17 @@ function getPlatformImagePath(platformName) {
}
function isPrivateIP(ip_address) {
- var parts = ip_address.split('.');
- if (parts[0] === '10' ||
- (parts[0] === '172' && (parseInt(parts[1], 10) >= 16 && parseInt(parts[1], 10) <= 31)) ||
- (parts[0] === '192' && parts[1] === '168')) {
+ if (ip_address.indexOf(".") > -1) {
+ var parts = ip_address.split('.');
+ if (parts[0] === '10' ||
+ (parts[0] === '172' && (parseInt(parts[1], 10) >= 16 && parseInt(parts[1], 10) <= 31)) ||
+ (parts[0] === '192' && parts[1] === '168')) {
+ return true;
+ }
+ return false;
+ } else {
return true;
}
- return false;
}
function humanTime(seconds) {
diff --git a/data/interfaces/default/js/tables/user_ips.js b/data/interfaces/default/js/tables/user_ips.js
index 99314278..96ff785b 100644
--- a/data/interfaces/default/js/tables/user_ips.js
+++ b/data/interfaces/default/js/tables/user_ips.js
@@ -32,7 +32,11 @@ user_ip_table_options = {
"className": "modal-control",
"createdCell": function (td, cellData, rowData, row, col) {
if (isPrivateIP(cellData)) {
- $(td).html(cellData);
+ if (cellData != '') {
+ $(td).html(cellData);
+ } else {
+ $(td).html('n/a');
+ }
} else {
$(td).html(' ' + cellData +'');
}
diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js
index cbde3b2e..2fade934 100644
--- a/data/interfaces/default/js/tables/users.js
+++ b/data/interfaces/default/js/tables/users.js
@@ -25,13 +25,13 @@ users_list_table_options = {
"columnDefs": [
{
"targets": [0],
- "data": null,
+ "data": "thumb",
"createdCell": function (td, cellData, rowData, row, col) {
- //if (rowData['user_thumb'] === '') {
+ if (cellData === '') {
$(td).html('
');
- //} else {
- // $(td).html('
');
- //}
+ } else {
+ $(td).html('
');
+ }
},
"orderable": false,
"className": "users-poster-face",
diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html
index 52fdf409..33840fc6 100644
--- a/data/interfaces/default/user.html
+++ b/data/interfaces/default/user.html
@@ -13,7 +13,7 @@
% else:
-
There was an error retrieving some data. Please check your
settings.
+
There was an error loading your PlexWatch data. Please check your
settings.
% endif
\ No newline at end of file
diff --git a/data/interfaces/default/user_watch_time_stats.html b/data/interfaces/default/user_watch_time_stats.html
index e95471e7..86ec886a 100644
--- a/data/interfaces/default/user_watch_time_stats.html
+++ b/data/interfaces/default/user_watch_time_stats.html
@@ -9,7 +9,7 @@
% elif a['query_days'] == 1:
Last 24 hours
% else:
-
Last ${a['query_days']} day(s)
+
Last ${a['query_days']} days
% endif
${a['total_plays']}
plays
@@ -21,4 +21,6 @@
% endfor
+% else:
+
There was an error loading your PlexWatch data. Please check your
settings.
% endif
\ No newline at end of file
diff --git a/plexpy/datatables.py b/plexpy/datatables.py
index 1df9df89..a8812df5 100644
--- a/plexpy/datatables.py
+++ b/plexpy/datatables.py
@@ -76,8 +76,8 @@ class DataTables(object):
order, custom_where)
# logger.debug(u"Query string: %s" % query)
-
filtered = self.ssp_db.select(query)
+
if search_value == '':
totalcount = len(filtered)
else:
diff --git a/plexpy/plexwatch.py b/plexpy/plexwatch.py
index 8d53794a..e4eb0e22 100644
--- a/plexpy/plexwatch.py
+++ b/plexpy/plexwatch.py
@@ -72,27 +72,35 @@ class PlexWatch(object):
'time',
'ip_address',
'COUNT(title) as plays']
-
- query = data_tables.ssp_query(table_name=self.get_user_table_name(),
- columns=columns,
- start=start,
- length=length,
- order_column=int(order_column),
- order_dir=order_dir,
- search_value=search_value,
- search_regex=search_regex,
- custom_where='',
- group_by='user',
- kwargs=kwargs)
+ try:
+ query = data_tables.ssp_query(table_name=self.get_user_table_name(),
+ columns=columns,
+ start=start,
+ length=length,
+ order_column=int(order_column),
+ order_dir=order_dir,
+ search_value=search_value,
+ search_regex=search_regex,
+ custom_where='',
+ group_by='user',
+ kwargs=kwargs)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return {'recordsFiltered': 0,
+ 'recordsTotal': 0,
+ 'data': 'null'},
users = query['result']
rows = []
for item in users:
+ thumb = self.get_user_gravatar_image(item['user'])
+
row = {"plays": item['plays'],
"time": item['time'],
"user": item["user"],
- "ip_address": item["ip_address"]
+ "ip_address": item["ip_address"],
+ "thumb": thumb['user_thumb']
}
rows.append(row)
@@ -136,17 +144,23 @@ class PlexWatch(object):
'orig_title as last_watched'
]
- query = data_tables.ssp_query(table_name=self.get_user_table_name(),
- columns=columns,
- start=start,
- length=length,
- order_column=int(order_column),
- order_dir=order_dir,
- search_value=search_value,
- search_regex=search_regex,
- custom_where=custom_where,
- group_by='ip_address',
- kwargs=kwargs)
+ try:
+ query = data_tables.ssp_query(table_name=self.get_user_table_name(),
+ columns=columns,
+ start=start,
+ length=length,
+ order_column=int(order_column),
+ order_dir=order_dir,
+ search_value=search_value,
+ search_regex=search_regex,
+ custom_where=custom_where,
+ group_by='ip_address',
+ kwargs=kwargs)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return {'recordsFiltered': 0,
+ 'recordsTotal': 0,
+ 'data': 'null'},
results = query['result']
@@ -207,18 +221,23 @@ class PlexWatch(object):
julianday(datetime(time, "unixepoch", "localtime"))) * 86400) - \
(case when paused_counter is null then 0 else paused_counter end) as duration'
]
-
- query = data_tables.ssp_query(table_name=self.get_history_table_name(),
- columns=columns,
- start=start,
- length=length,
- order_column=int(order_column),
- order_dir=order_dir,
- search_value=search_value,
- search_regex=search_regex,
- custom_where=custom_where,
- group_by='',
- kwargs=kwargs)
+ try:
+ query = data_tables.ssp_query(table_name=self.get_history_table_name(),
+ columns=columns,
+ start=start,
+ length=length,
+ order_column=int(order_column),
+ order_dir=order_dir,
+ search_value=search_value,
+ search_regex=search_regex,
+ custom_where=custom_where,
+ group_by='',
+ kwargs=kwargs)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return {'recordsFiltered': 0,
+ 'recordsTotal': 0,
+ 'data': 'null'},
history = query['result']
@@ -380,14 +399,18 @@ class PlexWatch(object):
if not limit.isdigit():
limit = '10'
- if user:
- query = 'SELECT time, user, xml FROM %s WHERE user = "%s" ORDER BY time DESC LIMIT %s' % \
- (self.get_user_table_name(), user, limit)
- xml = myDB.select(query)
- else:
- query = 'SELECT time, user, xml FROM %s ORDER BY time DESC LIMIT %s' % \
- (self.get_user_table_name(), limit)
- xml = myDB.select(query)
+ try:
+ if user:
+ query = 'SELECT time, user, xml FROM %s WHERE user = "%s" ORDER BY time DESC LIMIT %s' % \
+ (self.get_user_table_name(), user, limit)
+ xml = myDB.select(query)
+ else:
+ query = 'SELECT time, user, xml FROM %s ORDER BY time DESC LIMIT %s' % \
+ (self.get_user_table_name(), limit)
+ xml = myDB.select(query)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return None
for row in xml:
xml_data = helpers.latinToAscii(row[2])
@@ -435,10 +458,14 @@ class PlexWatch(object):
else:
where = 'WHERE user = "%s"' % user
- query = 'SELECT (SUM(stopped - time) - SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
- 'COUNT(id) AS total_plays ' \
- 'FROM %s %s' % (self.get_user_table_name(), where)
- result = myDB.select(query)
+ try:
+ query = 'SELECT (SUM(stopped - time) - SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
+ 'COUNT(id) AS total_plays ' \
+ 'FROM %s %s' % (self.get_user_table_name(), where)
+ result = myDB.select(query)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return None
for item in result:
if item[0]:
@@ -455,4 +482,84 @@ class PlexWatch(object):
user_watch_time_stats.append(row)
- return user_watch_time_stats
\ No newline at end of file
+ return user_watch_time_stats
+
+ def get_user_platform_stats(self, user=None):
+ myDB = db.DBConnection()
+
+ platform_stats = []
+ result_id = 0
+
+ try:
+ query = 'SELECT platform, COUNT(platform) as platform_count, xml ' \
+ 'FROM %s ' \
+ 'WHERE user = "%s" ' \
+ 'GROUP BY platform ' \
+ 'ORDER BY platform_count DESC' % (self.get_user_table_name(), user)
+ result = myDB.select(query)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return None
+
+ for item in result:
+ xml_data = helpers.latinToAscii(item[2])
+
+ try:
+ xml_parse = minidom.parseString(xml_data)
+ except:
+ logger.warn("Error parsing XML for Plex stream data.")
+ return None
+
+ xml_head = xml_parse.getElementsByTagName('Player')
+ if not xml_head:
+ logger.warn("Error parsing XML for Plex stream data.")
+ return None
+
+ for a in xml_head:
+ platform_type = self.get_xml_attr(a, 'platform')
+
+ row = {'platform_name': item[0],
+ 'platform_type': platform_type,
+ 'total_plays': item[1],
+ 'result_id': result_id
+ }
+ platform_stats.append(row)
+ result_id += 1
+
+ return platform_stats
+
+ def get_user_gravatar_image(self, user=None):
+ myDB = db.DBConnection()
+ user_info = None
+
+ try:
+ query = 'SELECT xml ' \
+ 'FROM %s ' \
+ 'WHERE user = "%s" ' \
+ 'ORDER BY id DESC LIMIT 1' % (self.get_user_table_name(), user)
+ result = myDB.select_single(query)
+ except:
+ logger.warn("Unable to open PlexWatch database.")
+ return None
+
+ xml_data = helpers.latinToAscii(result)
+
+ try:
+ xml_parse = minidom.parseString(xml_data)
+ except:
+ logger.warn("Error parsing XML for Plexwatch Database.")
+ return None
+
+ xml_head = xml_parse.getElementsByTagName('User')
+ if not xml_head:
+ logger.warn("Error parsing XML for Plexwatch Database.")
+ return None
+
+ for a in xml_head:
+ user_id = self.get_xml_attr(a, 'id')
+ user_thumb = self.get_xml_attr(a, 'thumb')
+
+ user_info = {'user_id': user_id,
+ 'user_thumb': user_thumb}
+
+ return user_info
\ No newline at end of file
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index 3d622d58..23b331d6 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -434,7 +434,6 @@ class WebInterface(object):
logger.warn(msg)
return msg
-
@cherrypy.expose
def get_pms_token(self):
@@ -447,7 +446,6 @@ class WebInterface(object):
logger.warn('Unable to retrieve Plex.tv token.')
return False
-
@cherrypy.expose
def get_pms_sessions_json(self, **kwargs):
@@ -543,7 +541,7 @@ class WebInterface(object):
if result:
return serve_template(templatename="user_recently_watched.html", recently_watched=result, title="Recently Watched")
else:
- return serve_template(templatename="user_recently_watched.html", recently_watched='', title="Recently Watched")
+ return serve_template(templatename="user_recently_watched.html", recently_watched=None, title="Recently Watched")
logger.warn('Unable to retrieve data.')
@cherrypy.expose
@@ -555,7 +553,19 @@ class WebInterface(object):
if result:
return serve_template(templatename="user_watch_time_stats.html", watch_stats=result, title="Watch Stats")
else:
- return serve_template(templatename="user_watch_time_stats.html", watch_stats='', title="Watch Stats")
+ return serve_template(templatename="user_watch_time_stats.html", watch_stats=None, title="Watch Stats")
+ logger.warn('Unable to retrieve data.')
+
+ @cherrypy.expose
+ def get_user_platform_stats(self, user=None, **kwargs):
+
+ plex_watch = plexwatch.PlexWatch()
+ result = plex_watch.get_user_platform_stats(user)
+
+ if result:
+ return serve_template(templatename="user_platform_stats.html", platform_stats=result, title="Platform Stats")
+ else:
+ return serve_template(templatename="user_platform_stats.html", platform_stats=None, title="Platform Stats")
logger.warn('Unable to retrieve data.')
@cherrypy.expose
@@ -637,6 +647,30 @@ class WebInterface(object):
plex_watch = plexwatch.PlexWatch()
result = plex_watch.get_user_watch_time_stats(user)
+ if result:
+ cherrypy.response.headers['Content-type'] = 'application/json'
+ return json.dumps(result)
+ else:
+ logger.warn('Unable to retrieve data.')
+
+ @cherrypy.expose
+ def get_platform_stats(self, user=None, **kwargs):
+
+ plex_watch = plexwatch.PlexWatch()
+ result = plex_watch.get_user_platform_stats(user)
+
+ if result:
+ cherrypy.response.headers['Content-type'] = 'application/json'
+ return json.dumps(result)
+ else:
+ logger.warn('Unable to retrieve data.')
+
+ @cherrypy.expose
+ def get_user_gravatar_image(self, user=None, **kwargs):
+
+ plex_watch = plexwatch.PlexWatch()
+ result = plex_watch.get_user_gravatar_image(user)
+
if result:
cherrypy.response.headers['Content-type'] = 'application/json'
return json.dumps(result)