fix and optimize

This commit is contained in:
bkfox 2017-06-29 21:21:28 +02:00
parent 8a129da46a
commit 60cbf18942
9 changed files with 176 additions and 193 deletions

View File

@ -183,8 +183,8 @@ class StationAdmin(admin.ModelAdmin):
@admin.register(Log) @admin.register(Log)
class LogAdmin(admin.ModelAdmin): class LogAdmin(admin.ModelAdmin):
list_display = ['id', 'date', 'station', 'source', 'type', 'comment', 'related'] list_display = ['id', 'date', 'station', 'source', 'type', 'comment', 'diffusion', 'sound', 'track']
list_filter = ['date', 'source', 'related_type'] list_filter = ['date', 'source', 'diffusion', 'sound', 'track']
admin.site.register(Port) admin.site.register(Port)

View File

@ -15,7 +15,7 @@ from django.conf import settings as main_settings
from django.core.management.base import BaseCommand, CommandError from django.core.management.base import BaseCommand, CommandError
from django.utils import timezone as tz from django.utils import timezone as tz
from aircox.models import Station, Diffusion, Track, Sound, Log from aircox.models import Station, Diffusion, Track, Sound, Log #, DiffusionLog, SoundLog
class Tracer: class Tracer:
@ -92,17 +92,18 @@ class Monitor:
if not current_sound or not current_source: if not current_sound or not current_source:
return return
log = Log.objects.get_for(self.station, model = Sound) \ log = Log.objects.station(self.station, sound__isnull = False) \
.select_related('sound') \
.order_by('date').last() .order_by('date').last()
# only streamed # only streamed ns
if log and (log.related and not log.related.diffusion): if log and not log.sound.diffusion:
self.trace_sound_tracks(log) self.trace_sound_tracks(log)
# TODO: expiration # TODO: expiration
if log and (log.source == current_source.id and \ if log and (log.source == current_source.id and \
log.related and log.sound and
log.related.path == current_sound): log.sound.path == current_sound):
return return
sound = Sound.objects.filter(path = current_sound) sound = Sound.objects.filter(path = current_sound)
@ -110,7 +111,7 @@ class Monitor:
type = Log.Type.play, type = Log.Type.play,
source = current_source.id, source = current_source.id,
date = tz.now(), date = tz.now(),
related = sound[0] if sound else None, sound = sound[0] if sound else None,
# keep sound path (if sound is removed, we keep that info) # keep sound path (if sound is removed, we keep that info)
comment = current_sound, comment = current_sound,
) )
@ -120,11 +121,12 @@ class Monitor:
Log tracks for the given sound (for streamed programs); Called by Log tracks for the given sound (for streamed programs); Called by
self.trace self.trace
""" """
logs = Log.objects.get_for(self.station, model = Track) \ logs = Log.objects.station(self.station,
.filter(pk__gt = log.pk) track__isnull = False,
logs = [ log.related_id for log in logs ] pk__gt = log.pk) \
.values_list('sound__pk', flat = True)
tracks = Track.objects.get_for(object = log.related) \ tracks = Track.objects.get_for(object = log.sound) \
.filter(in_seconds = True) .filter(in_seconds = True)
if tracks and len(tracks) == len(logs): if tracks and len(tracks) == len(logs):
return return
@ -138,7 +140,7 @@ class Monitor:
type = Log.Type.play, type = Log.Type.play,
source = log.source, source = log.source,
date = pos, date = pos,
related = track, track = track,
comment = track, comment = track,
) )
@ -157,7 +159,7 @@ class Monitor:
continue continue
playlist = source.program.sound_set.all() \ playlist = source.program.sound_set.all() \
.values_list('path', flat = True) .values_list('path', flat = True)
source.playlist = playlist source.playlist = list(playlist)
def trace_canceled(self): def trace_canceled(self):
""" """
@ -171,18 +173,18 @@ class Monitor:
type = Diffusion.Type.normal, type = Diffusion.Type.normal,
sound__type = Sound.Type.archive, sound__type = Sound.Type.archive,
) )
logs = station.played(models = Diffusion) logs = station.played(diffusion__isnull = False)
date = tz.now() - datetime.timedelta(seconds = self.cancel_timeout) date = tz.now() - datetime.timedelta(seconds = self.cancel_timeout)
for diff in diffs: for diff in diffs:
if logs.filter(related = diff): if logs.filter(diffusion = diff):
continue continue
if diff.start < now: if diff.start < now:
diff.type = Diffusion.Type.canceled diff.type = Diffusion.Type.canceled
diff.save() diff.save()
self.log( self.log(
type = Log.Type.other, type = Log.Type.other,
related = diff, diffusion = diff,
comment = 'Diffusion canceled after {} seconds' \ comment = 'Diffusion canceled after {} seconds' \
.format(self.cancel_timeout) .format(self.cancel_timeout)
) )
@ -195,29 +197,29 @@ class Monitor:
station = self.station station = self.station
now = tz.now() now = tz.now()
log = station.played(models = Diffusion).order_by('date').last() log = station.played(diffusion__isnull = False) \
if not log or not log.related.is_date_in_range(now): .select_related('diffusion') \
.order_by('date').last()
if not log or not log.diffusion.is_date_in_range(now):
# not running anymore # not running anymore
return None, [] return None, []
# sound has switched? assume it has been (forced to) stopped # last sound source change: end of file reached or forced to stop
sounds = station.played(models = Sound) \ sounds = station.played(sound__isnull = False) \
.filter(date__gte = log.date) \ .filter(date__gte = log.date) \
.order_by('date') .order_by('date')
# last sound source change: end of file reached
if sounds.count() and sounds.last().source != log.source: if sounds.count() and sounds.last().source != log.source:
# diffusion is finished: end of sound file reached
return None, [] return None, []
# last diff is still playing: get remaining playlist # last diff is still playing: get remaining playlist
sounds = sounds \ sounds = sounds \
.filter(source = log.source, pk__gt = diff_log.pk) \ .filter(source = log.source, pk__gt = log.pk) \
.exclude(related__type = Sound.Type.removed) .exclude(sound__type = Sound.Type.removed)
.values_list('related__path', flat = True)
remaining = log.related.get_archives().exclude(path__in = sounds)
return log.related, remaining remaining = log.diffusion.get_archives().exclude(pk__in = sounds) \
.values_list('path', flat = True)
return log.diffusion, list(remaining)
def __next_diff(self, diff): def __next_diff(self, diff):
""" """
@ -230,10 +232,10 @@ class Monitor:
kwargs = {'start__gte': diff.end } if diff else {} kwargs = {'start__gte': diff.end } if diff else {}
diff = Diffusion.objects \ diff = Diffusion.objects \
.at(station, now) \ .at(station, now) \
.filter(type = Diffusion.Type.normal, .filter(type = Diffusion.Type.normal, **kwargs) \
sound_type = Sound.Type.archive, **kwargs) \ .distinct().order_by('start')
.distinct().order_by('start').first() diff = diff.first()
return diff return (diff, diff and diff.playlist or [])
def handle_pl_sync(self, source, playlist, diff = None, date = None): def handle_pl_sync(self, source, playlist, diff = None, date = None):
""" """
@ -245,28 +247,30 @@ class Monitor:
dealer.playlist = playlist dealer.playlist = playlist
if diff and not diff.is_live(): if diff and not diff.is_live():
self.log(type = Log.Type.load, source = source.id, self.log(type = Log.Type.load, source = source.id,
related = diff, date = date) diffusion = diff, date = date)
def handle_diff_start(self, source, diff, date): def handle_diff_start(self, source, diff, date):
""" """
Enable dealer in order to play a given diffusion if required, Enable dealer in order to play a given diffusion if required,
handle start of diffusion handle start of diffusion
""" """
if not diff or not diff.start <= now: if not diff or diff.start > date:
return return
# live: just log it # live: just log it
if diff.is_live(): if diff.is_live():
if not Log.get_for(object = diff).count(): diff_ = Log.objects.station(self.station) \
.filter(diffusion = diff)
if not diff_.count():
self.log(type = Log.Type.live, source = source.id, self.log(type = Log.Type.live, source = source.id,
related = diff, date = date) diffusion = diff, date = date)
return return
# enable dealer # enable dealer
if not dealer.active: if not dealer.active:
dealer.active = True dealer.active = True
self.log(type = Log.Type.play, source = source.id, self.log(type = Log.Type.play, source = source.id,
related = diff, date = date) diffusion = diff, date = date)
def handle(self): def handle(self):
""" """
@ -280,15 +284,15 @@ class Monitor:
now = tz.now() now = tz.now()
# current and next diffs # current and next diffs
current_diff, current_pl = self.__current_diff() current_diff, remaining_pl = self.__current_diff()
next_diff, next_pl = self.__next_diff(diff) next_diff, next_pl = self.__next_diff(current_diff)
# playlist # playlist
dealer.active = bool(current_pl) dealer.active = bool(remaining_pl)
playlist = current_pl + next_pl playlist = remaining_pl + next_pl
self.handle_pl_sync(dealer, playlist, next_diff, now) self.handle_pl_sync(dealer, playlist, next_diff, now)
self.handle_diff_start(dealer, next_diff) self.handle_diff_start(dealer, next_diff, now)
class Command (BaseCommand): class Command (BaseCommand):

