Browse Source

properly flood with fixed start time (#294)

pull/295/head
Jason Dove 4 years ago committed by GitHub
parent
commit
45f1c6b22a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 176
      ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs
  2. 1
      ErsatzTV.Core/Domain/PlayoutAnchor.cs
  3. 18
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  4. 2979
      ErsatzTV.Infrastructure/Migrations/20210709184335_Add_PlayoutAnchorInFlood.Designer.cs
  5. 23
      ErsatzTV.Infrastructure/Migrations/20210709184335_Add_PlayoutAnchorInFlood.cs
  6. 5
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

176
ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs

@ -458,6 +458,182 @@ namespace ErsatzTV.Core.Tests.Scheduling
result.Items[5].MediaItemId.Should().Be(2); result.Items[5].MediaItemId.Should().Be(2);
} }
[Test]
public async Task FloodContent_Should_FloodWithFixedStartTime()
{
var floodCollection = new Collection
{
Id = 1,
Name = "Flood Items",
MediaItems = new List<MediaItem>
{
TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)),
TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1))
}
};
var fixedCollection = new Collection
{
Id = 2,
Name = "Fixed Items",
MediaItems = new List<MediaItem>
{
TestMovie(3, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)),
TestMovie(4, TimeSpan.FromHours(1), new DateTime(2020, 1, 2))
}
};
var fakeRepository = new FakeMediaCollectionRepository(
Map(
(floodCollection.Id, floodCollection.MediaItems.ToList()),
(fixedCollection.Id, fixedCollection.MediaItems.ToList())));
var items = new List<ProgramScheduleItem>
{
new ProgramScheduleItemFlood
{
Index = 1,
Collection = floodCollection,
CollectionId = floodCollection.Id,
StartTime = TimeSpan.FromHours(7)
},
new ProgramScheduleItemOne
{
Index = 2,
Collection = fixedCollection,
CollectionId = fixedCollection.Id,
StartTime = TimeSpan.FromHours(12)
}
};
var playout = new Playout
{
ProgramSchedule = new ProgramSchedule
{
Items = items,
MediaCollectionPlaybackOrder = PlaybackOrder.Chronological
},
Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" }
};
var televisionRepo = new FakeTelevisionRepository();
var artistRepo = new Mock<IArtistRepository>();
var builder = new PlayoutBuilder(fakeRepository, televisionRepo, artistRepo.Object, _logger);
DateTimeOffset start = HoursAfterMidnight(0);
DateTimeOffset finish = start + TimeSpan.FromHours(24);
Playout result = await builder.BuildPlayoutItems(playout, start, finish);
result.Items.Count.Should().Be(6);
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(7));
result.Items[0].MediaItemId.Should().Be(1);
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(8));
result.Items[1].MediaItemId.Should().Be(2);
result.Items[2].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(9));
result.Items[2].MediaItemId.Should().Be(1);
result.Items[3].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(10));
result.Items[3].MediaItemId.Should().Be(2);
result.Items[4].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(11));
result.Items[4].MediaItemId.Should().Be(1);
result.Items[5].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(12));
result.Items[5].MediaItemId.Should().Be(3);
}
[Test]
public async Task FloodContent_Should_FloodWithFixedStartTime_FromAnchor()
{
var floodCollection = new Collection
{
Id = 1,
Name = "Flood Items",
MediaItems = new List<MediaItem>
{
TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)),
TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1))
}
};
var fixedCollection = new Collection
{
Id = 2,
Name = "Fixed Items",
MediaItems = new List<MediaItem>
{
TestMovie(3, TimeSpan.FromHours(2), new DateTime(2020, 1, 1)),
TestMovie(4, TimeSpan.FromHours(1), new DateTime(2020, 1, 2))
}
};
var fakeRepository = new FakeMediaCollectionRepository(
Map(
(floodCollection.Id, floodCollection.MediaItems.ToList()),
(fixedCollection.Id, fixedCollection.MediaItems.ToList())));
var items = new List<ProgramScheduleItem>
{
new ProgramScheduleItemFlood
{
Index = 1,
Collection = floodCollection,
CollectionId = floodCollection.Id,
StartTime = TimeSpan.FromHours(7)
},
new ProgramScheduleItemOne
{
Index = 2,
Collection = fixedCollection,
CollectionId = fixedCollection.Id,
StartTime = TimeSpan.FromHours(12)
}
};
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(9).UtcDateTime,
NextScheduleItem = items[0],
NextScheduleItemId = 1,
InFlood = true
}
};
var televisionRepo = new FakeTelevisionRepository();
var artistRepo = new Mock<IArtistRepository>();
var builder = new PlayoutBuilder(fakeRepository, televisionRepo, artistRepo.Object, _logger);
DateTimeOffset start = HoursAfterMidnight(0);
DateTimeOffset finish = start + TimeSpan.FromHours(32);
Playout result = await builder.BuildPlayoutItems(playout, start, finish);
result.Items.Count.Should().Be(5);
result.Items[0].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(9));
result.Items[0].MediaItemId.Should().Be(1);
result.Items[1].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(10));
result.Items[1].MediaItemId.Should().Be(2);
result.Items[2].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(11));
result.Items[2].MediaItemId.Should().Be(1);
result.Items[3].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(12));
result.Items[3].MediaItemId.Should().Be(3);
result.Items[4].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(7));
result.Items[4].MediaItemId.Should().Be(2);
result.Anchor.InFlood.Should().BeTrue();
}
[Test] [Test]
public async Task FloodContent_Should_FloodAroundFixedContent_DurationWithoutOfflineTail() public async Task FloodContent_Should_FloodAroundFixedContent_DurationWithoutOfflineTail()
{ {

1
ErsatzTV.Core/Domain/PlayoutAnchor.cs

@ -13,6 +13,7 @@ namespace ErsatzTV.Core.Domain
public DateTime NextStart { get; set; } public DateTime NextStart { get; set; }
public int? MultipleRemaining { get; set; } public int? MultipleRemaining { get; set; }
public DateTime? DurationFinish { get; set; } public DateTime? DurationFinish { get; set; }
public bool InFlood { get; set; }
public DateTimeOffset NextStartOffset => new DateTimeOffset(NextStart, TimeSpan.Zero).ToLocalTime(); public DateTimeOffset NextStartOffset => new DateTimeOffset(NextStart, TimeSpan.Zero).ToLocalTime();

18
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -201,6 +201,7 @@ namespace ErsatzTV.Core.Scheduling
// start with the previous multiple/duration states // start with the previous multiple/duration states
Option<int> multipleRemaining = Optional(startAnchor.MultipleRemaining); Option<int> multipleRemaining = Optional(startAnchor.MultipleRemaining);
Option<DateTimeOffset> durationFinish = startAnchor.DurationFinishOffset; Option<DateTimeOffset> durationFinish = startAnchor.DurationFinishOffset;
bool inFlood = startAnchor.InFlood;
bool customGroup = multipleRemaining.IsSome || durationFinish.IsSome; bool customGroup = multipleRemaining.IsSome || durationFinish.IsSome;
@ -215,7 +216,8 @@ namespace ErsatzTV.Core.Scheduling
scheduleItem, scheduleItem,
currentTime, currentTime,
multipleRemaining.IsSome, multipleRemaining.IsSome,
durationFinish.IsSome); durationFinish.IsSome,
inFlood);
IMediaCollectionEnumerator enumerator = collectionEnumerators[CollectionKeyForItem(scheduleItem)]; IMediaCollectionEnumerator enumerator = collectionEnumerators[CollectionKeyForItem(scheduleItem)];
await enumerator.Current.IfSomeAsync( await enumerator.Current.IfSomeAsync(
@ -318,6 +320,11 @@ namespace ErsatzTV.Core.Scheduling
"Flood"); "Flood");
index++; index++;
customGroup = false; customGroup = false;
inFlood = false;
}
else
{
inFlood = true;
} }
}); });
break; break;
@ -374,7 +381,8 @@ namespace ErsatzTV.Core.Scheduling
NextScheduleItemId = nextScheduleItem.Id, NextScheduleItemId = nextScheduleItem.Id,
NextStart = GetStartTimeAfter(nextScheduleItem, currentTime).UtcDateTime, NextStart = GetStartTimeAfter(nextScheduleItem, currentTime).UtcDateTime,
MultipleRemaining = multipleRemaining.IsSome ? multipleRemaining.ValueUnsafe() : null, MultipleRemaining = multipleRemaining.IsSome ? multipleRemaining.ValueUnsafe() : null,
DurationFinish = durationFinish.IsSome ? durationFinish.ValueUnsafe().UtcDateTime : null DurationFinish = durationFinish.IsSome ? durationFinish.ValueUnsafe().UtcDateTime : null,
InFlood = inFlood
}; };
// build program schedule anchors // build program schedule anchors
@ -419,13 +427,15 @@ namespace ErsatzTV.Core.Scheduling
ProgramScheduleItem item, ProgramScheduleItem item,
DateTimeOffset start, DateTimeOffset start,
bool inMultiple = false, bool inMultiple = false,
bool inDuration = false) bool inDuration = false,
bool inFlood = false)
{ {
switch (item.StartType) switch (item.StartType)
{ {
case StartType.Fixed: case StartType.Fixed:
if (item is ProgramScheduleItemMultiple && inMultiple || if (item is ProgramScheduleItemMultiple && inMultiple ||
item is ProgramScheduleItemDuration && inDuration) item is ProgramScheduleItemDuration && inDuration ||
item is ProgramScheduleItemFlood && inFlood)
{ {
return start; return start;
} }

2979
ErsatzTV.Infrastructure/Migrations/20210709184335_Add_PlayoutAnchorInFlood.Designer.cs generated

File diff suppressed because it is too large Load Diff

23
ErsatzTV.Infrastructure/Migrations/20210709184335_Add_PlayoutAnchorInFlood.cs

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_PlayoutAnchorInFlood : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "Anchor_InFlood",
table: "Playout",
type: "INTEGER",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Anchor_InFlood",
table: "Playout");
}
}
}

5
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -14,7 +14,7 @@ namespace ErsatzTV.Infrastructure.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "5.0.6"); .HasAnnotation("ProductVersion", "5.0.7");
modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b => modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b =>
{ {
@ -2189,6 +2189,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b1.Property<DateTime?>("DurationFinish") b1.Property<DateTime?>("DurationFinish")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b1.Property<bool>("InFlood")
.HasColumnType("INTEGER");
b1.Property<int?>("MultipleRemaining") b1.Property<int?>("MultipleRemaining")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");

Loading…
Cancel
Save