Implement new home page stats (still needs styling)

This commit is contained in:
Tim 2015-06-21 23:25:45 +02:00
parent 9364b06c99
commit 112d5f0efa
4 changed files with 267 additions and 1 deletions

View file

@ -0,0 +1,67 @@
% if stats[0]['rows']:
<div class="dashboard-recent-media-row">
<ul class="dashboard-recent-media">
% for a in stats:
<div class="dashboard-recent-media-instance">
% if a['stat_id'] == 'top_tv':
<li>
<div class="poster">
<h5>Most watched TV</h5><br/>
<div class="poster-face">
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb'] != '':
<img src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=153&height=225" class="poster-face">
% else:
<img src="interfaces/default/images/poster.png" class="poster-face">
% endif
</a>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${a['rows'][0]['orig_title']}</h3>
<div class="muted">Plays: ${a['rows'][0]['total_plays']}</div>
</div>
</li>
% elif a['stat_id'] == 'top_users':
<li>
<div class="poster">
<h5>Most active user</h5><br/>
<div class="poster-face">
<a href="user?user=${a['rows'][0]['user']}">
% if a['rows'][0]['thumb'] != '':
<img src="${a['rows'][0]['thumb']}" class="poster-face">
% else:
<img src="interfaces/default/images/gravatar-default.png" class="poster-face">
% endif
</a>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${a['rows'][0]['user']}</h3>
<div class="muted">Plays: ${a['rows'][0]['total_plays']}</div>
</div>
</li>
% elif a['stat_id'] == 'top_platforms':
<li>
<div class="poster">
<h5>Most used platform</h5><br/>
<div class="poster-face" id="platform-face">
<img src="interfaces/default/images/platforms/default.png" class="poster-face">
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${a['rows'][0]['platform_type']}</h3>
<div class="muted">Plays: ${a['rows'][0]['total_plays']}</div>
</div>
</li>
<script>
$("#platform-face").html("<img class='user-platforms-instance-poster' src='" + getPlatformImagePath('${a['rows'][0]['platform_type']}') + "'>");
</script>
% endif
</div>
% endfor
</ul>
</div>
% else:
<div class="muted">No stats for selected period.</div><br>
% endif

View file

@ -26,6 +26,24 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Statistics
<span class="muted"> | <a href="javascript:void(0)" id="stats-7">7 days</a></span>
<span class="muted"> | <a href="javascript:void(0)" id="stats-30">30 days</a></span>
<span class="muted"> | <a href="javascript:void(0)" id="stats-90">90 days</a></span>
</h3>
</div>
</div>
<div id="home-stats">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading stats...</div><br>
</div>
</div>
</div>
</div>
<div class='row-fluid'> <div class='row-fluid'>
<div class='wellbg'> <div class='wellbg'>
<div class='wellheader'> <div class='wellheader'>
@ -45,6 +63,19 @@
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="interfaces/default/js/moment-with-locale.js"></script>
<script> <script>
function getHomeStats(days) {
$.ajax({
url: 'home_stats',
cache: false,
async: true,
data: {time_range: days},
complete: function(xhr, status) {
$("#home-stats").html(xhr.responseText);
}
});
}
function currentActivity() { function currentActivity() {
$.ajax({ $.ajax({
url: 'get_current_activity', url: 'get_current_activity',
@ -97,6 +128,24 @@
recentlyAdded(); recentlyAdded();
}); });
}); });
getHomeStats(7);
$('#stats-7').click(function() {
$('#home-stats').html('<div class="muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div><br>');
getHomeStats(7);
});
$('#stats-30').click(function() {
$('#home-stats').html('<div class="muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div><br>');
getHomeStats(30);
});
$('#stats-90').click(function() {
$('#home-stats').html('<div class="muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div><br>');
getHomeStats(90);
});
</script> </script>
</%def> </%def>

View file