View File

@ -50,7 +50,6 @@ class RelatedManager(models.Manager):
qs = qs.filter(related_id = object.pk) qs = qs.filter(related_id = object.pk)
return qs return qs
class Related(models.Model): class Related(models.Model):
""" """
Add a field "related" of type GenericForeignKey, plus utilities. Add a field "related" of type GenericForeignKey, plus utilities.
@ -148,7 +147,6 @@ class Track(Related):
verbose_name = _('Track') verbose_name = _('Track')
verbose_name_plural = _('Tracks') verbose_name_plural = _('Tracks')
# #
# Station related classes # Station related classes
# #
@ -180,7 +178,7 @@ class Station(Nameable):
__dealer = None __dealer = None
__streamer = None __streamer = None
def __prepare(self): def __prepare_controls(self):
import aircox.controllers as controllers import aircox.controllers as controllers
if not self.__streamer: if not self.__streamer:
self.__streamer = controllers.Streamer(station = self) self.__streamer = controllers.Streamer(station = self)
@ -215,12 +213,12 @@ class Station(Nameable):
""" """
Audio sources, dealer included Audio sources, dealer included
""" """
self.__prepare() self.__prepare_controls()
return self.__sources return self.__sources
@property @property
def dealer(self): def dealer(self):
self.__prepare() self.__prepare_controls()
return self.__dealer return self.__dealer
@property @property
@ -228,86 +226,25 @@ class Station(Nameable):
""" """
Audio controller for the station Audio controller for the station
""" """
self.__prepare() self.__prepare_controls()
return self.__streamer return self.__streamer
def played(self, models, archives = True, include_live = True): def played(self, *args, **kwargs):
""" """
Call Log.objects.played for this station Call Log.objects.played for this station
""" """
return Log.objects.played(self, models, archives, include_live) return Log.objects.played(self, *args, **kwargs)
@staticmethod
def __mix_logs_and_diff(diffs, logs, count = 0):
"""
Mix together logs and diffusion items of the same day,
ordered by their date.
Diffs and Logs are assumed to be ordered by -date, and so is
the resulting list
"""
# we fill a list with diff and retrieve logs that happened between
# each to put them too there.
# we do the algorithm in the reverse way in order to be able to limit
# process calculations using count if needed.
diff_ = None
now = tz.now()
items = []
logs = logs.order_by('-date')
for diff in diffs.order_by('-start'):
if diff_:
logs_ = logs.filter(date__gt = diff.end, date__lt = diff_.start)
else:
logs_ = logs.filter(date__gt = diff.end)
if diff.end < now:
# a log can be started before the end of the diffusion and still
# is running. We can't say if it has been properly finished
# before the end of the diffusion, but we assume that in most
# cases this is true.
# We just check if there is some other log after this partial
# one.
partial = logs.filter(
date__gt = diff.start, date__lt = diff.end
).last()
if partial:
next_log = logs.filter(pk__gt = partial.pk).first()
if not next_log or next_log.date > diff.end:
partial.date = diff.end
logs_ = list(logs_) + [partial]
# append to list
diff_ = diff
items.extend(logs_)
items.append(diff)
if count and len(items) >= count:
break
if diff_:
if count and len(items) >= count:
return items[:count]
logs_ = logs.filter(date__lt = diff_.start)
else:
logs_ = logs.all()
items.extend(logs_)
return items[:count] if count else items
def on_air(self, date = None, count = 0): def on_air(self, date = None, count = 0):
""" """
Return a list of what happened on air, based on logs and Return a queryset of what happened on air, based on logs and
diffusions informations. The list is sorted by -date. diffusions informations. The queryset is sorted by -date.
* date: only for what happened on this date; * date: only for what happened on this date;
* count: number of items to retrieve if not zero; * count: number of items to retrieve if not zero;
If date is not specified, count MUST be set to a non-zero value. If date is not specified, count MUST be set to a non-zero value.
Be careful with what you which for: the result is a plain list. Be careful with what you which for: the result is a plain list.
The list contains:
* track logs: for the streamed programs;
* diffusion: for the scheduled diffusions;
""" """
# FIXME: as an iterator? # FIXME: as an iterator?
# TODO argument to get sound instead of tracks # TODO argument to get sound instead of tracks
@ -315,21 +252,39 @@ class Station(Nameable):
raise ValueError('at least one argument must be set') raise ValueError('at least one argument must be set')
# FIXME can be a potential source of bug # FIXME can be a potential source of bug
if date:
date = utils.cast_date(date, to_datetime = False)
if date and date > datetime.date.today(): if date and date > datetime.date.today():
return [] return []
if date: if date:
logs = Log.objects.at_for(self, date, model = Track) logs = Log.objects.at(self, date)
diffs = Diffusion.objects.at(self, date) diffs = Diffusion.objects.at(self, date, type = Diffusion.Type.normal) \
.order_by('-start')
else: else:
logs = Log.objects.get_for(self, model = Track) logs = Log.objects
diffs = Diffusion.objects diffs = Diffusion.objects.filter(type = Diffusion.Type.normal,
logs = logs.filter(station = self) start__lte = tz.now()) \
.order_by('-start')[:count]
diffs = diffs.filter(program__station = self) \ q = models.Q(diffusion__isnull = False) | \
.filter(type = Diffusion.Type.normal) \ models.Q(track__isnull = False)
.filter(start__lte = tz.now()) logs = logs.filter(q).order_by('-date')
return self.__mix_logs_and_diff(diffs, logs, count)
# filter out tracks played when there was a diffusion
n = 0
q = models.Q()
for diff in diffs:
if count and n >= count:
break
q = q | models.Q(date__gte = diff.start, date__lte = diff.end)
n += 1
logs = logs.exclude(q, diffusion__isnull = True)
if count:
logs = logs[:count]
return logs
def save(self, make_sources = True, *args, **kwargs): def save(self, make_sources = True, *args, **kwargs):
if not self.path: if not self.path:
@ -348,9 +303,9 @@ class Station(Nameable):
class ProgramManager(models.Manager): class ProgramManager(models.Manager):
def station(self, station, qs = None): def station(self, station, qs = None, **kwargs):
qs = self if qs is None else qs qs = self if qs is None else qs
return qs.filter(station = station) return qs.filter(station = station, **kwargs)
class Program(Nameable): class Program(Nameable):
""" """
@ -730,11 +685,11 @@ class Schedule(models.Model):
class DiffusionManager(models.Manager): class DiffusionManager(models.Manager):
def station(self, station, qs = None): def station(self, station, qs = None, **kwargs):
qs = self if qs is None else qs qs = self if qs is None else qs
return qs.filter(program__station = station) return qs.filter(program__station = station, **kwargs)
def at(self, station, date = None, next = False, qs = None): def at(self, station, date = None, next = False, qs = None, **kwargs):
""" """
Return diffusions occuring at the given date, ordered by +start Return diffusions occuring at the given date, ordered by +start
@ -770,7 +725,7 @@ class DiffusionManager(models.Manager):
if next: if next:
# include also diffusions of the next day # include also diffusions of the next day
filters |= models.Q(start__gte = start) filters |= models.Q(start__gte = start)
qs = qs.filter(filters) qs = qs.filter(filters, **kwargs)
return self.station(station, qs).order_by('start').distinct() return self.station(station, qs).order_by('start').distinct()
def after(self, station, date = None, qs = None): def after(self, station, date = None, qs = None):
@ -867,7 +822,12 @@ class Diffusion(models.Model):
""" """
List of archives' path; uses get_archives List of archives' path; uses get_archives
""" """
return self.get_archives().values_list('path', flat = True) playlist = self.get_archives().values_list('path', flat = True)
return list(playlist)
def is_live(self):
return self.type == self.Type.normal and \
not self.get_archives().count()
def get_archives(self): def get_archives(self):
""" """
@ -1229,63 +1189,51 @@ class Port (models.Model):
) )
class LogManager(RelatedManager): class LogManager(models.Manager):
def station(self, station, qs = None): def station(self, station, qs = None, **kwargs):
qs = self if qs is None else qs qs = self if qs is None else qs
return qs.filter(station = station) return qs.filter(station = station, **kwargs)
def get_for(self, station, *args, **kwargs): def _at(self, date = None, qs = None, **kwargs):
qs = super().get_for(*args, **kwargs)
return self.station(station, qs) if station else qs
def _at(self, date = None, qs = None):
start, end = utils.date_range(date) start, end = utils.date_range(date)
qs = self if qs is None else qs qs = self if qs is None else qs
return qs.filter(date__gte = start, return qs.filter(date__gte = start, date__lte = end, **kwargs)
date__lte = end)
def at(self, station = None, date = None, qs = None): def at(self, station = None, date = None, qs = None, **kwargs):
""" """
Return a queryset of logs that have the given date Return a queryset of logs that have the given date
in their range. in their range.
""" """
qs = self._at(date, qs) qs = self._at(date, qs, **kwargs)
return self.station(station, qs) if station else qs return self.station(station, qs) if station else qs
def at_for(self, station, date, object = None, model = None, qs = None): def played(self, station, archives = True, include_live = True,
""" **kwargs):
Return a queryset of logs that occured at the given date
for the given model or object.
"""
qs = self.get_for(station, object, model, qs)
return self._at(date, qs)
def played(self, station, models, archives = True, include_live = True):
""" """
Return a queryset of the played elements' log for the given Return a queryset of the played elements' log for the given
station and model. This queryset is ordered by date ascending station and model. This queryset is ordered by date ascending
* station: related station * station: related station
* models: a model or a list of models
* archives: if false, exclude log of diffusion's archives from * archives: if false, exclude log of diffusion's archives from
the queryset; the queryset;
* include_live: include diffusion that have no archive
* kwargs: extra filter kwargs
""" """
if include_live: if include_live:
qs = self.get_for(station, model = models) \ qs = self.filter(type__in = (Log.Type.play, Log.Type.live),
.filter(type__in = (Log.Type.play, Log.Type.live)) **kwargs)
else: else:
qs = self.get_for(station, model = models) \ qs = self.filter(type = Log.Type.play, **kwargs)
.filter(type = Log.Type.play)
if not archives and station.dealer: if not archives and station.dealer:
qs = qs.exclude( qs = qs.exclude(
source = station.dealer.id, source = station.dealer.id,
related_type = ContentType.objects.get_for_model(Sound) sound__isnull = False
) )
return qs.order_by('date') return qs.order_by('date')
class Log(Related): class Log(models.Model):
""" """
Log sounds and diffusions that are played on the station. Log sounds and diffusions that are played on the station.
@ -1337,6 +1285,7 @@ class Log(Related):
date = models.DateTimeField( date = models.DateTimeField(
_('date'), _('date'),
default=tz.now, default=tz.now,
db_index = True,
) )
comment = models.CharField( comment = models.CharField(
_('comment'), _('comment'),
@ -1344,6 +1293,25 @@ class Log(Related):
blank = True, null = True, blank = True, null = True,
) )
diffusion = models.ForeignKey(
Diffusion,
verbose_name = _('Diffusion'),
blank = True, null = True,
db_index = True,
)
sound = models.ForeignKey(
Sound,
verbose_name = _('Sound'),
blank = True, null = True,
db_index = True,
)
track = models.ForeignKey(
Track,
verbose_name = _('Track'),
blank = True, null = True,
db_index = True,
)
objects = LogManager() objects = LogManager()
@property @property
@ -1351,12 +1319,16 @@ class Log(Related):
""" """
Calculated end using self.related informations Calculated end using self.related informations
""" """
if self.related_type == Diffusion: if self.diffusion:
return self.related.end return self.diffusion.end
if self.related_type == Sound: if self.sound:
return self.date + to_timedelta(self.duration) return self.date + to_timedelta(sound.duration)
return self.date return self.date
@property
def related(self):
return self.diffusion or self.sound or self.track
def is_expired(self, date = None): def is_expired(self, date = None):
""" """
Return True if the log is expired. Note that it only check Return True if the log is expired. Note that it only check
@ -1367,11 +1339,19 @@ class Log(Related):
return self.end < date return self.end < date
def print(self): def print(self):
r = []
if self.diffusion:
r.append('diff: ' + str(self.diffusion_id))
if self.sound:
r.append('sound: ' + str(self.sound_id))
if self.track:
r.append('track: ' + str(self.track_id))
logger.info('log #%s: %s%s', logger.info('log #%s: %s%s',
str(self), str(self),
self.comment or '', self.comment or '',
' -- {} #{}'.format(self.related_type, self.related_id) ' (' + ', '.join(r) + ')' if r else ''
if self.related else ''
) )
def __str__(self): def __str__(self):
@ -1379,4 +1359,3 @@ class Log(Related):
self.pk, self.date.strftime('%Y/%m/%d %H:%M'), self.source self.pk, self.date.strftime('%Y/%m/%d %H:%M'), self.source
) )

