start to work on stats

This commit is contained in:
bkfox 2016-10-25 16:50:58 +02:00
parent 3ab373097b
commit 76055c742a
8 changed files with 189 additions and 53 deletions

View File

@ -19,7 +19,7 @@ class Streamer:
""" """
Related station Related station
""" """
template_name = 'aircox/controllers/liquidsoap.liq' template_name = 'aircox/config/liquidsoap.liq'
""" """
If set, use this template in order to generated the configuration If set, use this template in order to generated the configuration
file in self.path file file in self.path file

View File

@ -137,7 +137,7 @@ class Command (BaseCommand):
group.add_argument( group.add_argument(
'--check', action='store_true', '--check', action='store_true',
help='check unconfirmed later diffusions from the given ' help='check unconfirmed later diffusions from the given '
'date again'\'t schedule. If no schedule is found, remove ' 'date agains\'t schedule. If no schedule is found, remove '
'it.' 'it.'
) )

View File

@ -105,7 +105,8 @@ class Monitor:
source = current_source.id, source = current_source.id,
date = tz.now(), date = tz.now(),
related = sound[0] if sound else None, related = sound[0] if sound else None,
comment = None if sound else current_sound, # keep sound path (if sound is removed, we keep that info)
comment = current_sound,
) )
def trace_sound_tracks(self, log): def trace_sound_tracks(self, log):

View File

@ -377,52 +377,6 @@ class Program(Nameable):
return qs[0] if qs else None return qs[0] if qs else None
class DiffusionManager(models.Manager):
def get_at(self, date = None, next = False):
"""
Return a queryset of diffusions that have the given date
in their range.
If date is a datetime.date object, check only against the
date.
"""
date = date or tz.now()
if not issubclass(type(date), datetime.datetime):
return self.filter(
models.Q(start__contains = date) | \
models.Q(end__contains = date)
)
if not next:
return self.filter(start__lte = date, end__gte = date) \
.order_by('start')
return self.filter(
models.Q(start__lte = date, end__gte = date) |
models.Q(start__gte = date),
).order_by('start')
def get_after(self, date = None):
"""
Return a queryset of diffusions that happen after the given
date.
"""
date = date_or_default(date)
return self.filter(
start__gte = date,
).order_by('start')
def get_before(self, date):
"""
Return a queryset of diffusions that finish before the given
date.
"""
date = date_or_default(date)
return self.filter(
end__lte = date,
).order_by('start')
class Stream(models.Model): class Stream(models.Model):
""" """
When there are no program scheduled, it is possible to play sounds When there are no program scheduled, it is possible to play sounds
@ -671,6 +625,52 @@ class Schedule(models.Model):
verbose_name_plural = _('Schedules') verbose_name_plural = _('Schedules')
class DiffusionManager(models.Manager):
def get_at(self, date = None, next = False):
"""
Return a queryset of diffusions that have the given date
in their range.
If date is a datetime.date object, check only against the
date.
"""
date = date or tz.now()
if not issubclass(type(date), datetime.datetime):
return self.filter(
models.Q(start__contains = date) | \
models.Q(end__contains = date)
)
if not next:
return self.filter(start__lte = date, end__gte = date) \
.order_by('start')
return self.filter(
models.Q(start__lte = date, end__gte = date) |
models.Q(start__gte = date),
).order_by('start')
def get_after(self, date = None):
"""
Return a queryset of diffusions that happen after the given
date.
"""
date = date_or_default(date)
return self.filter(
start__gte = date,
).order_by('start')
def get_before(self, date):
"""
Return a queryset of diffusions that finish before the given
date.
"""
date = date_or_default(date)
return self.filter(
end__lte = date,
).order_by('start')
class Diffusion(models.Model): class Diffusion(models.Model):
""" """
A Diffusion is an occurrence of a Program that is scheduled on the A Diffusion is an occurrence of a Program that is scheduled on the
@ -1036,7 +1036,7 @@ class Log(Related):
Log sounds and diffusions that are played on the station. Log sounds and diffusions that are played on the station.
This only remember what has been played on the outputs, not on each This only remember what has been played on the outputs, not on each
track; Source designate here which source is responsible of that. source; Source designate here which source is responsible of that.
""" """
class Type(IntEnum): class Type(IntEnum):
stop = 0x00 stop = 0x00

