More concurrent stream stats

* Also fix graph queries
This commit is contained in:
Jonathan Wong 2016-01-08 22:45:22 -08:00
parent af76017a79
commit b490831a50
3 changed files with 177 additions and 97 deletions

View file

@ -105,13 +105,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -181,13 +181,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -257,13 +257,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -333,13 +333,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -409,13 +409,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -485,13 +485,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -569,13 +569,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -647,13 +647,13 @@ DOCUMENTATION :: END
$("#platform-stat").html("<div class='home-platforms-instance-box' style='background-image: url(" + getPlatformImagePath('${top_stat['rows'][0]['platform_type']}') + ");'>");
</script>
</div>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -729,13 +729,13 @@ DOCUMENTATION :: END
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
@ -770,7 +770,7 @@ DOCUMENTATION :: END
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['thumb']}&width=300&height=450&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
@ -809,6 +809,45 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div>
</div>
% if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
% if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
${top_stat['rows'][loop.index]['title']}
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['count']}</h3>
<p> streams
% if top_stat['rows'][loop.index]['started']:
- <span id="most-concurrent-start-${loop.index + 1}">
<script>
$('#most-concurrent-start-${loop.index + 1}').text(moment(${top_stat['rows'][loop.index]['started']},"X").format(date_format + ' ' + time_format));
</script>
</span>
% else:
- N/A
% endif
</p>
</div>
</div>
<div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% endif

View file

@ -570,40 +570,81 @@ class DataFactory(object):
'rows': last_watched})
elif stat == 'most_concurrent':
def calc_most_concurrent(title, result):
'''
Function to calculate most concurrent streams
Input: Stat title, SQLite query result
Output: Dict {title, count, started, stopped}
'''
times = []
for item in result:
times.append({'time': str(item['started']) + 'B', 'count': 1})
times.append({'time': str(item['stopped']) + 'A', 'count': -1})
times = sorted(times, key=lambda k: k['time'])
count = 0
last_count = 0
last_start = 0
concurrent = {'title': title,
'count': 0,
'started': None,
'stopped': None
}
for d in times:
if d['count'] == 1:
count += d['count']
if count >= last_count:
last_start = d['time']
else:
if count >= last_count:
last_count = count
concurrent['count'] = count
concurrent['started'] = last_start[:-1]
concurrent['stopped'] = d['time'][:-1]
count += d['count']
return concurrent
most_concurrent = []
try:
query = 'SELECT started, stopped ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' % time_range
base_query = 'SELECT session_history.started, session_history.stopped ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' % time_range
title = 'Concurrent Streams'
query = base_query
result = monitor_db.select(query)
most_concurrent.append(calc_most_concurrent(title, result))
title = 'Concurrent Transcodes'
query = base_query \
+ 'AND (session_history_media_info.video_decision = "transcode" ' \
'OR session_history_media_info.audio_decision = "transcode") '
result = monitor_db.select(query)
most_concurrent.append(calc_most_concurrent(title, result))
title = 'Concurrent Direct Streams'
query = base_query \
+ 'AND (session_history_media_info.video_decision != "transcode" ' \
'AND session_history_media_info.audio_decision = "copy") '
result = monitor_db.select(query)
most_concurrent.append(calc_most_concurrent(title, result))
title = 'Concurrent Direct Plays'
query = base_query \
+ 'AND (session_history_media_info.video_decision = "direct play" ' \
'OR session_history_media_info.audio_decision = "direct play") '
result = monitor_db.select(query)
most_concurrent.append(calc_most_concurrent(title, result))
except:
logger.warn("Unable to execute database query for get_home_stats: most_concurrent.")
return None
times = []
for item in result:
times.append({'time': str(item['started']) + 'B', 'count': 1})
times.append({'time': str(item['stopped']) + 'A', 'count': -1})
times = sorted(times, key=lambda k: k['time'])
count = 0
last_count = 0
last_start = 0
most_concurrent = []
for d in times:
if d['count'] == 1:
count += d['count']
if count >= last_count:
last_start = d['time']
else:
if count >= last_count:
last_count = count
most_concurrent = [{'count': count,
'started': last_start[:-1],
'stopped': d['time'][:-1]}]
count += d['count']
home_stats.append({'stat_id': stat,
'rows': most_concurrent})

View file

@ -479,14 +479,14 @@ class Graphs(object):
try:
if y_axis == 'plays':
query = 'SELECT date(session_history.started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
@ -500,15 +500,15 @@ class Graphs(object):
else:
query = 'SELECT date(session_history.started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_count, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_count, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_count ' \
'FROM session_history ' \
@ -574,14 +574,14 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT session_history_media_info.video_resolution AS resolution, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
@ -597,15 +597,15 @@ class Graphs(object):
else:
query = 'SELECT session_history_media_info.video_resolution AS resolution,' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_count, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_count, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_count, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
@ -661,14 +661,14 @@ class Graphs(object):
'when session_history_media_info.transcode_height <= 1440 then "QHD" ' \
'when session_history_media_info.transcode_height <= 2160 then "4K" ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" '\
'or session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
@ -694,15 +694,15 @@ class Graphs(object):
'when session_history_media_info.transcode_height <= 2160 then "4K" ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_count, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_count, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_count, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
@ -749,14 +749,14 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
@ -772,15 +772,15 @@ class Graphs(object):
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_count, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_count, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history_media_info.audio_decision = "transcode") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_count, ' \
'SUM(case when session_history.stopped > 0 ' \
@ -828,14 +828,14 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT ' \
'CASE WHEN users.friendly_name is null then users.username else users.friendly_name end as username, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
@ -852,15 +852,15 @@ class Graphs(object):
query = 'SELECT ' \
'CASE WHEN users.friendly_name is null then users.username else users.friendly_name end as username, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'or session_history_media_info.audio_decision = "direct play") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_count, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'SUM(case when (session_history_media_info.video_decision != "transcode" ' \
'and session_history_media_info.audio_decision = "copy") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_count, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history_media_info.audio_decision = "transcode") ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_count, ' \
'SUM(case when session_history.stopped > 0 ' \