@ -15,6 +15,7 @@
from plexpy import logger, helpers, request, datatables, config, db from plexpy import logger, helpers, request, datatables, config, db
from xml.dom import minidom from xml.dom import minidom
from collections import defaultdict, Counter
import plexpy import plexpy
import json import json
@ -562,4 +563,134 @@ class PlexWatch(object):
user_info = {'user_id': user_id, user_info = {'user_id': user_id,
'user_thumb': user_thumb} 'user_thumb': user_thumb}
return user_info return user_info
def get_home_stats(self, time_range='30'):
myDB = db.DBConnection()
if not time_range.isdigit():
time_range = '30'
stats_queries = ["top_tv", "top_users", "top_platforms"]
home_stats = []
for stat in stats_queries:
if 'top_tv' in stat:
top_tv = []
query = 'SELECT orig_title, COUNT(orig_title) as total_plays, grandparentRatingKey, MAX(time) as last_watch, xml ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'AND episode != "" ' \
'GROUP BY orig_title ' \
'ORDER BY total_plays DESC LIMIT 10' % (self.get_user_table_name(), time_range)
result = myDB.select(query)
for item in result:
xml_data = helpers.latinToAscii(item[4])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch database.")
return None
xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.")
return None
for a in xml_head:
grandparent_thumb = self.get_xml_attr(a, 'grandparentThumb')
row = {'orig_title': item[0],
'total_plays': item[1],
'rating_key': item[2],
'last_play': item[3],
'grandparent_thumb': grandparent_thumb
}
top_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': top_tv})
elif 'top_users' in stat:
top_users = []
query = 'SELECT user, COUNT(id) as total_plays, MAX(time) as last_watch ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'GROUP BY user ' \
'ORDER BY total_plays DESC LIMIT 10' % (self.get_user_table_name(), time_range)
result = myDB.select(query)
for item in result:
thumb = self.get_user_gravatar_image(item[0])
row = {'user': item[0],
'total_plays': item[1],
'last_play': item[2],
'thumb': thumb['user_thumb']
}
top_users.append(row)
home_stats.append({'stat_id': stat,
'rows': top_users})
elif 'top_platforms' in stat:
top_platform = []
query = 'SELECT platform, COUNT(id) as total_plays, MAX(time) as last_watch, xml ' \
'FROM %s ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'GROUP BY platform ' \
'ORDER BY total_plays DESC' % (self.get_user_table_name(), time_range)
result = myDB.select(query)
for item in result:
xml_data = helpers.latinToAscii(item[3])
try:
xml_parse = minidom.parseString(xml_data)
except:
logger.warn("Error parsing XML for Plexwatch database.")
return None
xml_head = xml_parse.getElementsByTagName('Player')
if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.")
return None
for a in xml_head:
platform_type = self.get_xml_attr(a, 'platform')
row = {'platform': item[0],
'total_plays': item[1],
'last_play': item[2],
'platform_type': platform_type
}
top_platform.append(row)
top_platform_aggr = self.group_and_sum_dataset(
top_platform, 'platform_type', ['total_plays'], 'total_plays')
home_stats.append({'stat_id': stat,
'rows': top_platform_aggr})
return home_stats
# Taken from:
# https://stackoverflow.com/questions/18066269/group-by-and-aggregate-the-values-of-a-list-of-dictionaries-in-python
@staticmethod
def group_and_sum_dataset(dataset, group_by_key, sum_value_keys, sort_by_key):
container = defaultdict(Counter)
for item in dataset:
key = item[group_by_key]
values = {k: item[k] for k in sum_value_keys}
container[key].update(values)
new_dataset = [
dict([(group_by_key, item[0])] + item[1].items())
for item in container.items()
]
new_dataset.sort(key=lambda item: item[sort_by_key], reverse=True)
return new_dataset

View file

@ -83,6 +83,13 @@ class WebInterface(object):
cherrypy.response.headers['Content-type'] = 'application/json' cherrypy.response.headers['Content-type'] = 'application/json'
return json.dumps(formats) return json.dumps(formats)
@cherrypy.expose
def home_stats(self, time_range='30', **kwargs):
plex_watch = plexwatch.PlexWatch()
stats_data = plex_watch.get_home_stats(time_range)
return serve_template(templatename="home_stats.html", title="Stats", stats=stats_data)
@cherrypy.expose @cherrypy.expose
def history(self): def history(self):
return serve_template(templatename="history.html", title="History") return serve_template(templatename="history.html", title="History")
@ -671,6 +678,18 @@ class WebInterface(object):
plex_watch = plexwatch.PlexWatch() plex_watch = plexwatch.PlexWatch()
result = plex_watch.get_user_gravatar_image(user) result = plex_watch.get_user_gravatar_image(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_home_stats(self, time_range='30', **kwargs):
plex_watch = plexwatch.PlexWatch()
result = plex_watch.get_home_stats(time_range)
if result: if result:
cherrypy.response.headers['Content-type'] = 'application/json' cherrypy.response.headers['Content-type'] = 'application/json'
return json.dumps(result) return json.dumps(result)