fix playout builds using duration or multiple (#115)
This commit is contained in:
@@ -610,6 +610,190 @@ namespace ErsatzTV.Core.Tests.Scheduling
|
||||
result.Items[5].MediaItemId.Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Alternating_MultipleContent_Should_Maintain_Counts()
|
||||
{
|
||||
var collectionOne = new Collection
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Multiple Items 1",
|
||||
MediaItems = new List<MediaItem>
|
||||
{
|
||||
TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1))
|
||||
}
|
||||
};
|
||||
|
||||
var collectionTwo = new Collection
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Multiple Items 2",
|
||||
MediaItems = new List<MediaItem>
|
||||
{
|
||||
TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 1, 1))
|
||||
}
|
||||
};
|
||||
|
||||
var fakeRepository = new FakeMediaCollectionRepository(
|
||||
Map(
|
||||
(collectionOne.Id, collectionOne.MediaItems.ToList()),
|
||||
(collectionTwo.Id, collectionTwo.MediaItems.ToList())));
|
||||
|
||||
var items = new List<ProgramScheduleItem>
|
||||
{
|
||||
new ProgramScheduleItemMultiple
|
||||
{
|
||||
Id = 1,
|
||||
Index = 1,
|
||||
Collection = collectionOne,
|
||||
CollectionId = collectionOne.Id,
|
||||
StartTime = null,
|
||||
Count = 3
|
||||
},
|
||||
new ProgramScheduleItemMultiple
|
||||
{
|
||||
Id = 2,
|
||||
Index = 2,
|
||||
Collection = collectionTwo,
|
||||
CollectionId = collectionTwo.Id,
|
||||
StartTime = null,
|
||||
Count = 3
|
||||
}
|
||||
};
|
||||
|
||||
var playout = new Playout
|
||||
{
|
||||
ProgramSchedule = new ProgramSchedule
|
||||
{
|
||||
Items = items,
|
||||
MediaCollectionPlaybackOrder = PlaybackOrder.Chronological
|
||||
},
|
||||
Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" },
|
||||
Anchor = new PlayoutAnchor
|
||||
{
|
||||
NextStart = HoursAfterMidnight(1).UtcDateTime,
|
||||
NextScheduleItem = items[0],
|
||||
NextScheduleItemId = 1,
|
||||
MultipleRemaining = 2
|
||||
}
|
||||
};
|
||||
|
||||
var televisionRepo = new FakeTelevisionRepository();
|
||||
var builder = new PlayoutBuilder(fakeRepository, televisionRepo, _logger);
|
||||
|
||||
DateTimeOffset start = HoursAfterMidnight(0);
|
||||
DateTimeOffset finish = start + TimeSpan.FromHours(5);
|
||||
|
||||
Playout result = await builder.BuildPlayoutItems(playout, start, finish);
|
||||
|
||||
result.Items.Count.Should().Be(4);
|
||||
|
||||
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(1));
|
||||
result.Items[0].MediaItemId.Should().Be(1);
|
||||
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(2));
|
||||
result.Items[1].MediaItemId.Should().Be(1);
|
||||
|
||||
result.Items[2].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(3));
|
||||
result.Items[2].MediaItemId.Should().Be(2);
|
||||
result.Items[3].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(4));
|
||||
result.Items[3].MediaItemId.Should().Be(2);
|
||||
|
||||
result.Anchor.NextScheduleItem.Should().Be(items[1]);
|
||||
result.Anchor.MultipleRemaining.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Alternating_Duration_Should_Maintain_Duration()
|
||||
{
|
||||
var collectionOne = new Collection
|
||||
{
|
||||
Id = 1,
|
||||
Name = "Duration Items 1",
|
||||
MediaItems = new List<MediaItem>
|
||||
{
|
||||
TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1))
|
||||
}
|
||||
};
|
||||
|
||||
var collectionTwo = new Collection
|
||||
{
|
||||
Id = 2,
|
||||
Name = "Duration Items 2",
|
||||
MediaItems = new List<MediaItem>
|
||||
{
|
||||
TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 1, 1))
|
||||
}
|
||||
};
|
||||
|
||||
var fakeRepository = new FakeMediaCollectionRepository(
|
||||
Map(
|
||||
(collectionOne.Id, collectionOne.MediaItems.ToList()),
|
||||
(collectionTwo.Id, collectionTwo.MediaItems.ToList())));
|
||||
|
||||
var items = new List<ProgramScheduleItem>
|
||||
{
|
||||
new ProgramScheduleItemDuration
|
||||
{
|
||||
Id = 1,
|
||||
Index = 1,
|
||||
Collection = collectionOne,
|
||||
CollectionId = collectionOne.Id,
|
||||
StartTime = null,
|
||||
PlayoutDuration = TimeSpan.FromHours(3),
|
||||
OfflineTail = false
|
||||
},
|
||||
new ProgramScheduleItemDuration
|
||||
{
|
||||
Id = 2,
|
||||
Index = 2,
|
||||
Collection = collectionTwo,
|
||||
CollectionId = collectionTwo.Id,
|
||||
StartTime = null,
|
||||
PlayoutDuration = TimeSpan.FromHours(3),
|
||||
OfflineTail = false
|
||||
}
|
||||
};
|
||||
|
||||
var playout = new Playout
|
||||
{
|
||||
ProgramSchedule = new ProgramSchedule
|
||||
{
|
||||
Items = items,
|
||||
MediaCollectionPlaybackOrder = PlaybackOrder.Chronological
|
||||
},
|
||||
Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" },
|
||||
Anchor = new PlayoutAnchor
|
||||
{
|
||||
NextStart = HoursAfterMidnight(1).UtcDateTime,
|
||||
NextScheduleItem = items[0],
|
||||
NextScheduleItemId = 1,
|
||||
DurationFinish = HoursAfterMidnight(3).UtcDateTime
|
||||
}
|
||||
};
|
||||
|
||||
var televisionRepo = new FakeTelevisionRepository();
|
||||
var builder = new PlayoutBuilder(fakeRepository, televisionRepo, _logger);
|
||||
|
||||
DateTimeOffset start = HoursAfterMidnight(0);
|
||||
DateTimeOffset finish = start + TimeSpan.FromHours(5);
|
||||
|
||||
Playout result = await builder.BuildPlayoutItems(playout, start, finish);
|
||||
|
||||
result.Items.Count.Should().Be(4);
|
||||
|
||||
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(1));
|
||||
result.Items[0].MediaItemId.Should().Be(1);
|
||||
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(2));
|
||||
result.Items[1].MediaItemId.Should().Be(1);
|
||||
|
||||
result.Items[2].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(3));
|
||||
result.Items[2].MediaItemId.Should().Be(2);
|
||||
result.Items[3].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(4));
|
||||
result.Items[3].MediaItemId.Should().Be(2);
|
||||
|
||||
result.Anchor.NextScheduleItem.Should().Be(items[1]);
|
||||
result.Anchor.DurationFinish.Should().Be(HoursAfterMidnight(6).UtcDateTime);
|
||||
}
|
||||
|
||||
private static DateTimeOffset HoursAfterMidnight(int hours)
|
||||
{
|
||||
DateTimeOffset now = DateTimeOffset.Now;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using LanguageExt;
|
||||
using static LanguageExt.Prelude;
|
||||
|
||||
namespace ErsatzTV.Core.Domain
|
||||
{
|
||||
@@ -9,7 +11,13 @@ namespace ErsatzTV.Core.Domain
|
||||
public ProgramScheduleItem NextScheduleItem { get; set; }
|
||||
|
||||
public DateTime NextStart { get; set; }
|
||||
public int? MultipleRemaining { get; set; }
|
||||
public DateTime? DurationFinish { get; set; }
|
||||
|
||||
public DateTimeOffset NextStartOffset => new DateTimeOffset(NextStart, TimeSpan.Zero).ToLocalTime();
|
||||
|
||||
public Option<DateTimeOffset> DurationFinishOffset =>
|
||||
Optional(DurationFinish)
|
||||
.Map(durationFinish => new DateTimeOffset(durationFinish, TimeSpan.Zero).ToLocalTime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,10 @@ namespace ErsatzTV.Core.Scheduling
|
||||
// start with the previously-decided schedule item
|
||||
int index = sortedScheduleItems.IndexOf(startAnchor.NextScheduleItem);
|
||||
|
||||
Option<int> multipleRemaining = None;
|
||||
Option<DateTimeOffset> durationFinish = None;
|
||||
// start with the previous multiple/duration states
|
||||
Option<int> multipleRemaining = Optional(startAnchor.MultipleRemaining);
|
||||
Option<DateTimeOffset> durationFinish = startAnchor.DurationFinishOffset;
|
||||
|
||||
// loop until we're done filling the desired amount of time
|
||||
while (currentTime < playoutFinish)
|
||||
{
|
||||
@@ -298,7 +300,9 @@ namespace ErsatzTV.Core.Scheduling
|
||||
{
|
||||
NextScheduleItem = nextScheduleItem,
|
||||
NextScheduleItemId = nextScheduleItem.Id,
|
||||
NextStart = GetStartTimeAfter(nextScheduleItem, currentTime).UtcDateTime
|
||||
NextStart = GetStartTimeAfter(nextScheduleItem, currentTime).UtcDateTime,
|
||||
MultipleRemaining = multipleRemaining.IsSome ? multipleRemaining.ValueUnsafe() : null,
|
||||
DurationFinish = durationFinish.IsSome ? durationFinish.ValueUnsafe().UtcDateTime : null
|
||||
};
|
||||
|
||||
// build program schedule anchors
|
||||
|
||||
Generated
+1820
File diff suppressed because it is too large
Load Diff
+34
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Migrations
|
||||
{
|
||||
public partial class Add_PlayoutAnchor_DurationMultiple : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
"Anchor_DurationFinish",
|
||||
"Playout",
|
||||
"TEXT",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
"Anchor_MultipleRemaining",
|
||||
"Playout",
|
||||
"INTEGER",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
"Anchor_DurationFinish",
|
||||
"Playout");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
"Anchor_MultipleRemaining",
|
||||
"Playout");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1412,6 +1412,12 @@ namespace ErsatzTV.Infrastructure.Migrations
|
||||
b1.Property<int>("PlayoutId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.Property<DateTime?>("DurationFinish")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b1.Property<int?>("MultipleRemaining")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b1.Property<int>("NextScheduleItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user