forked from rc/aircox
Merge branch 'streamer_live'
This commit is contained in:
commit
013a0894ab
|
@ -183,8 +183,8 @@ class StationAdmin(admin.ModelAdmin):
|
|||
|
||||
@admin.register(Log)
|
||||
class LogAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'date', 'station', 'source', 'type', 'comment', 'related']
|
||||
list_filter = ['date', 'source', 'related_type']
|
||||
list_display = ['id', 'date', 'station', 'source', 'type', 'comment', 'diffusion', 'sound', 'track']
|
||||
list_filter = ['date', 'source', 'diffusion', 'sound', 'track']
|
||||
|
||||
admin.site.register(Port)
|
||||
|
||||
|
|
|
@ -15,7 +15,14 @@ from django.conf import settings as main_settings
|
|||
from django.core.management.base import BaseCommand, CommandError
|
||||
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:
|
||||
"""
|
||||
Keep trace of played item and update logs in adequation to it
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Monitor:
|
||||
|
@ -65,11 +72,12 @@ class Monitor:
|
|||
self.sync_playlists()
|
||||
self.handle()
|
||||
|
||||
def log(self, **kwargs):
|
||||
def log(self, date = None, **kwargs):
|
||||
"""
|
||||
Create a log using **kwargs, and print info
|
||||
"""
|
||||
log = Log(station = self.station, **kwargs)
|
||||
log = Log(station = self.station, date = date or tz.now(),
|
||||
**kwargs)
|
||||
log.save()
|
||||
log.print()
|
||||
|
||||
|
@ -84,17 +92,18 @@ class Monitor:
|
|||
if not current_sound or not current_source:
|
||||
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()
|
||||
|
||||
# only streamed
|
||||
if log and (log.related and not log.related.diffusion):
|
||||
# only streamed ns
|
||||
if log and not log.sound.diffusion:
|
||||
self.trace_sound_tracks(log)
|
||||
|
||||
# TODO: expiration
|
||||
if log and (log.source == current_source.id and \
|
||||
log.related and
|
||||
log.related.path == current_sound):
|
||||
log.sound and
|
||||
log.sound.path == current_sound):
|
||||
return
|
||||
|
||||
sound = Sound.objects.filter(path = current_sound)
|
||||
|
@ -102,7 +111,7 @@ class Monitor:
|
|||
type = Log.Type.play,
|
||||
source = current_source.id,
|
||||
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)
|
||||
comment = current_sound,
|
||||
)
|
||||
|
@ -112,11 +121,12 @@ class Monitor:
|
|||
Log tracks for the given sound (for streamed programs); Called by
|
||||
self.trace
|
||||
"""
|
||||
logs = Log.objects.get_for(self.station, model = Track) \
|
||||
.filter(pk__gt = log.pk)
|
||||
logs = [ log.related_id for log in logs ]
|
||||
logs = Log.objects.station(self.station,
|
||||
track__isnull = False,
|
||||
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)
|
||||
if tracks and len(tracks) == len(logs):
|
||||
return
|
||||
|
@ -130,7 +140,7 @@ class Monitor:
|
|||
type = Log.Type.play,
|
||||
source = log.source,
|
||||
date = pos,
|
||||
related = track,
|
||||
track = track,
|
||||
comment = track,
|
||||
)
|
||||
|
||||
|
@ -147,9 +157,9 @@ class Monitor:
|
|||
for source in self.station.sources:
|
||||
if source == self.station.dealer:
|
||||
continue
|
||||
playlist = [ sound.path for sound in
|
||||
source.program.sound_set.all() ]
|
||||
source.playlist = playlist
|
||||
playlist = source.program.sound_set.all() \
|
||||
.values_list('path', flat = True)
|
||||
source.playlist = list(playlist)
|
||||
|
||||
def trace_canceled(self):
|
||||
"""
|
||||
|
@ -163,18 +173,18 @@ class Monitor:
|
|||
type = Diffusion.Type.normal,
|
||||
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)
|
||||
for diff in diffs:
|
||||
if logs.filter(related = diff):
|
||||
if logs.filter(diffusion = diff):
|
||||
continue
|
||||
if diff.start < now:
|
||||
diff.type = Diffusion.Type.canceled
|
||||
diff.save()
|
||||
self.log(
|
||||
type = Log.Type.other,
|
||||
related = diff,
|
||||
diffusion = diff,
|
||||
comment = 'Diffusion canceled after {} seconds' \
|
||||
.format(self.cancel_timeout)
|
||||
)
|
||||
|
@ -187,53 +197,81 @@ class Monitor:
|
|||
station = self.station
|
||||
now = tz.now()
|
||||
|
||||
diff_log = station.played(models = Diffusion) \
|
||||
.order_by('date').last()
|
||||
if not diff_log or \
|
||||
not diff_log.related.is_date_in_range(now):
|
||||
log = station.played(diffusion__isnull = False) \
|
||||
.select_related('diffusion') \
|
||||
.order_by('date').last()
|
||||
if not log or not log.diffusion.is_date_in_range(now):
|
||||
# not running anymore
|
||||
return None, []
|
||||
|
||||
# sound has switched? assume it has been (forced to) stopped
|
||||
sounds = station.played(models = Sound) \
|
||||
.filter(date__gte = diff_log.date) \
|
||||
# last sound source change: end of file reached or forced to stop
|
||||
sounds = station.played(sound__isnull = False) \
|
||||
.filter(date__gte = log.date) \
|
||||
.order_by('date')
|
||||
|
||||
if sounds.last() and sounds.last().source != diff_log.source:
|
||||
return diff_log, []
|
||||
if sounds.count() and sounds.last().source != log.source:
|
||||
return None, []
|
||||
|
||||
# last diff is still playing: get the remaining playlist
|
||||
sounds = sounds.filter(
|
||||
source = diff_log.source, pk__gt = diff_log.pk
|
||||
)
|
||||
sounds = [
|
||||
sound.related.path for sound in sounds
|
||||
if sound.related.type != Sound.Type.removed
|
||||
]
|
||||
# last diff is still playing: get remaining playlist
|
||||
sounds = sounds \
|
||||
.filter(source = log.source, pk__gt = log.pk) \
|
||||
.exclude(sound__type = Sound.Type.removed)
|
||||
|
||||
return (
|
||||
diff_log.related,
|
||||
[ path for path in diff_log.related.playlist
|
||||
if path not in sounds ]
|
||||
)
|
||||
remaining = log.diffusion.get_archives().exclude(pk__in = sounds) \
|
||||
.values_list('path', flat = True)
|
||||
return log.diffusion, list(remaining)
|
||||
|
||||
def __next_diff(self, diff):
|
||||
"""
|
||||
Return the tuple with the next diff that should be played and
|
||||
the playlist
|
||||
|
||||
Note: diff is a log
|
||||
Return the next diffusion to be played as tuple of (diff, playlist).
|
||||
If diff is given, it is the one to be played right after it.
|
||||
"""
|
||||
station = self.station
|
||||
now = tz.now()
|
||||
|
||||
args = {'start__gt': diff.date } if diff else {}
|
||||
diff = Diffusion.objects.at(station, now).filter(
|
||||
type = Diffusion.Type.normal,
|
||||
sound__type = Sound.Type.archive,
|
||||
**args
|
||||
).distinct().order_by('start').first()
|
||||
kwargs = {'start__gte': diff.end } if diff else {}
|
||||
diff = Diffusion.objects \
|
||||
.at(station, now) \
|
||||
.filter(type = Diffusion.Type.normal, **kwargs) \
|
||||
.distinct().order_by('start')
|
||||
diff = diff.first()
|
||||
return (diff, diff and diff.playlist or [])
|
||||
|
||||
def handle_pl_sync(self, source, playlist, diff = None, date = None):
|
||||
"""
|
||||
Update playlist of a source if required, and handle logging when
|
||||
it is needed.
|
||||
"""
|
||||
dealer = self.station.dealer
|
||||
if dealer.playlist != playlist:
|
||||
dealer.playlist = playlist
|
||||
if diff and not diff.is_live():
|
||||
self.log(type = Log.Type.load, source = source.id,
|
||||
diffusion = diff, date = date)
|
||||
|
||||
def handle_diff_start(self, source, diff, date):
|
||||
"""
|
||||
Enable dealer in order to play a given diffusion if required,
|
||||
handle start of diffusion
|
||||
"""
|
||||
if not diff or diff.start > date:
|
||||
return
|
||||
|
||||
# live: just log it
|
||||
if diff.is_live():
|
||||
diff_ = Log.objects.station(self.station) \
|
||||
.filter(diffusion = diff)
|
||||
if not diff_.count():
|
||||
self.log(type = Log.Type.on_air, source = source.id,
|
||||
diffusion = diff, date = date)
|
||||
return
|
||||
|
||||
# enable dealer
|
||||
if not dealer.active:
|
||||
dealer.active = True
|
||||
self.log(type = Log.Type.play, source = source.id,
|
||||
diffusion = diff, date = date)
|
||||
|
||||
def handle(self):
|
||||
"""
|
||||
Handle scheduled diffusion, trigger if needed, preload playlists
|
||||
|
@ -246,33 +284,15 @@ class Monitor:
|
|||
now = tz.now()
|
||||
|
||||
# current and next diffs
|
||||
diff, playlist = self.__current_diff()
|
||||
dealer.active = bool(playlist)
|
||||
current_diff, remaining_pl = self.__current_diff()
|
||||
next_diff, next_pl = self.__next_diff(current_diff)
|
||||
|
||||
next_diff, next_playlist = self.__next_diff(diff)
|
||||
playlist += next_playlist
|
||||
# playlist
|
||||
dealer.active = bool(remaining_pl)
|
||||
playlist = remaining_pl + next_pl
|
||||
|
||||
# playlist update
|
||||
if dealer.playlist != playlist:
|
||||
dealer.playlist = playlist
|
||||
if next_diff:
|
||||
self.log(
|
||||
type = Log.Type.load,
|
||||
source = dealer.id,
|
||||
date = now,
|
||||
related = next_diff
|
||||
)
|
||||
|
||||
# dealer.on when next_diff start <= now
|
||||
if next_diff and not dealer.active and \
|
||||
next_diff.start <= now:
|
||||
dealer.active = True
|
||||
self.log(
|
||||
type = Log.Type.play,
|
||||
source = dealer.id,
|
||||
date = now,
|
||||
related = next_diff,
|
||||
)
|
||||
self.handle_pl_sync(dealer, playlist, next_diff, now)
|
||||
self.handle_diff_start(dealer, next_diff, now)
|
||||
|
||||
|
||||
class Command (BaseCommand):
|
||||
|
|
231
aircox/models.py
231
aircox/models.py
|
@ -50,7 +50,6 @@ class RelatedManager(models.Manager):
|
|||
qs = qs.filter(related_id = object.pk)
|
||||
return qs
|
||||
|
||||
|
||||
class Related(models.Model):
|
||||
"""
|
||||
Add a field "related" of type GenericForeignKey, plus utilities.
|
||||
|
@ -148,7 +147,6 @@ class Track(Related):
|
|||
verbose_name = _('Track')
|
||||
verbose_name_plural = _('Tracks')
|
||||
|
||||
|
||||
#
|
||||
# Station related classes
|
||||
#
|
||||
|
@ -180,7 +178,7 @@ class Station(Nameable):
|
|||
__dealer = None
|
||||
__streamer = None
|
||||
|
||||
def __prepare(self):
|
||||
def __prepare_controls(self):
|
||||
import aircox.controllers as controllers
|
||||
if not self.__streamer:
|
||||
self.__streamer = controllers.Streamer(station = self)
|
||||
|
@ -215,12 +213,12 @@ class Station(Nameable):
|
|||
"""
|
||||
Audio sources, dealer included
|
||||
"""
|
||||
self.__prepare()
|
||||
self.__prepare_controls()
|
||||
return self.__sources
|
||||
|
||||
@property
|
||||
def dealer(self):
|
||||
self.__prepare()
|
||||
self.__prepare_controls()
|
||||
return self.__dealer
|
||||
|
||||
@property
|
||||
|
@ -228,86 +226,25 @@ class Station(Nameable):
|
|||
"""
|
||||
Audio controller for the station
|
||||
"""
|
||||
self.__prepare()
|
||||
self.__prepare_controls()
|
||||
return self.__streamer
|
||||
|
||||
def played(self, models, archives = True):
|
||||
def played(self, *args, **kwargs):
|
||||
"""
|
||||
Call Log.objects.played for this station
|
||||
"""
|
||||
return Log.objects.played(self, models, archives)
|
||||
|
||||
@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
|
||||
return Log.objects.played(self, *args, **kwargs)
|
||||
|
||||
def on_air(self, date = None, count = 0):
|
||||
"""
|
||||
Return a list of what happened on air, based on logs and
|
||||
diffusions informations. The list is sorted by -date.
|
||||
Return a queryset of what happened on air, based on logs and
|
||||
diffusions informations. The queryset is sorted by -date.
|
||||
|
||||
* date: only for what happened on this date;
|
||||
* count: number of items to retrieve if not zero;
|
||||
|
||||
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.
|
||||
|
||||
The list contains:
|
||||
* track logs: for the streamed programs;
|
||||
* diffusion: for the scheduled diffusions;
|
||||
"""
|
||||
# FIXME: as an iterator?
|
||||
# TODO argument to get sound instead of tracks
|
||||
|
@ -315,21 +252,39 @@ class Station(Nameable):
|
|||
raise ValueError('at least one argument must be set')
|
||||
|
||||
# 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():
|
||||
return []
|
||||
|
||||
if date:
|
||||
logs = Log.objects.at_for(self, date, model = Track)
|
||||
diffs = Diffusion.objects.at(self, date)
|
||||
logs = Log.objects.at(self, date)
|
||||
diffs = Diffusion.objects.at(self, date, type = Diffusion.Type.normal) \
|
||||
.order_by('-start')
|
||||
else:
|
||||
logs = Log.objects.get_for(self, model = Track)
|
||||
diffs = Diffusion.objects
|
||||
logs = logs.filter(station = self)
|
||||
logs = Log.objects
|
||||
diffs = Diffusion.objects.filter(type = Diffusion.Type.normal,
|
||||
start__lte = tz.now()) \
|
||||
.order_by('-start')[:count]
|
||||
|
||||
diffs = diffs.filter(program__station = self) \
|
||||
.filter(type = Diffusion.Type.normal) \
|
||||
.filter(start__lte = tz.now())
|
||||
return self.__mix_logs_and_diff(diffs, logs, count)
|
||||
q = models.Q(diffusion__isnull = False) | \
|
||||
models.Q(track__isnull = False)
|
||||
logs = logs.filter(q).order_by('-date')
|
||||
|
||||
# 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):
|
||||
if not self.path:
|
||||
|
@ -348,9 +303,9 @@ class Station(Nameable):
|
|||
|
||||
|
||||
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
|
||||
return qs.filter(station = station)
|
||||
return qs.filter(station = station, **kwargs)
|
||||
|
||||
class Program(Nameable):
|
||||
"""
|
||||
|
@ -730,11 +685,11 @@ class Schedule(models.Model):
|
|||
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -770,7 +725,7 @@ class DiffusionManager(models.Manager):
|
|||
if next:
|
||||
# include also diffusions of the next day
|
||||
filters |= models.Q(start__gte = start)
|
||||
qs = qs.filter(filters)
|
||||
qs = qs.filter(filters, **kwargs)
|
||||
return self.station(station, qs).order_by('start').distinct()
|
||||
|
||||
def after(self, station, date = None, qs = None):
|
||||
|
@ -867,7 +822,12 @@ class Diffusion(models.Model):
|
|||
"""
|
||||
List of archives' path; uses get_archives
|
||||
"""
|
||||
return [ sound.path for sound in self.get_archives() ]
|
||||
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):
|
||||
"""
|
||||
|
@ -1229,59 +1189,51 @@ class Port (models.Model):
|
|||
)
|
||||
|
||||
|
||||
class LogManager(RelatedManager):
|
||||
def station(self, station, qs = None):
|
||||
class LogManager(models.Manager):
|
||||
def station(self, station, qs = None, **kwargs):
|
||||
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):
|
||||
qs = super().get_for(*args, **kwargs)
|
||||
return self.station(station, qs) if station else qs
|
||||
|
||||
def _at(self, date = None, qs = None):
|
||||
def _at(self, date = None, qs = None, **kwargs):
|
||||
start, end = utils.date_range(date)
|
||||
qs = self if qs is None else qs
|
||||
return qs.filter(date__gte = start,
|
||||
date__lte = end)
|
||||
return qs.filter(date__gte = start, date__lte = end, **kwargs)
|
||||
|
||||
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
|
||||
in their range.
|
||||
"""
|
||||
qs = self._at(date, qs)
|
||||
qs = self._at(date, qs, **kwargs)
|
||||
return self.station(station, qs) if station else qs
|
||||
|
||||
def at_for(self, station, date, object = None, model = None, qs = None):
|
||||
"""
|
||||
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):
|
||||
def played(self, station, archives = True, include_live = True,
|
||||
**kwargs):
|
||||
"""
|
||||
Return a queryset of the played elements' log for the given
|
||||
station and model. This queryset is ordered by date ascending
|
||||
|
||||
* station: related station
|
||||
* models: a model or a list of models
|
||||
* archives: if false, exclude log of diffusion's archives from
|
||||
the queryset;
|
||||
* include_live: include diffusion that have no archive
|
||||
* kwargs: extra filter kwargs
|
||||
"""
|
||||
qs = self.get_for(station, model = models) \
|
||||
.filter(type = Log.Type.play)
|
||||
if include_live:
|
||||
qs = self.filter(type__in = (Log.Type.play, Log.Type.on_air),
|
||||
**kwargs)
|
||||
else:
|
||||
qs = self.filter(type = Log.Type.play, **kwargs)
|
||||
|
||||
if not archives and station.dealer:
|
||||
qs = qs.exclude(
|
||||
source = station.dealer.id,
|
||||
related_type = ContentType.objects.get_for_model(Sound)
|
||||
sound__isnull = False
|
||||
)
|
||||
return qs.order_by('date')
|
||||
|
||||
|
||||
class Log(Related):
|
||||
class Log(models.Model):
|
||||
"""
|
||||
Log sounds and diffusions that are played on the station.
|
||||
|
||||
|
@ -1303,14 +1255,18 @@ class Log(Related):
|
|||
"""
|
||||
Source starts to be preload related_object
|
||||
"""
|
||||
other = 0x03
|
||||
on_air = 0x03
|
||||
"""
|
||||
A diffusion occured, but in live (no sound played by Aircox)
|
||||
"""
|
||||
other = 0x04
|
||||
"""
|
||||
Other log
|
||||
"""
|
||||
|
||||
type = models.SmallIntegerField(
|
||||
verbose_name = _('type'),
|
||||
choices = [ (int(y), _(x)) for x,y in Type.__members__.items() ],
|
||||
choices = [ (int(y), _(x.replace('_',' '))) for x,y in Type.__members__.items() ],
|
||||
blank = True, null = True,
|
||||
)
|
||||
station = models.ForeignKey(
|
||||
|
@ -1329,6 +1285,7 @@ class Log(Related):
|
|||
date = models.DateTimeField(
|
||||
_('date'),
|
||||
default=tz.now,
|
||||
db_index = True,
|
||||
)
|
||||
comment = models.CharField(
|
||||
_('comment'),
|
||||
|
@ -1336,6 +1293,25 @@ class Log(Related):
|
|||
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()
|
||||
|
||||
@property
|
||||
|
@ -1343,12 +1319,16 @@ class Log(Related):
|
|||
"""
|
||||
Calculated end using self.related informations
|
||||
"""
|
||||
if self.related_type == Diffusion:
|
||||
return self.related.end
|
||||
if self.related_type == Sound:
|
||||
return self.date + to_timedelta(self.duration)
|
||||
if self.diffusion:
|
||||
return self.diffusion.end
|
||||
if self.sound:
|
||||
return self.date + to_timedelta(sound.duration)
|
||||
return self.date
|
||||
|
||||
@property
|
||||
def related(self):
|
||||
return self.diffusion or self.sound or self.track
|
||||
|
||||
def is_expired(self, date = None):
|
||||
"""
|
||||
Return True if the log is expired. Note that it only check
|
||||
|
@ -1359,11 +1339,19 @@ class Log(Related):
|
|||
return self.end < date
|
||||
|
||||
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',
|
||||
str(self),
|
||||
self.comment or '',
|
||||
' -- {} #{}'.format(self.related_type, self.related_id)
|
||||
if self.related else ''
|
||||
' (' + ', '.join(r) + ')' if r else ''
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -1371,4 +1359,3 @@ class Log(Related):
|
|||
self.pk, self.date.strftime('%Y/%m/%d %H:%M'), self.source
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -40,12 +40,12 @@ def on_air(request):
|
|||
else:
|
||||
station = stations.stations.first()
|
||||
|
||||
last = station.on_air(count = 10)
|
||||
if not last:
|
||||
on_air = station.on_air(count = 10).select_related('track','diffusion')
|
||||
if not on_air.count():
|
||||
return HttpResponse('')
|
||||
|
||||
last = last[0]
|
||||
if type(last) == models.Log:
|
||||
last = on_air.last()
|
||||
if last.track:
|
||||
last = {
|
||||
'type': 'track',
|
||||
'artist': last.related.artist,
|
||||
|
@ -54,11 +54,12 @@ def on_air(request):
|
|||
}
|
||||
else:
|
||||
try:
|
||||
diff = last.diffusion
|
||||
publication = None
|
||||
if cms:
|
||||
publication = \
|
||||
cms.DiffusionPage.objects.filter(
|
||||
diffusion = last.initial or last).first() or \
|
||||
diffusion = diff.initial or diff).first() or \
|
||||
cms.ProgramPage.objects.filter(
|
||||
program = last.program).first()
|
||||
except:
|
||||
|
@ -66,8 +67,8 @@ def on_air(request):
|
|||
|
||||
last = {
|
||||
'type': 'diffusion',
|
||||
'title': last.program.name,
|
||||
'date': last.start,
|
||||
'title': diff.program.name,
|
||||
'date': diff.start,
|
||||
'url': publication.specific.url if publication else None,
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class Command (BaseCommand):
|
|||
initial__isnull = True
|
||||
).exclude(type = Diffusion.Type.unconfirmed)
|
||||
for diffusion in qs:
|
||||
if not diffusion.program.page.count():
|
||||
if not diffusion.program.page:
|
||||
if not hasattr(diffusion.program, '__logged_diff_error'):
|
||||
logger.warning(
|
||||
'the program {} has no page; skip the creation of '
|
||||
|
@ -80,7 +80,7 @@ class Command (BaseCommand):
|
|||
page = DiffusionPage.from_diffusion(
|
||||
diffusion, live = False
|
||||
)
|
||||
diffusion.program.page.first().add_child(instance = page)
|
||||
diffusion.program.page.add_child(instance = page)
|
||||
except:
|
||||
import sys
|
||||
e = sys.exc_info()[0]
|
||||
|
|
|
@ -452,10 +452,8 @@ class ProgramPage(Publication):
|
|||
|
||||
def diffs_to_page(self, diffs):
|
||||
for diff in diffs:
|
||||
if diff.page.count():
|
||||
diff.page_ = diff.page.first()
|
||||
else:
|
||||
diff.page_ = ListItem(
|
||||
if not diff.page:
|
||||
diff.page = ListItem(
|
||||
title = '{}, {}'.format(
|
||||
self.program.name, diff.date.strftime('%d %B %Y')
|
||||
),
|
||||
|
@ -464,7 +462,7 @@ class ProgramPage(Publication):
|
|||
date = diff.start,
|
||||
)
|
||||
return [
|
||||
diff.page_ for diff in diffs if diff.page_.live
|
||||
diff.page for diff in diffs if diff.page.live
|
||||
]
|
||||
|
||||
@property
|
||||
|
@ -560,8 +558,8 @@ class DiffusionPage(Publication):
|
|||
'title': '{}, {}'.format(
|
||||
diff.program.name, tz.localtime(diff.date).strftime('%d %B %Y')
|
||||
),
|
||||
'cover': (diff.program.page.count() and \
|
||||
diff.program.page.first().cover) or None,
|
||||
'cover': (diff.program.page and \
|
||||
diff.program.page.cover) or None,
|
||||
'date': diff.start,
|
||||
}
|
||||
model_kwargs.update(kwargs)
|
||||
|
@ -637,7 +635,7 @@ class DiffusionPage(Publication):
|
|||
if self.diffusion:
|
||||
# set publish_as
|
||||
if not self.pk:
|
||||
self.publish_as = self.diffusion.program.page.first()
|
||||
self.publish_as = self.diffusion.program.page
|
||||
|
||||
# sync date
|
||||
self.date = self.diffusion.start
|
||||
|
@ -777,8 +775,9 @@ class LogsPage(DatedListPage):
|
|||
|
||||
logs = []
|
||||
for date in context['nav_dates']['dates']:
|
||||
items = [ SectionLogsList.as_item(item)
|
||||
for item in self.station.on_air(date = date) ]
|
||||
items = self.station.on_air(date = date) \
|
||||
.select_related('track','diffusion')
|
||||
items = [ SectionLogsList.as_item(item) for item in items ]
|
||||
logs.append(
|
||||
(date, reversed(items) if self.reverse else items)
|
||||
)
|
||||
|
|
|
@ -957,16 +957,16 @@ class SectionLogsList(SectionItem):
|
|||
Supports: Log/Track, Diffusion
|
||||
"""
|
||||
from aircox_cms.models import DiffusionPage
|
||||
if type(log) == aircox.models.Diffusion:
|
||||
return DiffusionPage.as_item(log)
|
||||
if log.diffusion:
|
||||
return DiffusionPage.as_item(log.diffusion)
|
||||
|
||||
related = log.related
|
||||
track = log.track
|
||||
return ListItem(
|
||||
title = '{artist} -- {title}'.format(
|
||||
artist = related.artist,
|
||||
title = related.title,
|
||||
artist = track.artist,
|
||||
title = track.title,
|
||||
),
|
||||
headline = related.info,
|
||||
headline = track.info,
|
||||
date = log.date,
|
||||
info = '♫',
|
||||
css_class = 'track'
|
||||
|
|
|
@ -118,7 +118,7 @@ def station_post_saved(sender, instance, created, *args, **kwargs):
|
|||
|
||||
@receiver(post_save, sender=aircox.Program)
|
||||
def program_post_saved(sender, instance, created, *args, **kwargs):
|
||||
if not created or instance.page.count():
|
||||
if not created or instance.page:
|
||||
return
|
||||
|
||||
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(
|
||||
instance, live = False
|
||||
)
|
||||
instance.program.page.first().add_child(
|
||||
instance.program.page.add_child(
|
||||
instance = page
|
||||
)
|
||||
|
||||
|
|
|
@ -127,8 +127,8 @@ class LogAdmin(ModelAdmin):
|
|||
menu_label = _('Logs')
|
||||
menu_icon = 'time'
|
||||
menu_order = 300
|
||||
list_display = ['date', 'station', 'source', 'type', 'comment', 'related']
|
||||
list_filter = ['date', 'source', 'related_type']
|
||||
list_display = ['id', 'date', 'station', 'source', 'type', 'comment', 'diffusion', 'sound', 'track']
|
||||
list_filter = ['date', 'source', 'diffusion', 'sound', 'track']
|
||||
|
||||
aircox.models.Log.panels = [
|
||||
MultiFieldPanel([
|
||||
|
@ -139,11 +139,12 @@ aircox.models.Log.panels = [
|
|||
]),
|
||||
FieldPanel('type'),
|
||||
FieldPanel('comment'),
|
||||
FieldRowPanel([
|
||||
FieldPanel('related_type'),
|
||||
FieldPanel('related_id')
|
||||
]),
|
||||
], heading = _('Log')),
|
||||
MultiFieldPanel([
|
||||
FieldPanel('diffusion'),
|
||||
FieldPanel('sound'),
|
||||
FieldPanel('track'),
|
||||
], heading = _('Related objects')),
|
||||
]
|
||||
|
||||
|
||||
|
@ -327,7 +328,7 @@ class TodayMenu(GenericMenu):
|
|||
return MenuItem(label, self.page_url(item), attrs = attrs)
|
||||
|
||||
def get_parent(self, item):
|
||||
return item.program.page.first()
|
||||
return item.program.page
|
||||
|
||||
|
||||
@hooks.register('register_admin_menu_item')
|
||||
|
|
Loading…
Reference in New Issue
Block a user