mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-07 05:31:15 -07:00
Add new graphs for watches by day of week and hour of day.
Clean up some graph styling
This commit is contained in:
parent
71a2e75fef
commit
0224c709b0
6 changed files with 257 additions and 3 deletions
|
@ -8152,7 +8152,7 @@ ol.test >li {
|
||||||
}
|
}
|
||||||
|
|
||||||
.graphs-instance {
|
.graphs-instance {
|
||||||
height: 350px;
|
height: 300px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background-color: #282828;
|
background-color: #282828;
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
|
@ -8160,7 +8160,9 @@ ol.test >li {
|
||||||
}
|
}
|
||||||
|
|
||||||
.watch-chart {
|
.watch-chart {
|
||||||
height: 360px;
|
margin-top: 10px;
|
||||||
|
height: 300px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.graphs-load {
|
.graphs-load {
|
||||||
|
|
|
@ -30,13 +30,42 @@ from plexpy import helpers
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="currentActivity">
|
<div>
|
||||||
<div class="graphs-instance">
|
<div class="graphs-instance">
|
||||||
<div class="watch-chart" id="chart_div_plays_by_day">
|
<div class="watch-chart" id="chart_div_plays_by_day">
|
||||||
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div><br>
|
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div><br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span6">
|
||||||
|
<div class="wellheader">
|
||||||
|
<div class="dashboard-wellheader">
|
||||||
|
<h3>Watches by day of week (Past 30 days)</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="graphs-instance">
|
||||||
|
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
|
||||||
|
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="span6">
|
||||||
|
<div class="wellheader">
|
||||||
|
<div class="dashboard-wellheader">
|
||||||
|
<h3>Watches by hour of day (Past 30 days)</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="graphs-instance">
|
||||||
|
<div class="watch-chart" id="chart_div_plays_by_hourofday">
|
||||||
|
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -47,7 +76,10 @@ from plexpy import helpers
|
||||||
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
||||||
<script src="interfaces/default/js/highcharts/js/highcharts.js"></script>
|
<script src="interfaces/default/js/highcharts/js/highcharts.js"></script>
|
||||||
<script src="interfaces/default/js/graphs/plays_by_day.js"></script>
|
<script src="interfaces/default/js/graphs/plays_by_day.js"></script>
|
||||||
|
<script src="interfaces/default/js/graphs/plays_by_dayofweek.js"></script>
|
||||||
|
<script src="interfaces/default/js/graphs/plays_by_hourofday.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "get_plays_by_date",
|
url: "get_plays_by_date",
|
||||||
type: 'get',
|
type: 'get',
|
||||||
|
@ -64,5 +96,30 @@ from plexpy import helpers
|
||||||
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
|
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "get_plays_by_dayofweek",
|
||||||
|
type: 'get',
|
||||||
|
data: { time_range: '30' },
|
||||||
|
dataType: "json",
|
||||||
|
success: function(data) {
|
||||||
|
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
|
||||||
|
hc_plays_by_dayofweek_options.series = data.series;
|
||||||
|
var hc_plays_by_dayofweek = new Highcharts.Chart(hc_plays_by_dayofweek_options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "get_plays_by_hourofday",
|
||||||
|
type: 'get',
|
||||||
|
data: { time_range: '30' },
|
||||||
|
dataType: "json",
|
||||||
|
success: function(data) {
|
||||||
|
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
|
||||||
|
hc_plays_by_hourofday_options.series = data.series;
|
||||||
|
var hc_plays_by_hourofday = new Highcharts.Chart(hc_plays_by_hourofday_options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
45
data/interfaces/default/js/graphs/plays_by_dayofweek.js
Normal file
45
data/interfaces/default/js/graphs/plays_by_dayofweek.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
var hc_plays_by_dayofweek_options = {
|
||||||
|
chart: {
|
||||||
|
type: 'column',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0)',
|
||||||
|
renderTo: 'chart_div_plays_by_dayofweek'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: ''
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
column: {
|
||||||
|
pointPadding: 0.2,
|
||||||
|
borderWidth: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
enabled: true,
|
||||||
|
itemStyle: {
|
||||||
|
font: '9pt "Open Sans", sans-serif',
|
||||||
|
color: '#A0A0A0'
|
||||||
|
},
|
||||||
|
itemHoverStyle: {
|
||||||
|
color: '#FFF'
|
||||||
|
},
|
||||||
|
itemHiddenStyle: {
|
||||||
|
color: '#444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
colors: ['#F9AA03', '#FFFFFF'],
|
||||||
|
xAxis: {
|
||||||
|
categories: [{}]
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
|
||||||
|
},
|
||||||
|
series: [{}]
|
||||||
|
};
|
45
data/interfaces/default/js/graphs/plays_by_hourofday.js
Normal file
45
data/interfaces/default/js/graphs/plays_by_hourofday.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
var hc_plays_by_hourofday_options = {
|
||||||
|
chart: {
|
||||||
|
type: 'column',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0)',
|
||||||
|
renderTo: 'chart_div_plays_by_hourofday'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: ''
|
||||||
|
},
|
||||||
|
plotOptions: {
|
||||||
|
column: {
|
||||||
|
pointPadding: 0.2,
|
||||||
|
borderWidth: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
enabled: true,
|
||||||
|
itemStyle: {
|
||||||
|
font: '9pt "Open Sans", sans-serif',
|
||||||
|
color: '#A0A0A0'
|
||||||
|
},
|
||||||
|
itemHoverStyle: {
|
||||||
|
color: '#FFF'
|
||||||
|
},
|
||||||
|
itemHiddenStyle: {
|
||||||
|
color: '#444'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
colors: ['#F9AA03', '#FFFFFF'],
|
||||||
|
xAxis: {
|
||||||
|
categories: [{}]
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
title: {
|
||||||
|
text: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
|
||||||
|
},
|
||||||
|
series: [{}]
|
||||||
|
};
|
|
@ -792,6 +792,87 @@ class PlexWatch(object):
|
||||||
'series': [series_1_output, series_2_output]}
|
'series': [series_1_output, series_2_output]}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def get_total_plays_per_dayofweek(self, time_range='30'):
|
||||||
|
myDB = db.DBConnection()
|
||||||
|
|
||||||
|
if not time_range.isdigit():
|
||||||
|
time_range = '30'
|
||||||
|
|
||||||
|
query = 'SELECT strftime("%w", datetime(time, "unixepoch", "localtime")) as daynumber, ' \
|
||||||
|
'case cast (strftime("%w", datetime(time, "unixepoch", "localtime")) as integer) ' \
|
||||||
|
'when 0 then "Sunday" ' \
|
||||||
|
'when 1 then "Monday" ' \
|
||||||
|
'when 2 then "Tuesday" ' \
|
||||||
|
'when 3 then "Wednesday" ' \
|
||||||
|
'when 4 then "Thursday" ' \
|
||||||
|
'when 5 then "Friday" ' \
|
||||||
|
'else "Saturday" end as dayofweek, ' \
|
||||||
|
'COUNT(id) as total_plays ' \
|
||||||
|
'from ' + self.get_user_table_name() + ' ' + \
|
||||||
|
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
|
||||||
|
'datetime("now", "-' + time_range + ' days", "localtime") ' \
|
||||||
|
'GROUP BY dayofweek ' \
|
||||||
|
'ORDER BY daynumber'
|
||||||
|
|
||||||
|
result = myDB.select(query)
|
||||||
|
|
||||||
|
categories = []
|
||||||
|
series_1 = []
|
||||||
|
|
||||||
|
for item in result:
|
||||||
|
categories.append(item[1])
|
||||||
|
series_1.append(item[2])
|
||||||
|
|
||||||
|
series_1_output = {'name': 'Total plays',
|
||||||
|
'data': series_1}
|
||||||
|
|
||||||
|
output = {'categories': categories,
|
||||||
|
'series': [series_1_output]}
|
||||||
|
return output
|
||||||
|
|
||||||
|
def get_total_plays_per_hourofday(self, time_range='30'):
|
||||||
|
myDB = db.DBConnection()
|
||||||
|
|
||||||
|
if not time_range.isdigit():
|
||||||
|
time_range = '30'
|
||||||
|
|
||||||
|
query = 'select strftime("%H", datetime(time, "unixepoch", "localtime")) as hourofday, ' \
|
||||||
|
'COUNT(id) ' \
|
||||||
|
'FROM ' + self.get_user_table_name() + ' ' + \
|
||||||
|
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
|
||||||
|
'datetime("now", "-' + time_range + ' days", "localtime") ' \
|
||||||
|
'GROUP BY hourofday ' \
|
||||||
|
'ORDER BY hourofday'
|
||||||
|
|
||||||
|
result = myDB.select(query)
|
||||||
|
|
||||||
|
hours_list = ['00','01','02','03','04','05',
|
||||||
|
'06','07','08','09','10','11',
|
||||||
|
'12','13','14','15','16','17',
|
||||||
|
'18','19','20','21','22','23']
|
||||||
|
|
||||||
|
categories = []
|
||||||
|
series_1 = []
|
||||||
|
|
||||||
|
for hour_item in hours_list:
|
||||||
|
categories.append(hour_item)
|
||||||
|
series_1_value = 0
|
||||||
|
for item in result:
|
||||||
|
if hour_item == item[0]:
|
||||||
|
series_1_value = item[1]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
series_1_value = 0
|
||||||
|
|
||||||
|
series_1.append(series_1_value)
|
||||||
|
|
||||||
|
series_1_output = {'name': 'Total plays',
|
||||||
|
'data': series_1}
|
||||||
|
|
||||||
|
output = {'categories': categories,
|
||||||
|
'series': [series_1_output]}
|
||||||
|
return output
|
||||||
|
|
||||||
# Taken from:
|
# Taken from:
|
||||||
# https://stackoverflow.com/questions/18066269/group-by-and-aggregate-the-values-of-a-list-of-dictionaries-in-python
|
# https://stackoverflow.com/questions/18066269/group-by-and-aggregate-the-values-of-a-list-of-dictionaries-in-python
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -738,3 +738,27 @@ class WebInterface(object):
|
||||||
return json.dumps(result)
|
return json.dumps(result)
|
||||||
else:
|
else:
|
||||||
logger.warn('Unable to retrieve data.')
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def get_plays_by_dayofweek(self, time_range='30', **kwargs):
|
||||||
|
|
||||||
|
plex_watch = plexwatch.PlexWatch()
|
||||||
|
result = plex_watch.get_total_plays_per_dayofweek(time_range)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps(result)
|
||||||
|
else:
|
||||||
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def get_plays_by_hourofday(self, time_range='30', **kwargs):
|
||||||
|
|
||||||
|
plex_watch = plexwatch.PlexWatch()
|
||||||
|
result = plex_watch.get_total_plays_per_hourofday(time_range)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps(result)
|
||||||
|
else:
|
||||||
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue