Merge pull request #1356 from jooola/fix/api_cueout
Fix cueout for schedule starts overlapping show ends
This commit is contained in:
commit
f9f7f83ef7
|
@ -24,26 +24,58 @@ class Schedule(models.Model):
|
||||||
|
|
||||||
def get_cueout(self):
|
def get_cueout(self):
|
||||||
"""
|
"""
|
||||||
Returns a cueout that is based on the current show. Cueout of a specific
|
Returns a scheduled item cueout that is based on the current show instance.
|
||||||
item can potentially overrun the show that it is scheduled in. In that
|
|
||||||
case, the cueout should be the end of the show. This prevents the next
|
Cueout of a specific item can potentially overrun the show that it is
|
||||||
show having overlapping items playing.
|
scheduled in. In that case, the cueout should be the end of the show.
|
||||||
|
This prevents the next show having overlapping items playing.
|
||||||
|
|
||||||
|
Cases:
|
||||||
|
- When the schedule ends before the end of the show instance,
|
||||||
|
return the stored cueout.
|
||||||
|
|
||||||
|
- When the schedule starts before the end of the show instance
|
||||||
|
and ends after the show instance ends,
|
||||||
|
return timedelta between schedule starts and show instance ends.
|
||||||
|
|
||||||
|
- When the schedule starts after the end of the show instance,
|
||||||
|
return the stored cue_out even if the schedule WILL NOT BE PLAYED.
|
||||||
"""
|
"""
|
||||||
if self.instance.ends < self.ends:
|
if self.starts < self.instance.ends and self.instance.ends < self.ends:
|
||||||
return self.instance.ends - self.starts
|
return self.instance.ends - self.starts
|
||||||
return self.cue_out
|
return self.cue_out
|
||||||
|
|
||||||
def get_ends(self):
|
def get_ends(self):
|
||||||
"""
|
"""
|
||||||
Returns an item end that is based on the current show. Ends of a
|
Returns a scheduled item ends that is based on the current show instance.
|
||||||
specific item can potentially overrun the show that it is scheduled in.
|
|
||||||
In that case, the end should be the end of the show. This prevents the
|
End of a specific item can potentially overrun the show that it is
|
||||||
next show having overlapping items playing.
|
scheduled in. In that case, the end should be the end of the show.
|
||||||
|
This prevents the next show having overlapping items playing.
|
||||||
|
|
||||||
|
Cases:
|
||||||
|
- When the schedule ends before the end of the show instance,
|
||||||
|
return the scheduled item ends.
|
||||||
|
|
||||||
|
- When the schedule starts before the end of the show instance
|
||||||
|
and ends after the show instance ends,
|
||||||
|
return the show instance ends.
|
||||||
|
|
||||||
|
- When the schedule starts after the end of the show instance,
|
||||||
|
return the show instance ends.
|
||||||
"""
|
"""
|
||||||
if self.instance.ends < self.ends:
|
if self.instance.ends < self.ends:
|
||||||
return self.instance.ends
|
return self.instance.ends
|
||||||
return self.ends
|
return self.ends
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self):
|
||||||
|
"""
|
||||||
|
A schedule item is valid if it starts before the end of the show instance
|
||||||
|
it is in
|
||||||
|
"""
|
||||||
|
return self.starts < self.instance.ends
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
managed = False
|
managed = False
|
||||||
db_table = "cc_schedule"
|
db_table = "cc_schedule"
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from django.test import SimpleTestCase
|
||||||
|
from libretimeapi.models import Schedule, ShowInstance
|
||||||
|
|
||||||
|
|
||||||
|
class TestSchedule(SimpleTestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.show_instance = ShowInstance(
|
||||||
|
created=datetime(year=2021, month=10, day=1, hour=12),
|
||||||
|
starts=datetime(year=2021, month=10, day=2, hour=1),
|
||||||
|
ends=datetime(year=2021, month=10, day=2, hour=2),
|
||||||
|
)
|
||||||
|
cls.length = timedelta(minutes=10)
|
||||||
|
cls.cue_in = timedelta(seconds=1)
|
||||||
|
cls.cue_out = cls.length - timedelta(seconds=4)
|
||||||
|
|
||||||
|
def create_schedule(self, starts):
|
||||||
|
return Schedule(
|
||||||
|
starts=starts,
|
||||||
|
ends=starts + self.length,
|
||||||
|
cue_in=self.cue_in,
|
||||||
|
cue_out=self.cue_out,
|
||||||
|
instance=self.show_instance,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_cueout(self):
|
||||||
|
# No overlapping schedule datetimes, normal usecase:
|
||||||
|
s1_starts = datetime(year=2021, month=10, day=2, hour=1, minute=30)
|
||||||
|
s1 = self.create_schedule(s1_starts)
|
||||||
|
self.assertEqual(s1.get_cueout(), self.cue_out)
|
||||||
|
self.assertEqual(s1.get_ends(), s1_starts + self.length)
|
||||||
|
|
||||||
|
# Mixed overlapping schedule datetimes (only ends is overlapping):
|
||||||
|
s2_starts = datetime(year=2021, month=10, day=2, hour=1, minute=55)
|
||||||
|
s2 = self.create_schedule(s2_starts)
|
||||||
|
self.assertEqual(s2.get_cueout(), timedelta(minutes=5))
|
||||||
|
self.assertEqual(s2.get_ends(), self.show_instance.ends)
|
||||||
|
|
||||||
|
# Fully overlapping schedule datetimes (starts and ends are overlapping):
|
||||||
|
s3_starts = datetime(year=2021, month=10, day=2, hour=2, minute=1)
|
||||||
|
s3 = self.create_schedule(s3_starts)
|
||||||
|
self.assertEqual(s3.get_cueout(), self.cue_out)
|
||||||
|
self.assertEqual(s3.get_ends(), self.show_instance.ends)
|
||||||
|
|
||||||
|
def test_is_valid(self):
|
||||||
|
# Starts before the schedule ends
|
||||||
|
s1_starts = datetime(year=2021, month=10, day=2, hour=1, minute=30)
|
||||||
|
s1 = self.create_schedule(s1_starts)
|
||||||
|
self.assertTrue(s1.is_valid)
|
||||||
|
|
||||||
|
# Starts after the schedule ends
|
||||||
|
s2_starts = datetime(year=2021, month=10, day=2, hour=3)
|
||||||
|
s2 = self.create_schedule(s2_starts)
|
||||||
|
self.assertFalse(s2.is_valid)
|
|
@ -141,7 +141,7 @@ class PreferenceViewSet(viewsets.ModelViewSet):
|
||||||
class ScheduleViewSet(viewsets.ModelViewSet):
|
class ScheduleViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Schedule.objects.all()
|
queryset = Schedule.objects.all()
|
||||||
serializer_class = ScheduleSerializer
|
serializer_class = ScheduleSerializer
|
||||||
filter_fields = ("starts", "ends", "playout_status", "broadcasted")
|
filter_fields = ("starts", "ends", "playout_status", "broadcasted", "is_valid")
|
||||||
model_permission_name = "schedule"
|
model_permission_name = "schedule"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ class AirtimeApiClient:
|
||||||
data = self.services.schedule_url(
|
data = self.services.schedule_url(
|
||||||
params={
|
params={
|
||||||
"ends__range": ("{}Z,{}Z".format(str_current, str_end)),
|
"ends__range": ("{}Z,{}Z".format(str_current, str_end)),
|
||||||
|
"is_valid": True,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
result = {"media": {}}
|
result = {"media": {}}
|
||||||
|
|
Loading…
Reference in New Issue