View File

@ -40,12 +40,12 @@ def on_air(request):
else: else:
station = stations.stations.first() station = stations.stations.first()
last = station.on_air(count = 10) on_air = station.on_air(count = 10).select_related('track','diffusion')
if not last: if not on_air.count():
return HttpResponse('') return HttpResponse('')
last = last[0] last = on_air.last()
if type(last) == models.Log: if last.track:
last = { last = {
'type': 'track', 'type': 'track',
'artist': last.related.artist, 'artist': last.related.artist,
@ -54,11 +54,12 @@ def on_air(request):
} }
else: else:
try: try:
diff = last.diffusion
publication = None publication = None
if cms: if cms:
publication = \ publication = \
cms.DiffusionPage.objects.filter( cms.DiffusionPage.objects.filter(
diffusion = last.initial or last).first() or \ diffusion = diff.initial or diff).first() or \
cms.ProgramPage.objects.filter( cms.ProgramPage.objects.filter(
program = last.program).first() program = last.program).first()
except: except:
@ -66,8 +67,8 @@ def on_air(request):
last = { last = {
'type': 'diffusion', 'type': 'diffusion',
'title': last.program.name, 'title': diff.program.name,
'date': last.start, 'date': diff.start,
'url': publication.specific.url if publication else None, 'url': publication.specific.url if publication else None,
} }