View File

@ -0,0 +1,46 @@
{% load i18n %}
<div id='stats'>
{% for stats in statistics %}
<section class="station">
<header>
<h1>{{ stats.station.name }}</h1>
<h2>- {{ stats.date|date:'l d F Y' }}</h2>
</header>
<table border=1>
<tr>
<th>{% trans "Date" %}</th>
{# Translators "Header for statistics view" #}
<th>{% trans "Diffusion or sound played" %}
<th colspan="100"></th>
</tr>
{% for item in stats.items %}
<tr>
<td>{{ item.date|date:"H:i" }}</td>
{# TODO: logs #}
<td>{{ item.program.name }}</td>
{% for tag,count in item.tags %}
<td>{{ tag }}: {{ count }}</td>
{% endfor %}
</tr>
{% endfor %}
<tr>
<td>{{ stats.date|date:'d/m/Y' }}</td>
<td>{% trans "Total and average" %} ({{ stats.tracks_count }})</td>
{% for tag, count, average in stats.tags %}
<td>{{ tag }}: <b>{{ count }} / {{ average|floatformat }}%</b></td>
{% endfor %}
</tr>
</table>
</section>
{% endfor %}
</div>

View File

@ -4,6 +4,7 @@ import aircox.views as views
urls = [ urls = [
url(r'^on_air', views.on_air, name='aircox.on_air'), url(r'^on_air', views.on_air, name='aircox.on_air'),
url(r'^monitor', views.Monitor.as_view(), name='aircox.monitor') url(r'^monitor', views.Monitor.as_view(), name='aircox.monitor'),
url(r'^stats', views.StatisticsView.as_view(), name='aircox.stats'),
] ]

View File

@ -1,5 +1,7 @@
import json import json
import datetime
from django.db.models import Count
from django.views.generic.base import View, TemplateResponseMixin from django.views.generic.base import View, TemplateResponseMixin
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
@ -121,6 +123,92 @@ class Monitor(View,TemplateResponseMixin,LoginRequiredMixin):
return HttpResponse('') return HttpResponse('')
class StatisticsView(View,TemplateResponseMixin,LoginRequiredMixin):
template_name = 'aircox/controllers/stats.html'
class Stats:
station = None
date = None
items = None
"""
Log or Diffusion object that has been diffused by date. These
objects have extra fields:
- tags: [ (tag_name, tag_count), ...]
- tracks_count: total count of tracks
"""
tags = None
"""
Total of played track's tags: [(tag_name, tag_count, tag_average), ...]
on the station for the given date. Note: tag_average is in %
"""
tracks_count = 0
def __init__(self, **kwargs):
self.items = []
self.tags = []
self.__dict__.update(kwargs)
def get_stats(self, station, date):
"""
Return statistics for the given station and date.
"""
items = station.on_air(date)
stats = self.Stats(station = station, items = items, date = date)
sums = {}
total = 0
for item in items:
qs = models.Track.objects.get_for(item)
item.tracks = qs
item.tracks_count = qs.count()
qs = qs.values('tags__name').annotate(count = Count('tags__name')) \
.order_by('tags__name')
item.tags = [
(q['tags__name'], q['count'])
for q in qs if q['tags__name']
]
for name, count in item.tags:
sums[name] = (sums.get(name) or 0) + count
total += item.tracks_count
stats.tracks_count = total
stats.tags = [
(name, count, count / total * 100)
for name, count in sums.items()
]
stats.tags.sort(key=lambda s: s[0])
return stats
def get_context_data(self, **kwargs):
context = {}
date = datetime.date.today()
try:
GET = self.request.GET
year = int(GET["year"]) if 'year' in GET else date.year
month = int(GET["month"]) if 'month' in GET else date.month
day = int(GET["day"]) if 'day' in GET else date.day
date = datetime.date(year, month, day)
except:
pass
context["statistics"] = [
self.get_stats(station, date)
for station in models.Station.objects.all()
]
return context
def get(self, request = None, **kwargs):
if not request.user.is_active:
return Http404()
self.request = request
context = self.get_context_data(**kwargs)
return render(request, self.template_name, context)