add manager for programs.Diffusion + adapt; list_by_date's date urls; website's section Log algorithm

This commit is contained in:
bkfox 2016-07-18 18:29:24 +02:00
parent 6b7255112d
commit e0edd7fc7d
5 changed files with 127 additions and 113 deletions

View File

@ -1,3 +1,5 @@
import datetime
from django.db import models
from django.utils import timezone as tz
from django.conf.urls import url
@ -176,17 +178,13 @@ class DateRoute(Route):
]
@classmethod
def get_queryset(cl, model, request, year, month, day,
attr='date', **kwargs):
def get_queryset(cl, model, request, year, month, day, **kwargs):
"""
* request: optional
* attr: name of the attribute to check the date against
"""
return model.objects.filter(**{
attr + '__year': int(year),
attr + '__month': int(month),
attr + '__day': int(day)
})
date = datetime.date(int(year), int(month), int(day))
return model.objects.filter(date__contains = date)
@classmethod
def get_title(cl, model, request, year, month, day, **kwargs):

View File

@ -108,7 +108,7 @@ class Monitor:
.order_by('date').last()
if not diff_log or \
not diff_log.related.is_date_in_my_range(now):
not diff_log.related.is_date_in_range(now):
return None, []
# sound has switched? assume it has been (forced to) stopped
@ -138,10 +138,8 @@ class Monitor:
now = tz.make_aware(tz.datetime.now())
args = {'start__gt': diff.start } if diff else {}
diff = programs.Diffusion.get(
now, now = True,
diff = programs.Diffusion.objects.get_at(now).filter(
type = programs.Diffusion.Type.normal,
sound__type = programs.Sound.Type.archive,
sound__removed = False,
**args

View File

@ -27,7 +27,6 @@
- admin cms
-> sections/actions and django decorator?
-> enhance calendar with possible actions?
- sections id generator
- website:
- diffusions:
@ -39,7 +38,6 @@
- remove from playing playlist -> stop
- date_by_list:
- sections' url
- list of played diffusions and tracks when non-stop;
# Long term TODO
- automatic cancel of passed diffusion based on logs?

View File

@ -1,3 +1,4 @@
import datetime
import os
import shutil
import logging
@ -36,7 +37,7 @@ def date_or_default(date, no_time = False):
Return date or default value (now) if not defined, and remove time info
if date_only is True
"""
date = date or tz.datetime.today()
date = date or tz.now()
if not tz.is_aware(date):
date = tz.make_aware(date)
if no_time:
@ -576,6 +577,49 @@ class Program(Nameable):
return qs[0] if qs else None
class DiffusionManager(models.Manager):
def get_at(self, date = None):
"""
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 issubclass(type(date), datetime.date):
return self.filter(
models.Q(start__contains = date) | \
models.Q(end__contains = date)
)
return self.filter(
models.Q(start__lte = date, end__gte = date) |
# FIXME: should not be here?
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):
"""
A Diffusion is an occurrence of a Program that is scheduled on the
@ -594,6 +638,8 @@ class Diffusion(models.Model):
- cancel: the diffusion has been canceled
- stop: the diffusion has been manually stopped
"""
objects = DiffusionManager()
class Type(IntEnum):
normal = 0x00
unconfirmed = 0x01
@ -642,52 +688,13 @@ class Diffusion(models.Model):
return sounds.filter(type = Sound.Type.archive, removed = False). \
order_by('path')
@classmethod
def get(cl, date = None,
now = False, next = False, prev = False,
queryset = None,
**filter_args):
"""
Return a queryset of diffusions, depending on value of now/next/prev
- now: that have date in their start-end range or start after
- next: that start after date
- prev: that end before date
If queryset is not given, use self.objects.all
Diffusions are ordered by +start for now and next; -start for prev
"""
#FIXME: conflicts? ( + calling functions)
date = date_or_default(date)
if queryset is None:
queryset = cl.objects
if now:
return queryset.filter(
models.Q(start__lte = date,
end__gte = date) |
models.Q(start__gte = date),
**filter_args
).order_by('start')
if next:
return queryset.filter(
start__gte = date,
**filter_args
).order_by('start')
if prev:
return queryset.filter(
end__lte = date,
**filter_args
).order_by('-start')
def is_date_in_my_range(self, date = None):
def is_date_in_range(self, date = None):
"""
Return true if the given date is in the diffusion's start-end
range.
"""
return self.start < date_or_default(date) < self.end
date = date or tz.now()
return self.start < date < self.end
def get_conflicts(self):
"""

View File

@ -1,9 +1,11 @@
import json
import datetime
from django.utils import timezone as tz
from django.utils.translation import ugettext as _, ugettext_lazy
import aircox.programs.models as programs
import aircox.controllers.models as controllers
import aircox.cms.models as cms
import aircox.cms.routes as routes
import aircox.cms.sections as sections
@ -30,12 +32,12 @@ class Player(sections.Section):
@expose
def on_air(cl, request):
qs = programs.Diffusion.get(
now = True,
now = tz.now()
qs = programs.Diffusion.objects.get_at(now).filter(
type = programs.Diffusion.Type.normal
)
if not qs or not qs[0].is_date_in_my_range():
if not qs or not qs[0].is_date_in_range():
return {}
qs = qs[0]
@ -214,7 +216,8 @@ class Sounds(sections.List):
class ListByDate(sections.List):
"""
List that add a navigation by date in its header.
List that add a navigation by date in its header. It aims to be
used with DateRoute.
"""
template_name = 'aircox/website/list_by_date.html'
message_empty = ''
@ -253,15 +256,19 @@ class ListByDate(sections.List):
return [ first + tz.timedelta(days=i) for i in range(0, self.nav_days) ]
def date_or_default(self):
"""
Return self.date or create a date if needed, using kwargs'
year, month, day attributes if exists (otherwise, use today)
"""
if self.date:
return self.date
return datetime.date(self.date)
elif self.kwargs and 'year' in self.kwargs:
return tz.datetime(year = int(self.kwargs['year']),
month = int(self.kwargs['month']),
day = int(self.kwargs['day']),
hour = 0, minute = 0, second = 0,
microsecond = 0)
return tz.now()
return datetime.date(
year = int(self.kwargs['year']),
month = int(self.kwargs['month']),
day = int(self.kwargs['day'])
)
return datetime.date.today()
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
@ -270,6 +277,7 @@ class ListByDate(sections.List):
dates = [ (date, self.get_date_url(date))
for date in self.nav_dates(date) ]
# FIXME
next_week = dates[-1][0] + tz.timedelta(days=1)
next_week = self.get_date_url(next_week)
@ -289,18 +297,22 @@ class ListByDate(sections.List):
@staticmethod
def get_date_url(date):
"""
return a url to the list for the given date
return an url for the given date
"""
return self.view.website.reverse(
model = self.model, route = routes.DateRoute,
year = date.year, month = date.month, day = date.day,
)
@property
def url(self):
return None
class Schedule(Diffusions,ListByDate):
"""
Render a list of diffusions in the form of a schedule
"""
model = models.Diffusion
fields = [ 'time', 'image', 'title', 'content', 'info', 'actions' ]
truncate = 30
@ -310,10 +322,7 @@ class Schedule(Diffusions,ListByDate):
def get_object_list(self):
date = self.date_or_default()
diffs = routes.DateRoute.get_queryset(
programs.Diffusion, None, date.year, date.month, date.day,
attr = 'start'
).order_by('start')
diffs = programs.Diffusion.objects.get_at(date).order_by('start')
return models.Diffusion.objects.get_for(diffs, create = True)
@staticmethod
@ -329,54 +338,58 @@ class Schedule(Diffusions,ListByDate):
class Logs(ListByDate):
"""
Return a list of played stream sounds and diffusions.
Print a list of played stream tracks and diffusions.
Note that for the moment we don't print if the track has been
partially hidden by a scheduled diffusion
"""
model = controllers.Log
@staticmethod
def make_item(log):
def make_item(item):
"""
Return a list of items to add to the playlist.
Only support Log related to a Track and programs.Diffusion
"""
if issubclass(type(log.related), programs.Diffusion):
diff = log.related
post = models.Diffusion.objects.filter(related = diff).first() \
or models.Program.objects.filter(related = diff.program).first() \
or ListItem(title = diff.program.name)
post.date = diff.start
return post
if issubclass(type(log.related), programs.Track):
track = log.related
post = ListItem(
title = '{artist} &#8212; {name}'.format(
artist = track.artist,
name = track.name,
),
date = log.date,
content = track.info,
info = '',
if issubclass(type(item), programs.Diffusion):
return models.Diffusion.objects.get_for(
item, create = True, save = False
)
track = log.related
post = ListItem(
title = '{artist} &#8212; {name}'.format(
artist = track.artist,
name = track.name,
),
date = log.date,
content = track.info,
info = '',
)
return post
@staticmethod
def make_diff(diff):
pass
def get_object_list(self):
return []
station = self.view.website.station
qs = station.get_played(
models = [ programs.Diffusion, programs.Track ],
).filter(
date__year = int(year), date__month = int(month),
date__day = int(day)
)
# TODO for each, exclude if there is a corresponding diffusion
# (that has not been logged)
# if diff and diff != last_diff:
# r.append(cl.make_item
# return [ cl.make_item(log) for log in qs ]
date = self.date_or_default()
if date > datetime.date.today():
return []
logs = controllers.Log.get_for(model = programs.Track) \
.filter(date__contains = date) \
.order_by('date')
diffs = programs.Diffusion.objects.get_at(date) \
.filter(type = programs.Diffusion.Type.normal)
items = []
prev_diff = None
for diff in diffs:
logs_ = logs.filter(date__gt = prev_diff.end,
date__lt = diff.start) \
if prev_diff else \
logs.filter(date__lt = diff.start)
prev_diff = diff
items.extend(logs_)
items.append(diff)
return list(map(self.make_item, items))
@staticmethod
def get_date_url(date):
return 'TODO'