View File

@ -64,7 +64,7 @@ class Command (BaseCommand):
initial__isnull = True initial__isnull = True
).exclude(type = Diffusion.Type.unconfirmed) ).exclude(type = Diffusion.Type.unconfirmed)
for diffusion in qs: for diffusion in qs:
if not diffusion.program.page.count(): if not diffusion.program.page:
if not hasattr(diffusion.program, '__logged_diff_error'): if not hasattr(diffusion.program, '__logged_diff_error'):
logger.warning( logger.warning(
'the program {} has no page; skip the creation of ' 'the program {} has no page; skip the creation of '
@ -80,7 +80,7 @@ class Command (BaseCommand):
page = DiffusionPage.from_diffusion( page = DiffusionPage.from_diffusion(
diffusion, live = False diffusion, live = False
) )
diffusion.program.page.first().add_child(instance = page) diffusion.program.page.add_child(instance = page)
except: except:
import sys import sys
e = sys.exc_info()[0] e = sys.exc_info()[0]

View File

@ -452,10 +452,8 @@ class ProgramPage(Publication):
def diffs_to_page(self, diffs): def diffs_to_page(self, diffs):
for diff in diffs: for diff in diffs:
if diff.page.count(): if not diff.page:
diff.page_ = diff.page.first() diff.page = ListItem(
else:
diff.page_ = ListItem(
title = '{}, {}'.format( title = '{}, {}'.format(
self.program.name, diff.date.strftime('%d %B %Y') self.program.name, diff.date.strftime('%d %B %Y')
), ),
@ -464,7 +462,7 @@ class ProgramPage(Publication):
date = diff.start, date = diff.start,
) )
return [ return [
diff.page_ for diff in diffs if diff.page_.live diff.page for diff in diffs if diff.page.live
] ]
@property @property
@ -560,8 +558,8 @@ class DiffusionPage(Publication):
'title': '{}, {}'.format( 'title': '{}, {}'.format(
diff.program.name, tz.localtime(diff.date).strftime('%d %B %Y') diff.program.name, tz.localtime(diff.date).strftime('%d %B %Y')
), ),
'cover': (diff.program.page.count() and \ 'cover': (diff.program.page and \
diff.program.page.first().cover) or None, diff.program.page.cover) or None,
'date': diff.start, 'date': diff.start,
} }
model_kwargs.update(kwargs) model_kwargs.update(kwargs)
@ -637,7 +635,7 @@ class DiffusionPage(Publication):
if self.diffusion: if self.diffusion:
# set publish_as # set publish_as
if not self.pk: if not self.pk:
self.publish_as = self.diffusion.program.page.first() self.publish_as = self.diffusion.program.page
# sync date # sync date
self.date = self.diffusion.start self.date = self.diffusion.start
@ -777,8 +775,9 @@ class LogsPage(DatedListPage):
logs = [] logs = []
for date in context['nav_dates']['dates']: for date in context['nav_dates']['dates']:
items = [ SectionLogsList.as_item(item) items = self.station.on_air(date = date) \
for item in self.station.on_air(date = date) ] .select_related('track','diffusion')
items = [ SectionLogsList.as_item(item) for item in items ]
logs.append( logs.append(
(date, reversed(items) if self.reverse else items) (date, reversed(items) if self.reverse else items)
) )

