forked from rc/aircox
fix models manager and qs; schedule_post_saved
This commit is contained in:
parent
04c3330c21
commit
f70b692aff
|
@ -164,9 +164,18 @@ class ScheduleAdmin(admin.ModelAdmin):
|
||||||
rerun.short_description = _('Rerun')
|
rerun.short_description = _('Rerun')
|
||||||
rerun.boolean = True
|
rerun.boolean = True
|
||||||
|
|
||||||
|
|
||||||
list_filter = ['frequency', 'program']
|
list_filter = ['frequency', 'program']
|
||||||
list_display = ['id', 'program_name', 'frequency', 'day', 'date', 'time', 'timezone', 'duration', 'rerun']
|
list_display = ['id', 'program_name', 'frequency', 'day', 'date',
|
||||||
list_editable = ['frequency', 'date', 'time', 'timezone', 'duration']
|
'time', 'duration', 'timezone', 'rerun']
|
||||||
|
list_editable = ['time', 'timezone', 'duration']
|
||||||
|
|
||||||
|
|
||||||
|
def get_readonly_fields(self, request, obj=None):
|
||||||
|
if obj:
|
||||||
|
return ['program', 'date', 'frequency']
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Track)
|
@admin.register(Track)
|
||||||
|
|
|
@ -172,12 +172,9 @@ class SoundInfo:
|
||||||
self.hour or 0, self.minute or 0)
|
self.hour or 0, self.minute or 0)
|
||||||
date = tz.get_current_timezone().localize(date)
|
date = tz.get_current_timezone().localize(date)
|
||||||
|
|
||||||
diffusion = Diffusion.objects.after(
|
qs = Diffusion.objects.station(program.station).after(date) \
|
||||||
program.station,
|
.filter(program = program, initial__isnull = True)
|
||||||
date,
|
diffusion = qs.first()
|
||||||
program = program,
|
|
||||||
initial__isnull = True,
|
|
||||||
).first()
|
|
||||||
if not diffusion:
|
if not diffusion:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -245,14 +245,14 @@ class Monitor:
|
||||||
if not self.cancel_timeout:
|
if not self.cancel_timeout:
|
||||||
return
|
return
|
||||||
|
|
||||||
diffs = Diffusions.objects.at(self.station).filter(
|
qs = Diffusions.objects.station(self.station).at().filter(
|
||||||
type = Diffusion.Type.normal,
|
type = Diffusion.Type.normal,
|
||||||
sound__type = Sound.Type.archive,
|
sound__type = Sound.Type.archive,
|
||||||
)
|
)
|
||||||
logs = station.raw_on_air(diffusion__isnull = False)
|
logs = station.raw_on_air(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 qs:
|
||||||
if logs.filter(diffusion = diff):
|
if logs.filter(diffusion = diff):
|
||||||
continue
|
continue
|
||||||
if diff.start < now:
|
if diff.start < now:
|
||||||
|
@ -305,14 +305,13 @@ class Monitor:
|
||||||
If diff is given, it is the one to be played right after it.
|
If diff is given, it is the one to be played right after it.
|
||||||
"""
|
"""
|
||||||
station = self.station
|
station = self.station
|
||||||
now = tz.now()
|
|
||||||
|
|
||||||
kwargs = {'start__gte': diff.end } if diff else {}
|
kwargs = {'start__gte': diff.end } if diff else {}
|
||||||
diff = Diffusion.objects \
|
kwargs['type'] = Diffusion.Type.normal
|
||||||
.at(station, now) \
|
|
||||||
.filter(type = Diffusion.Type.normal, **kwargs) \
|
qs = Diffusion.objects.station(station).at().filter(**kwargs) \
|
||||||
.distinct().order_by('start')
|
.distinct().order_by('start')
|
||||||
diff = diff.first()
|
diff = qs.first()
|
||||||
return (diff, diff and diff.get_playlist(archive = True) or [])
|
return (diff, diff and diff.get_playlist(archive = True) or [])
|
||||||
|
|
||||||
def handle_pl_sync(self, source, playlist, diff = None, date = None):
|
def handle_pl_sync(self, source, playlist, diff = None, date = None):
|
||||||
|
|
|
@ -232,11 +232,11 @@ class Station(Nameable):
|
||||||
self.__prepare_controls()
|
self.__prepare_controls()
|
||||||
return self.__streamer
|
return self.__streamer
|
||||||
|
|
||||||
def raw_on_air(self, *args, **kwargs):
|
def raw_on_air(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Forward call to Log.objects.on_air for this station
|
Forward call to Log.objects.on_air for this station
|
||||||
"""
|
"""
|
||||||
return Log.objects.on_air(self, *args, **kwargs)
|
return Log.objects.station(self).on_air().filter(**kwargs)
|
||||||
|
|
||||||
def on_air(self, date = None, count = 0, no_cache = False):
|
def on_air(self, date = None, count = 0, no_cache = False):
|
||||||
"""
|
"""
|
||||||
|
@ -266,11 +266,10 @@ class Station(Nameable):
|
||||||
|
|
||||||
now = tz.now()
|
now = tz.now()
|
||||||
if date:
|
if date:
|
||||||
logs = Log.objects.at(self, date)
|
logs = Log.objects.station(self).at(date)
|
||||||
diffs = Diffusion.objects \
|
diffs = Diffusion.objects.station(self).at(date) \
|
||||||
.at(self, date, type = Diffusion.Type.normal) \
|
.filter(start__lte = now, type = Diffusion.Type.normal) \
|
||||||
.filter(start__lte = now) \
|
.order_by('-start')
|
||||||
.order_by('-start')
|
|
||||||
else:
|
else:
|
||||||
logs = Log.objects
|
logs = Log.objects
|
||||||
diffs = Diffusion.objects \
|
diffs = Diffusion.objects \
|
||||||
|
@ -568,15 +567,11 @@ class Schedule(models.Model):
|
||||||
if not initial:
|
if not initial:
|
||||||
return
|
return
|
||||||
|
|
||||||
before, now = self.__initial, self.__dict__
|
this = self.__dict__
|
||||||
before, now = {
|
for field in fields:
|
||||||
f: getattr(before, f) for f in fields
|
if initial.get(field) != this.get(field):
|
||||||
if hasattr(before, f)
|
return True
|
||||||
}, {
|
return False
|
||||||
f: getattr(now, f) for f in fields
|
|
||||||
if hasattr(now, f)
|
|
||||||
}
|
|
||||||
return before == now
|
|
||||||
|
|
||||||
def match(self, date = None, check_time = True):
|
def match(self, date = None, check_time = True):
|
||||||
"""
|
"""
|
||||||
|
@ -727,7 +722,10 @@ class Schedule(models.Model):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.__initial = self.__dict__.copy()
|
|
||||||
|
# initial only if it has been yet saved
|
||||||
|
if self.pk:
|
||||||
|
self.__initial = self.__dict__.copy()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ' | '.join([ '#' + str(self.id), self.program.name,
|
return ' | '.join([ '#' + str(self.id), self.program.name,
|
||||||
|
@ -747,12 +745,14 @@ class Schedule(models.Model):
|
||||||
verbose_name_plural = _('Schedules')
|
verbose_name_plural = _('Schedules')
|
||||||
|
|
||||||
|
|
||||||
class DiffusionManager(models.Manager):
|
class DiffusionQuerySet(models.QuerySet):
|
||||||
def station(self, station, qs = None, **kwargs):
|
def station(self, station, **kwargs):
|
||||||
qs = self if qs is None else qs
|
return self.filter(program__station = station, **kwargs)
|
||||||
return qs.filter(program__station = station, **kwargs)
|
|
||||||
|
|
||||||
def at(self, station, date = None, next = False, qs = None, **kwargs):
|
def program(self, program):
|
||||||
|
return self.filter(program = program)
|
||||||
|
|
||||||
|
def at(self, date = None, next = False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return diffusions occuring at the given date, ordered by +start
|
Return diffusions occuring at the given date, ordered by +start
|
||||||
|
|
||||||
|
@ -768,7 +768,7 @@ class DiffusionManager(models.Manager):
|
||||||
# note: we work with localtime
|
# note: we work with localtime
|
||||||
date = utils.date_or_default(date, keep_type = True)
|
date = utils.date_or_default(date, keep_type = True)
|
||||||
|
|
||||||
qs = self if qs is None else qs
|
qs = self
|
||||||
filters = None
|
filters = None
|
||||||
if isinstance(date, datetime.datetime):
|
if isinstance(date, datetime.datetime):
|
||||||
# use datetime: we want diffusion that occurs around this
|
# use datetime: we want diffusion that occurs around this
|
||||||
|
@ -789,25 +789,23 @@ class DiffusionManager(models.Manager):
|
||||||
# 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, **kwargs)
|
qs = qs.filter(filters, **kwargs)
|
||||||
return self.station(station, qs).order_by('start').distinct()
|
return qs.order_by('start').distinct()
|
||||||
|
|
||||||
def after(self, station, date = None, **kwargs):
|
def after(self, date = None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return a queryset of diffusions that happen after the given
|
Return a queryset of diffusions that happen after the given
|
||||||
date.
|
date.
|
||||||
"""
|
"""
|
||||||
date = utils.date_or_default(date, keep_type = True)
|
date = utils.date_or_default(date, keep_type = True)
|
||||||
return self.station(station, start__gte = date, **kwargs)\
|
return self.filter(start__gte = date, **kwargs).order_by('start')
|
||||||
.order_by('start')
|
|
||||||
|
|
||||||
def before(self, station, date = None, **kwargs):
|
def before(self, date = None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return a queryset of diffusions that finish before the given
|
Return a queryset of diffusions that finish before the given
|
||||||
date.
|
date.
|
||||||
"""
|
"""
|
||||||
date = utils.date_or_default(date)
|
date = utils.date_or_default(date)
|
||||||
return self.station(station, end__lte = date, **kwargs) \
|
return self.filter(end__lte = date, **kwargs).order_by('start')
|
||||||
.order_by('start')
|
|
||||||
|
|
||||||
|
|
||||||
class Diffusion(models.Model):
|
class Diffusion(models.Model):
|
||||||
|
@ -828,7 +826,7 @@ class Diffusion(models.Model):
|
||||||
- cancel: the diffusion has been canceled
|
- cancel: the diffusion has been canceled
|
||||||
- stop: the diffusion has been manually stopped
|
- stop: the diffusion has been manually stopped
|
||||||
"""
|
"""
|
||||||
objects = DiffusionManager()
|
objects = DiffusionQuerySet.as_manager()
|
||||||
|
|
||||||
class Type(IntEnum):
|
class Type(IntEnum):
|
||||||
normal = 0x00
|
normal = 0x00
|
||||||
|
@ -1281,26 +1279,18 @@ class Port (models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LogManager(models.Manager):
|
class LogQuerySet(models.QuerySet):
|
||||||
def station(self, station, *args, **kwargs):
|
def station(self, station):
|
||||||
return self.filter(*args, station = station, **kwargs)
|
return self.filter(station = station)
|
||||||
|
|
||||||
def _at(self, date = None, *args, **kwargs):
|
def at(self, date = None):
|
||||||
start, end = utils.date_range(date)
|
start, end = utils.date_range(date)
|
||||||
# return qs.filter(models.Q(end__gte = start) |
|
# return qs.filter(models.Q(end__gte = start) |
|
||||||
# models.Q(date__lte = end))
|
# models.Q(date__lte = end))
|
||||||
return self.filter(*args, date__gte = start, date__lte = end, **kwargs)
|
return self.filter(date__gte = start, date__lte = end)
|
||||||
|
|
||||||
def at(self, station = None, date = None, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Return a queryset of logs that have the given date
|
|
||||||
in their range.
|
|
||||||
"""
|
|
||||||
qs = self._at(date, *args, **kwargs)
|
|
||||||
return qs.filter(station = station) if station else qs
|
|
||||||
|
|
||||||
# TODO: rename on_air + rename Station.on_air into sth like regular_on_air
|
# TODO: rename on_air + rename Station.on_air into sth like regular_on_air
|
||||||
def on_air(self, station, date = None, **kwargs):
|
def on_air(self, date = None):
|
||||||
"""
|
"""
|
||||||
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
|
||||||
|
@ -1310,11 +1300,11 @@ class LogManager(models.Manager):
|
||||||
* kwargs: extra filter kwargs
|
* kwargs: extra filter kwargs
|
||||||
"""
|
"""
|
||||||
if date:
|
if date:
|
||||||
qs = self.at(station, date)
|
qs = self.at(date)
|
||||||
else:
|
else:
|
||||||
qs = self
|
qs = self
|
||||||
|
|
||||||
qs = qs.filter(type = Log.Type.on_air, **kwargs)
|
qs = qs.filter(type = Log.Type.on_air)
|
||||||
return qs.order_by('date')
|
return qs.order_by('date')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1399,7 +1389,7 @@ class LogManager(models.Manager):
|
||||||
if os.path.exists(path) and not force:
|
if os.path.exists(path) and not force:
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
qs = self.at(station, date)
|
qs = self.station(station).at(date)
|
||||||
if not qs.exists():
|
if not qs.exists():
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
@ -1516,7 +1506,7 @@ class Log(models.Model):
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = LogManager()
|
objects = LogQuerySet.as_manager()
|
||||||
|
|
||||||
def estimate_end(self):
|
def estimate_end(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -39,62 +39,44 @@ def user_default_groups(sender, instance, created, *args, **kwargs):
|
||||||
instance.groups.add(group)
|
instance.groups.add(group)
|
||||||
|
|
||||||
|
|
||||||
# FIXME: avoid copy of the code in schedule_post_saved and
|
|
||||||
# schedule_pre_delete
|
|
||||||
|
|
||||||
@receiver(post_save, sender=models.Schedule)
|
@receiver(post_save, sender=models.Schedule)
|
||||||
def schedule_post_saved(sender, instance, created, *args, **kwargs):
|
def schedule_post_save(sender, instance, created, *args, **kwargs):
|
||||||
return
|
"""
|
||||||
# TODO: case instance.program | instance.frequency has changed
|
Handles Schedule's time, duration and timezone changes and update
|
||||||
if not instance.program.sync:
|
corresponding diffusions accordingly.
|
||||||
|
"""
|
||||||
|
if created or not instance.program.sync or \
|
||||||
|
not instance.changed(['time','duration','timezone']):
|
||||||
return
|
return
|
||||||
|
|
||||||
initial = instance._Schedule__initial
|
initial = instance._Schedule__initial
|
||||||
if not initial or not instance.changed(['date','duration', 'frequency']):
|
initial = models.Schedule(**{ k: v
|
||||||
return
|
for k, v in instance._Schedule__initial.items()
|
||||||
|
if not k.startswith('_')
|
||||||
if not initial.get('date') or not initial.get('duration') \
|
|
||||||
or not initial.get('frequency') or \
|
|
||||||
initial.frequency != instance.frequency:
|
|
||||||
return
|
|
||||||
|
|
||||||
# old schedule and timedelta
|
|
||||||
old = models.Schedule(**{ key: initial.get(key)
|
|
||||||
for key in ('date','timezone','duration','frequency')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# change: day, time, duration, frequence => TODO
|
today = tz.datetime.today()
|
||||||
delta = (instance.date - old.date) + \
|
delta = instance.normalize(today) - \
|
||||||
(instance.time - old.time)
|
initial.normalize(today)
|
||||||
|
|
||||||
qs = models.Diffusion.objects.station(
|
qs = models.Diffusion.objects.program(instance.program).after()
|
||||||
instance.program.station,
|
pks = [ d.pk for d in qs if initial.match(d.date) ]
|
||||||
)
|
|
||||||
|
|
||||||
pks = [ item.pk for item in qs if old.match(item.date) ]
|
|
||||||
qs.filter(pk__in = pks).update(
|
qs.filter(pk__in = pks).update(
|
||||||
start = F('start') + delta,
|
start = F('start') + delta,
|
||||||
end = F('start') + delta + utils.to_timedelta(instance.duration)
|
end = F('start') + delta + utils.to_timedelta(instance.duration)
|
||||||
)
|
)
|
||||||
return
|
|
||||||
|
|
||||||
@receiver(pre_delete, sender=models.Schedule)
|
@receiver(pre_delete, sender=models.Schedule)
|
||||||
def schedule_pre_delete(sender, instance, *args, **kwargs):
|
def schedule_pre_delete(sender, instance, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Delete later corresponding diffusion to a changed schedule.
|
||||||
|
"""
|
||||||
if not instance.program.sync:
|
if not instance.program.sync:
|
||||||
return
|
return
|
||||||
|
|
||||||
initial = instance._Schedule__initial
|
qs = models.Diffusion.objects.program(instance.program).after()
|
||||||
if not initial or not instance.changed(['date','duration', 'frequency']):
|
pks = [ d.pk for d in qs if instance.match(d.date) ]
|
||||||
return
|
|
||||||
|
|
||||||
old = models.Schedule(**{ key: initial.get(key)
|
|
||||||
for key in ('date','timezone','duration','frequency')
|
|
||||||
})
|
|
||||||
|
|
||||||
qs = models.Diffusion.objects.station(
|
|
||||||
instance.program.station,
|
|
||||||
)
|
|
||||||
|
|
||||||
pks = [ item.pk for item in qs if old.match(item.date) ]
|
|
||||||
qs.filter(pk__in = pks).delete()
|
qs.filter(pk__in = pks).delete()
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user