View File

@ -957,16 +957,16 @@ class SectionLogsList(SectionItem):
Supports: Log/Track, Diffusion Supports: Log/Track, Diffusion
""" """
from aircox_cms.models import DiffusionPage from aircox_cms.models import DiffusionPage
if type(log) == aircox.models.Diffusion: if log.diffusion:
return DiffusionPage.as_item(log) return DiffusionPage.as_item(log.diffusion)
related = log.related track = log.track
return ListItem( return ListItem(
title = '{artist} -- {title}'.format( title = '{artist} -- {title}'.format(
artist = related.artist, artist = track.artist,
title = related.title, title = track.title,
), ),
headline = related.info, headline = track.info,
date = log.date, date = log.date,
info = '', info = '',
css_class = 'track' css_class = 'track'

View File

@ -118,7 +118,7 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
@receiver(post_save, sender=aircox.Program) @receiver(post_save, sender=aircox.Program)
def program_post_saved(sender, instance, created, *args, **kwargs): def program_post_saved(sender, instance, created, *args, **kwargs):
if not created or instance.page.count(): if not created or instance.page:
return return
settings = utils.get_station_settings(instance.station) settings = utils.get_station_settings(instance.station)
@ -191,7 +191,7 @@ def diffusion_post_saved(sender, instance, created, *args, **kwargs):
page = models.DiffusionPage.from_diffusion( page = models.DiffusionPage.from_diffusion(
instance, live = False instance, live = False
) )
instance.program.page.first().add_child( instance.program.page.add_child(
instance = page instance = page
) )

View File

@ -327,7 +327,7 @@ class TodayMenu(GenericMenu):
return MenuItem(label, self.page_url(item), attrs = attrs) return MenuItem(label, self.page_url(item), attrs = attrs)
def get_parent(self, item): def get_parent(self, item):
return item.program.page.first() return item.program.page
@hooks.register('register_admin_menu_item') @hooks.register('register_admin_menu_item')