Browse Source

add option to shuffle schedule items (#652)

* add schedule setting

* it works

* fix tests

* update readme

* rebuild all playouts
pull/655/head
Jason Dove 3 years ago committed by GitHub
parent
commit
78fdc9c57a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 3
      ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramSchedule.cs
  3. 3
      ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramScheduleHandler.cs
  4. 3
      ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs
  5. 6
      ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs
  6. 3
      ErsatzTV.Application/ProgramSchedules/Mapper.cs
  7. 3
      ErsatzTV.Application/ProgramSchedules/ProgramScheduleViewModel.cs
  8. 3
      ErsatzTV.Application/ProgramSchedules/Queries/GetAllProgramSchedulesHandler.cs
  9. 2
      ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleByIdHandler.cs
  10. 31
      ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleItemsHandler.cs
  11. 31
      ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs
  12. 186
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerDurationTests.cs
  13. 226
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerFloodTests.cs
  14. 162
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs
  15. 178
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerOneTests.cs
  16. 7
      ErsatzTV.Core.Tests/Scheduling/SchedulerTestBase.cs
  17. 5
      ErsatzTV.Core/Domain/PlayoutAnchor.cs
  18. 1
      ErsatzTV.Core/Domain/ProgramSchedule.cs
  19. 12
      ErsatzTV.Core/Interfaces/Scheduling/IScheduleItemsEnumerator.cs
  20. 40
      ErsatzTV.Core/Scheduling/OrderedScheduleItemsEnumerator.cs
  21. 35
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  22. 3
      ErsatzTV.Core/Scheduling/PlayoutBuilderState.cs
  23. 10
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs
  24. 22
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  25. 3
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs
  26. 4
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerOne.cs
  27. 107
      ErsatzTV.Core/Scheduling/ShuffledScheduleItemsEnumerator.cs
  28. 4
      ErsatzTV.Infrastructure/Data/Configurations/PlayoutConfiguration.cs
  29. 3875
      ErsatzTV.Infrastructure/Migrations/20220223000405_Add_ProgramScheduleShuffleScheduleItems.Designer.cs
  30. 26
      ErsatzTV.Infrastructure/Migrations/20220223000405_Add_ProgramScheduleShuffleScheduleItems.cs
  31. 3883
      ErsatzTV.Infrastructure/Migrations/20220223020421_Add_PlayoutAnchorScheduleItemsEnumeratorState.Designer.cs
  32. 69
      ErsatzTV.Infrastructure/Migrations/20220223020421_Add_PlayoutAnchorScheduleItemsEnumeratorState.cs
  33. 3883
      ErsatzTV.Infrastructure/Migrations/20220223031713_Rebuild_AllPlayouts20220222.Designer.cs
  34. 20
      ErsatzTV.Infrastructure/Migrations/20220223031713_Rebuild_AllPlayouts20220222.cs
  35. 35
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  36. 8
      ErsatzTV/Pages/ScheduleEditor.razor
  37. 30
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  38. 5
      ErsatzTV/ViewModels/ProgramScheduleEditViewModel.cs
  39. 1
      ErsatzTV/ViewModels/ProgramScheduleItemsEditViewModel.cs

3
CHANGELOG.md

@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Add configurable channel group (M3U) and categories (XMLTV)
- Add `Shuffle Schedule Items` option to schedule configuration
- When this is enabled, schedule items will be shuffled rather than looped in order
- **To support this, all playouts will be rebuilt (one time) after upgrading to this version**
### Changed
- Disable framerate normalization by default and on all ffmpeg profiles

3
ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramSchedule.cs

@ -8,5 +8,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands @@ -8,5 +8,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
public record CreateProgramSchedule(
string Name,
bool KeepMultiPartEpisodesTogether,
bool TreatCollectionsAsShows) : IRequest<Either<BaseError, CreateProgramScheduleResult>>;
bool TreatCollectionsAsShows,
bool ShuffleScheduleItems) : IRequest<Either<BaseError, CreateProgramScheduleResult>>;
}

3
ErsatzTV.Application/ProgramSchedules/Commands/CreateProgramScheduleHandler.cs

@ -50,7 +50,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands @@ -50,7 +50,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
{
Name = name,
KeepMultiPartEpisodesTogether = keepMultiPartEpisodesTogether,
TreatCollectionsAsShows = keepMultiPartEpisodesTogether && request.TreatCollectionsAsShows
TreatCollectionsAsShows = keepMultiPartEpisodesTogether && request.TreatCollectionsAsShows,
ShuffleScheduleItems = request.ShuffleScheduleItems
};
});

3
ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramSchedule.cs

@ -10,5 +10,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands @@ -10,5 +10,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
int ProgramScheduleId,
string Name,
bool KeepMultiPartEpisodesTogether,
bool TreatCollectionsAsShows) : IRequest<Either<BaseError, UpdateProgramScheduleResult>>;
bool TreatCollectionsAsShows,
bool ShuffleScheduleItems) : IRequest<Either<BaseError, UpdateProgramScheduleResult>>;
}

6
ErsatzTV.Application/ProgramSchedules/Commands/UpdateProgramScheduleHandler.cs

@ -31,7 +31,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands @@ -31,7 +31,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
UpdateProgramSchedule request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Validation<BaseError, ProgramSchedule> validation = await Validate(dbContext, request);
return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request));
@ -45,12 +45,14 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands @@ -45,12 +45,14 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
// we need to rebuild playouts if the playback order or keep multi-episodes has been modified
bool needToRebuildPlayout =
programSchedule.KeepMultiPartEpisodesTogether != request.KeepMultiPartEpisodesTogether ||
programSchedule.TreatCollectionsAsShows != request.TreatCollectionsAsShows;
programSchedule.TreatCollectionsAsShows != request.TreatCollectionsAsShows ||
programSchedule.ShuffleScheduleItems != request.ShuffleScheduleItems;
programSchedule.Name = request.Name;
programSchedule.KeepMultiPartEpisodesTogether = request.KeepMultiPartEpisodesTogether;
programSchedule.TreatCollectionsAsShows = programSchedule.KeepMultiPartEpisodesTogether &&
request.TreatCollectionsAsShows;
programSchedule.ShuffleScheduleItems = request.ShuffleScheduleItems;
await dbContext.SaveChangesAsync();

3
ErsatzTV.Application/ProgramSchedules/Mapper.cs

@ -10,7 +10,8 @@ namespace ErsatzTV.Application.ProgramSchedules @@ -10,7 +10,8 @@ namespace ErsatzTV.Application.ProgramSchedules
programSchedule.Id,
programSchedule.Name,
programSchedule.KeepMultiPartEpisodesTogether,
programSchedule.TreatCollectionsAsShows);
programSchedule.TreatCollectionsAsShows,
programSchedule.ShuffleScheduleItems);
internal static ProgramScheduleItemViewModel ProjectToViewModel(ProgramScheduleItem programScheduleItem) =>
programScheduleItem switch

3
ErsatzTV.Application/ProgramSchedules/ProgramScheduleViewModel.cs

@ -4,5 +4,6 @@ @@ -4,5 +4,6 @@
int Id,
string Name,
bool KeepMultiPartEpisodesTogether,
bool TreatCollectionsAsShows);
bool TreatCollectionsAsShows,
bool ShuffleScheduleItems);
}

3
ErsatzTV.Application/ProgramSchedules/Queries/GetAllProgramSchedulesHandler.cs

@ -25,7 +25,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries @@ -25,7 +25,8 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries
ps.Id,
ps.Name,
ps.KeepMultiPartEpisodesTogether,
ps.TreatCollectionsAsShows))
ps.TreatCollectionsAsShows,
ps.ShuffleScheduleItems))
.ToListAsync(cancellationToken);
}
}

2
ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleByIdHandler.cs

@ -21,7 +21,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries @@ -21,7 +21,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries
GetProgramScheduleById request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
return await dbContext.ProgramSchedules
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.Id)
.MapT(ProjectToViewModel);

31
ErsatzTV.Application/ProgramSchedules/Queries/GetProgramScheduleItemsHandler.cs

@ -4,6 +4,7 @@ using System.Threading; @@ -4,6 +4,7 @@ using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using LanguageExt;
using MediatR;
using Microsoft.EntityFrameworkCore;
@ -23,7 +24,11 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries @@ -23,7 +24,11 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries
GetProgramScheduleItems request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<ProgramSchedule> maybeProgramSchedule =
await dbContext.ProgramSchedules.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.Id);
return await dbContext.ProgramScheduleItems
.Filter(psi => psi.ProgramScheduleId == request.Id)
.Include(i => i.Collection)
@ -51,7 +56,29 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries @@ -51,7 +56,29 @@ namespace ErsatzTV.Application.ProgramSchedules.Queries
.Include(i => i.TailFiller)
.Include(i => i.FallbackFiller)
.ToListAsync(cancellationToken)
.Map(programScheduleItems => programScheduleItems.Map(ProjectToViewModel).ToList());
.Map(
programScheduleItems => programScheduleItems.Map(ProjectToViewModel)
.Map(psi => EnforceProperties(maybeProgramSchedule, psi)).ToList());
}
// shuffled schedule items supports a limited set of properly values
private ProgramScheduleItemViewModel EnforceProperties(
Option<ProgramSchedule> maybeProgramSchedule,
ProgramScheduleItemViewModel item)
{
foreach (ProgramSchedule programSchedule in maybeProgramSchedule)
{
if (programSchedule.ShuffleScheduleItems)
{
item = item with { StartType = StartType.Dynamic };
if (item.PlayoutMode == PlayoutMode.Flood)
{
item = item with { PlayoutMode = PlayoutMode.One };
}
}
}
return item;
}
}
}

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

@ -624,8 +624,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -624,8 +624,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
Anchor = new PlayoutAnchor
{
NextStart = HoursAfterMidnight(9).UtcDateTime,
NextScheduleItem = items[0],
NextScheduleItemId = 1,
ScheduleItemsEnumeratorState = new CollectionEnumeratorState
{
Index = 0,
Seed = 1
},
InFlood = true
}
};
@ -918,8 +921,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -918,8 +921,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
Anchor = new PlayoutAnchor
{
NextStart = HoursAfterMidnight(1).UtcDateTime,
NextScheduleItem = items[0],
NextScheduleItemId = 1,
ScheduleItemsEnumeratorState = new CollectionEnumeratorState
{
Index = 0,
Seed = 1
},
MultipleRemaining = 2
}
};
@ -951,7 +957,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -951,7 +957,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
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.ScheduleItemsEnumeratorState.Index.Should().Be(1);
result.Anchor.MultipleRemaining.Should().Be(1);
}
@ -1048,7 +1054,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -1048,7 +1054,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
result.Items[4].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(4));
result.Items[4].MediaItemId.Should().Be(5);
result.Anchor.NextScheduleItem.Should().Be(items[0]);
result.Anchor.ScheduleItemsEnumeratorState.Index.Should().Be(0);
result.Anchor.MultipleRemaining.Should().BeNull();
}
@ -1116,8 +1122,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -1116,8 +1122,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
Anchor = new PlayoutAnchor
{
NextStart = HoursAfterMidnight(1).UtcDateTime,
NextScheduleItem = items[0],
NextScheduleItemId = 1,
ScheduleItemsEnumeratorState = new CollectionEnumeratorState
{
Index = 0,
Seed = 1
},
DurationFinish = HoursAfterMidnight(3).UtcDateTime
}
};
@ -1149,7 +1158,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -1149,7 +1158,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
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.ScheduleItemsEnumeratorState.Index.Should().Be(1);
result.Anchor.DurationFinish.Should().Be(HoursAfterMidnight(6).UtcDateTime);
}
@ -1284,7 +1293,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -1284,7 +1293,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
result.Items[11].StartOffset.TimeOfDay.Should().Be(new TimeSpan(5, 55, 0));
result.Items[11].MediaItemId.Should().Be(3);
result.Anchor.NextScheduleItem.Should().Be(items[0]);
result.Anchor.ScheduleItemsEnumeratorState.Index.Should().Be(0);
result.Anchor.DurationFinish.Should().BeNull();
}
@ -1361,7 +1370,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -1361,7 +1370,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
result.Items[5].StartOffset.TimeOfDay.Should().Be(TimeSpan.FromHours(5));
result.Items[5].MediaItemId.Should().Be(4);
result.Anchor.NextScheduleItem.Should().Be(items[0]);
result.Anchor.ScheduleItemsEnumeratorState.Index.Should().Be(0);
result.Anchor.DurationFinish.Should().BeNull();
}

186
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerDurationTests.cs

@ -31,19 +31,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -31,19 +31,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
PlaybackOrder = PlaybackOrder.Chronological
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -51,26 +57,26 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -51,26 +57,26 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
@ -94,19 +100,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -94,19 +100,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
CustomTitle = "Custom Title"
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -114,28 +126,28 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -114,28 +126,28 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[0].CustomTitle.Should().Be("Custom Title");
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].CustomTitle.Should().Be("Custom Title");
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
@ -159,19 +171,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -159,19 +171,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
PlaybackOrder = PlaybackOrder.Chronological
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -179,26 +197,26 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -179,26 +197,26 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
@ -221,47 +239,53 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -221,47 +239,53 @@ namespace ErsatzTV.Core.Tests.Scheduling
PlaybackOrder = PlaybackOrder.Chronological
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
// duration block should end after exact duration, with gap
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutBuilderState.NextGuideGroup.Should().Be(4);
playoutBuilderState.DurationFinish.IsNone.Should().BeTrue();
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
@ -291,6 +315,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -291,6 +315,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -299,15 +327,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -299,15 +327,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -315,7 +345,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -315,7 +345,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -323,25 +353,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -323,25 +353,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Fallback);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
@ -371,6 +401,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -371,6 +401,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -379,15 +413,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -379,15 +413,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -395,7 +431,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -395,7 +431,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -403,37 +439,37 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -403,37 +439,37 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
@ -463,6 +499,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -463,6 +499,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -471,23 +511,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -471,23 +511,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutBuilderState.NextGuideGroup.Should().Be(4);
playoutBuilderState.DurationFinish.IsNone.Should().BeTrue();
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -495,37 +537,37 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -495,37 +537,37 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].GuideFinish.HasValue.Should().BeFalse();
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].GuideFinish.HasValue.Should().BeFalse();
@ -562,6 +604,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -562,6 +604,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -574,9 +620,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -574,9 +620,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerDuration(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -586,9 +634,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -586,9 +634,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -596,7 +644,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -596,7 +644,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -605,43 +653,43 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -605,43 +653,43 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(7);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[0].GuideFinish.HasValue.Should().BeFalse();
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].GuideFinish.HasValue.Should().BeFalse();
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].GuideFinish.HasValue.Should().BeTrue();
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].GuideFinish.HasValue.Should().BeFalse();
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].GuideFinish.HasValue.Should().BeFalse();
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].GuideFinish.HasValue.Should().BeFalse();
playoutItems[6].MediaItemId.Should().Be(5);
playoutItems[6].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].GuideGroup.Should().Be(3);
playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback);
playoutItems[6].GuideFinish.HasValue.Should().BeFalse();

226
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerFloodTests.cs

@ -41,15 +41,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -41,15 +41,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -57,24 +63,24 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -57,24 +63,24 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}
@ -110,15 +116,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -110,15 +116,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -126,24 +138,24 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -126,24 +138,24 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}
@ -188,15 +200,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -188,15 +200,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -204,7 +222,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -204,7 +222,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -212,32 +230,32 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -212,32 +230,32 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[2].MediaItemId.Should().Be(2);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[2].GuideGroup.Should().Be(2);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(4);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 55, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 55, 0)));
playoutItems[3].GuideGroup.Should().Be(2);
playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[4].MediaItemId.Should().Be(1);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.None);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.PostRoll);
}
@ -269,15 +287,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -269,15 +287,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -285,24 +309,24 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -285,24 +309,24 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}
@ -344,15 +368,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -344,15 +368,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -360,7 +390,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -360,7 +390,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -368,32 +398,32 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -368,32 +398,32 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
}
@ -435,15 +465,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -435,15 +465,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -451,7 +487,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -451,7 +487,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -459,22 +495,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -459,22 +495,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -516,15 +552,21 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -516,15 +552,21 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -532,7 +574,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -532,7 +574,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -540,32 +582,32 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -540,32 +582,32 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
}
@ -617,9 +659,15 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -617,9 +659,15 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -629,9 +677,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -629,9 +677,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -639,7 +687,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -639,7 +687,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -648,37 +696,37 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -648,37 +696,37 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(7);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[6].MediaItemId.Should().Be(5);
playoutItems[6].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].GuideGroup.Should().Be(3);
playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -730,9 +778,15 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -730,9 +778,15 @@ namespace ErsatzTV.Core.Tests.Scheduling
NextScheduleItem
};
var scheduler = new PlayoutModeSchedulerFlood(sortedScheduleItems, new Mock<ILogger>().Object);
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
sortedScheduleItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerFlood(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -742,9 +796,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -742,9 +796,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -752,7 +806,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -752,7 +806,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(1);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(0);
@ -761,17 +815,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -761,17 +815,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}

162
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerMultipleTests.cs

@ -34,6 +34,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -34,6 +34,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -43,15 +47,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -43,15 +47,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForScheduleItem(scheduleItem), collectionOne.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -59,24 +65,24 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -59,24 +65,24 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}
@ -99,6 +105,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -99,6 +105,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -108,15 +118,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -108,15 +118,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForScheduleItem(scheduleItem), collectionOne.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -124,24 +136,24 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -124,24 +136,24 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}
@ -170,6 +182,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -170,6 +182,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -184,15 +200,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -184,15 +200,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForFillerPreset(scheduleItem.TailFiller), collectionTwo.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -200,7 +218,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -200,7 +218,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -208,32 +226,32 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -208,32 +226,32 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
}
@ -262,6 +280,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -262,6 +280,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -276,15 +298,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -276,15 +298,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForFillerPreset(scheduleItem.FallbackFiller), collectionTwo.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -292,7 +316,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -292,7 +316,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -300,22 +324,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -300,22 +324,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -344,6 +368,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -344,6 +368,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -358,15 +386,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -358,15 +386,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForFillerPreset(scheduleItem.TailFiller), collectionTwo.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -374,7 +404,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -374,7 +404,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -382,32 +412,32 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -382,32 +412,32 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(6);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
}
@ -442,6 +472,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -442,6 +472,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -461,9 +495,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -461,9 +495,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForFillerPreset(scheduleItem.FallbackFiller), collectionThree.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -473,9 +509,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -473,9 +509,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -483,7 +519,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -483,7 +519,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -492,37 +528,37 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -492,37 +528,37 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(7);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddMinutes(55));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddMinutes(55));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(1, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[3].GuideGroup.Should().Be(3);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(4);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[4].GuideGroup.Should().Be(3);
playoutItems[4].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[5].MediaItemId.Should().Be(3);
playoutItems[5].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[5].GuideGroup.Should().Be(3);
playoutItems[5].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[6].MediaItemId.Should().Be(5);
playoutItems[6].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[6].GuideGroup.Should().Be(3);
playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -557,6 +593,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -557,6 +593,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
Count = 3
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -576,9 +616,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -576,9 +616,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
{ CollectionKey.ForFillerPreset(scheduleItem.FallbackFiller), collectionThree.MediaItems }
}.ToMap();
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerMultiple(collectionMediaItems, new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -588,9 +630,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -588,9 +630,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(4);
@ -598,7 +640,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -598,7 +640,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(0);
@ -607,17 +649,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -607,17 +649,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(3);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(2);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(2);
playoutItems[1].FillerKind.Should().Be(FillerKind.None);
playoutItems[2].MediaItemId.Should().Be(1);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.AddHours(2));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.AddHours(2));
playoutItems[2].GuideGroup.Should().Be(3);
playoutItems[2].FillerKind.Should().Be(FillerKind.None);
}

178
ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerOneTests.cs

@ -31,19 +31,25 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -31,19 +31,25 @@ namespace ErsatzTV.Core.Tests.Scheduling
FallbackFiller = null
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(1));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -51,14 +57,14 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -51,14 +57,14 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator.State.Index.Should().Be(1);
playoutItems.Count.Should().Be(1);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
}
@ -92,6 +98,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -92,6 +98,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -104,15 +114,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -104,15 +114,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(1));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -120,7 +132,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -120,7 +132,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(0);
@ -129,7 +141,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -129,7 +141,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(1);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
}
@ -157,6 +169,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -157,6 +169,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
FallbackFiller = null
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -165,15 +181,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -165,15 +181,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -181,7 +199,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -181,7 +199,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -189,22 +207,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -189,22 +207,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[2].MediaItemId.Should().Be(4);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].GuideGroup.Should().Be(1);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
}
@ -232,6 +250,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -232,6 +250,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -240,15 +262,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -240,15 +262,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -256,7 +280,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -256,7 +280,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -264,12 +288,12 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -264,12 +288,12 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(2);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.AddHours(1));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.AddHours(1));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -297,6 +321,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -297,6 +321,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
FallbackFiller = null
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -305,15 +333,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -305,15 +333,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionTwo.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -321,7 +351,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -321,7 +351,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -329,22 +359,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -329,22 +359,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[2].MediaItemId.Should().Be(4);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[3].GuideGroup.Should().Be(1);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
}
@ -378,6 +408,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -378,6 +408,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -390,9 +424,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -390,9 +424,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -402,9 +438,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -402,9 +438,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -412,7 +448,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -412,7 +448,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -421,27 +457,27 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -421,27 +457,27 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(5);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[2].MediaItemId.Should().Be(4);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 49, 0)));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 53, 0)));
playoutItems[3].GuideGroup.Should().Be(1);
playoutItems[3].FillerKind.Should().Be(FillerKind.Tail);
playoutItems[4].MediaItemId.Should().Be(5);
playoutItems[4].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[4].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
playoutItems[4].GuideGroup.Should().Be(1);
playoutItems[4].FillerKind.Should().Be(FillerKind.Fallback);
}
@ -475,6 +511,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -475,6 +511,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -487,9 +527,11 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -487,9 +527,11 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(
scheduleItem,
enumerator1,
@ -499,9 +541,9 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -499,9 +541,9 @@ namespace ErsatzTV.Core.Tests.Scheduling
enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -509,7 +551,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -509,7 +551,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(0);
@ -518,7 +560,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -518,7 +560,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(1);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
}
@ -554,6 +596,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -554,6 +596,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -566,15 +612,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -566,15 +612,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -582,7 +630,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -582,7 +630,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -590,22 +638,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -590,22 +638,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[2].MediaItemId.Should().Be(4);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].GuideGroup.Should().Be(1);
playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll);
}
@ -641,6 +689,10 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -641,6 +689,10 @@ namespace ErsatzTV.Core.Tests.Scheduling
}
};
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
new List<ProgramScheduleItem> { scheduleItem },
new CollectionEnumeratorState());
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
collectionOne.MediaItems,
new CollectionEnumeratorState());
@ -653,15 +705,17 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -653,15 +705,17 @@ namespace ErsatzTV.Core.Tests.Scheduling
collectionThree.MediaItems,
new CollectionEnumeratorState());
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
StartState,
startState,
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3),
scheduleItem,
NextScheduleItem,
HardStop);
HardStop(scheduleItemsEnumerator));
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddHours(3));
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
playoutBuilderState.NextGuideGroup.Should().Be(2);
@ -669,7 +723,7 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -669,7 +723,7 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutBuilderState.InFlood.Should().BeFalse();
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
playoutBuilderState.InDurationFiller.Should().BeFalse();
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
enumerator1.State.Index.Should().Be(1);
enumerator2.State.Index.Should().Be(1);
@ -678,22 +732,22 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -678,22 +732,22 @@ namespace ErsatzTV.Core.Tests.Scheduling
playoutItems.Count.Should().Be(4);
playoutItems[0].MediaItemId.Should().Be(1);
playoutItems[0].StartOffset.Should().Be(StartState.CurrentTime);
playoutItems[0].StartOffset.Should().Be(startState.CurrentTime);
playoutItems[0].GuideGroup.Should().Be(1);
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
playoutItems[1].MediaItemId.Should().Be(3);
playoutItems[1].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
playoutItems[1].GuideGroup.Should().Be(1);
playoutItems[1].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[2].MediaItemId.Should().Be(4);
playoutItems[2].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 50, 0)));
playoutItems[2].GuideGroup.Should().Be(1);
playoutItems[2].FillerKind.Should().Be(FillerKind.PostRoll);
playoutItems[3].MediaItemId.Should().Be(3);
playoutItems[3].StartOffset.Should().Be(StartState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].StartOffset.Should().Be(startState.CurrentTime.Add(new TimeSpan(2, 55, 0)));
playoutItems[3].GuideGroup.Should().Be(1);
playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll);
}

7
ErsatzTV.Core.Tests/Scheduling/SchedulerTestBase.cs

@ -10,8 +10,8 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -10,8 +10,8 @@ namespace ErsatzTV.Core.Tests.Scheduling
{
public abstract class SchedulerTestBase
{
protected static PlayoutBuilderState StartState => new(
0,
protected static PlayoutBuilderState StartState(IScheduleItemsEnumerator scheduleItemsEnumerator) => new(
scheduleItemsEnumerator,
Prelude.None,
Prelude.None,
false,
@ -24,7 +24,8 @@ namespace ErsatzTV.Core.Tests.Scheduling @@ -24,7 +24,8 @@ namespace ErsatzTV.Core.Tests.Scheduling
StartTime = null
};
protected static DateTimeOffset HardStop => StartState.CurrentTime.AddHours(6);
protected static DateTimeOffset HardStop(IScheduleItemsEnumerator scheduleItemsEnumerator) =>
StartState(scheduleItemsEnumerator).CurrentTime.AddHours(6);
protected static Dictionary<CollectionKey, IMediaCollectionEnumerator> CollectionEnumerators(
ProgramScheduleItem scheduleItem, IMediaCollectionEnumerator enumerator) =>

5
ErsatzTV.Core/Domain/PlayoutAnchor.cs

@ -6,10 +6,7 @@ namespace ErsatzTV.Core.Domain @@ -6,10 +6,7 @@ namespace ErsatzTV.Core.Domain
{
public class PlayoutAnchor
{
public int NextScheduleItemId { get; set; }
public ProgramScheduleItem NextScheduleItem { get; set; }
public CollectionEnumeratorState ScheduleItemsEnumeratorState { get; set; }
public DateTime NextStart { get; set; }
public int? MultipleRemaining { get; set; }
public DateTime? DurationFinish { get; set; }

1
ErsatzTV.Core/Domain/ProgramSchedule.cs

@ -8,6 +8,7 @@ namespace ErsatzTV.Core.Domain @@ -8,6 +8,7 @@ namespace ErsatzTV.Core.Domain
public string Name { get; set; }
public bool KeepMultiPartEpisodesTogether { get; set; }
public bool TreatCollectionsAsShows { get; set; }
public bool ShuffleScheduleItems { get; set; }
public List<ProgramScheduleItem> Items { get; set; }
public List<Playout> Playouts { get; set; }
}

12
ErsatzTV.Core/Interfaces/Scheduling/IScheduleItemsEnumerator.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
using ErsatzTV.Core.Domain;
using LanguageExt;
namespace ErsatzTV.Core.Interfaces.Scheduling;
public interface IScheduleItemsEnumerator
{
CollectionEnumeratorState State { get; }
ProgramScheduleItem Current { get; }
void MoveNext();
ProgramScheduleItem Peek(int offset);
}

40
ErsatzTV.Core/Scheduling/OrderedScheduleItemsEnumerator.cs

@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Linq;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling;
public class OrderedScheduleItemsEnumerator : IScheduleItemsEnumerator
{
private readonly IList<ProgramScheduleItem> _sortedScheduleItems;
public OrderedScheduleItemsEnumerator(
IEnumerable<ProgramScheduleItem> scheduleItems,
CollectionEnumeratorState state)
{
_sortedScheduleItems = scheduleItems.OrderBy(i => i.Index).ToList();
State = new CollectionEnumeratorState { Seed = state.Seed };
if (state.Index >= _sortedScheduleItems.Count)
{
state.Index = 0;
state.Seed = 0;
}
while (State.Index < state.Index)
{
MoveNext();
}
}
public CollectionEnumeratorState State { get; }
public ProgramScheduleItem Current => _sortedScheduleItems[State.Index];
public void MoveNext() => State.Index = (State.Index + 1) % _sortedScheduleItems.Count;
public ProgramScheduleItem Peek(int offset) =>
_sortedScheduleItems[(State.Index + offset) % _sortedScheduleItems.Count];
}

35
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -3,7 +3,6 @@ using System.Collections.Generic; @@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Scheduling;
using LanguageExt;
@ -105,6 +104,12 @@ namespace ErsatzTV.Core.Scheduling @@ -105,6 +104,12 @@ namespace ErsatzTV.Core.Scheduling
}
var sortedScheduleItems = playout.ProgramSchedule.Items.OrderBy(i => i.Index).ToList();
CollectionEnumeratorState scheduleItemsEnumeratorState =
playout.Anchor?.ScheduleItemsEnumeratorState ?? new CollectionEnumeratorState
{ Seed = Random.Next(), Index = 0 };
IScheduleItemsEnumerator scheduleItemsEnumerator = playout.ProgramSchedule.ShuffleScheduleItems
? new ShuffledScheduleItemsEnumerator(playout.ProgramSchedule.Items, scheduleItemsEnumeratorState)
: new OrderedScheduleItemsEnumerator(playout.ProgramSchedule.Items, scheduleItemsEnumeratorState);
var collectionEnumerators = new Dictionary<CollectionKey, IMediaCollectionEnumerator>();
foreach ((CollectionKey collectionKey, List<MediaItem> mediaItems) in collectionMediaItems)
{
@ -119,7 +124,7 @@ namespace ErsatzTV.Core.Scheduling @@ -119,7 +124,7 @@ namespace ErsatzTV.Core.Scheduling
}
// find start anchor
PlayoutAnchor startAnchor = FindStartAnchor(playout, playoutStart, sortedScheduleItems);
PlayoutAnchor startAnchor = FindStartAnchor(playout, playoutStart, scheduleItemsEnumerator);
// start at the previously-decided time
DateTimeOffset currentTime = startAnchor.NextStartOffset.ToLocalTime();
@ -142,7 +147,7 @@ namespace ErsatzTV.Core.Scheduling @@ -142,7 +147,7 @@ namespace ErsatzTV.Core.Scheduling
// start with the previously-decided schedule item
// start with the previous multiple/duration states
var playoutBuilderState = new PlayoutBuilderState(
sortedScheduleItems.IndexOf(startAnchor.NextScheduleItem),
scheduleItemsEnumerator,
Optional(startAnchor.MultipleRemaining),
startAnchor.DurationFinishOffset,
startAnchor.InFlood,
@ -153,17 +158,15 @@ namespace ErsatzTV.Core.Scheduling @@ -153,17 +158,15 @@ namespace ErsatzTV.Core.Scheduling
var schedulerOne = new PlayoutModeSchedulerOne(_logger);
var schedulerMultiple = new PlayoutModeSchedulerMultiple(collectionMediaItems, _logger);
var schedulerDuration = new PlayoutModeSchedulerDuration(_logger);
var schedulerFlood = new PlayoutModeSchedulerFlood(sortedScheduleItems, _logger);
var schedulerFlood = new PlayoutModeSchedulerFlood(_logger);
// loop until we're done filling the desired amount of time
while (playoutBuilderState.CurrentTime < playoutFinish)
{
// get the schedule item out of the sorted list
ProgramScheduleItem scheduleItem =
sortedScheduleItems[playoutBuilderState.ScheduleItemIndex % sortedScheduleItems.Count];
ProgramScheduleItem scheduleItem = playoutBuilderState.ScheduleItemsEnumerator.Current;
ProgramScheduleItem nextScheduleItem =
sortedScheduleItems[(playoutBuilderState.ScheduleItemIndex + 1) % sortedScheduleItems.Count];
ProgramScheduleItem nextScheduleItem = playoutBuilderState.ScheduleItemsEnumerator.Peek(1);
Tuple<PlayoutBuilderState, List<PlayoutItem>> result = scheduleItem switch
{
@ -205,8 +208,7 @@ namespace ErsatzTV.Core.Scheduling @@ -205,8 +208,7 @@ namespace ErsatzTV.Core.Scheduling
}
// once more to get playout anchor
ProgramScheduleItem anchorScheduleItem =
sortedScheduleItems[playoutBuilderState.ScheduleItemIndex % sortedScheduleItems.Count];
ProgramScheduleItem anchorScheduleItem = playoutBuilderState.ScheduleItemsEnumerator.Current;
// build program schedule anchors
playout.ProgramScheduleAnchors = BuildProgramScheduleAnchors(playout, collectionEnumerators);
@ -226,8 +228,7 @@ namespace ErsatzTV.Core.Scheduling @@ -226,8 +228,7 @@ namespace ErsatzTV.Core.Scheduling
playout.Anchor = new PlayoutAnchor
{
NextScheduleItem = anchorScheduleItem,
NextScheduleItemId = anchorScheduleItem.Id,
ScheduleItemsEnumeratorState = playoutBuilderState.ScheduleItemsEnumerator.State,
NextStart = PlayoutModeSchedulerBase<ProgramScheduleItem>.GetStartTimeAfter(playoutBuilderState, anchorScheduleItem)
.UtcDateTime,
MultipleRemaining = playoutBuilderState.MultipleRemaining.IsSome
@ -320,18 +321,17 @@ namespace ErsatzTV.Core.Scheduling @@ -320,18 +321,17 @@ namespace ErsatzTV.Core.Scheduling
private static PlayoutAnchor FindStartAnchor(
Playout playout,
DateTimeOffset start,
IReadOnlyCollection<ProgramScheduleItem> sortedScheduleItems) =>
IScheduleItemsEnumerator enumerator) =>
Optional(playout.Anchor).IfNone(
() =>
{
ProgramScheduleItem schedule = sortedScheduleItems.Head();
ProgramScheduleItem schedule = enumerator.Current;
switch (schedule.StartType)
{
case StartType.Fixed:
return new PlayoutAnchor
{
NextScheduleItem = schedule,
NextScheduleItemId = schedule.Id,
ScheduleItemsEnumeratorState = enumerator.State,
NextStart = (start - start.TimeOfDay).UtcDateTime +
schedule.StartTime.GetValueOrDefault()
};
@ -339,8 +339,7 @@ namespace ErsatzTV.Core.Scheduling @@ -339,8 +339,7 @@ namespace ErsatzTV.Core.Scheduling
default:
return new PlayoutAnchor
{
NextScheduleItem = schedule,
NextScheduleItemId = schedule.Id,
ScheduleItemsEnumeratorState = enumerator.State,
NextStart = (start - start.TimeOfDay).UtcDateTime
};
}

3
ErsatzTV.Core/Scheduling/PlayoutBuilderState.cs

@ -1,10 +1,11 @@ @@ -1,10 +1,11 @@
using System;
using ErsatzTV.Core.Interfaces.Scheduling;
using LanguageExt;
namespace ErsatzTV.Core.Scheduling
{
public record PlayoutBuilderState(
int ScheduleItemIndex,
IScheduleItemsEnumerator ScheduleItemsEnumerator,
Option<int> MultipleRemaining,
Option<DateTimeOffset> DurationFinish,
bool InFlood,

10
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

@ -122,9 +122,10 @@ namespace ErsatzTV.Core.Scheduling @@ -122,9 +122,10 @@ namespace ErsatzTV.Core.Scheduling
nextState = nextState with
{
DurationFinish = None,
ScheduleItemIndex = nextState.ScheduleItemIndex + 1
DurationFinish = None
};
nextState.ScheduleItemsEnumerator.MoveNext();
}
}
@ -133,9 +134,10 @@ namespace ErsatzTV.Core.Scheduling @@ -133,9 +134,10 @@ namespace ErsatzTV.Core.Scheduling
{
nextState = nextState with
{
DurationFinish = None,
ScheduleItemIndex = nextState.ScheduleItemIndex + 1
DurationFinish = None
};
nextState.ScheduleItemsEnumerator.MoveNext();
}
if (playoutItems.Select(pi => pi.GuideGroup).Distinct().Count() != 1)

22
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -12,12 +12,9 @@ namespace ErsatzTV.Core.Scheduling @@ -12,12 +12,9 @@ namespace ErsatzTV.Core.Scheduling
{
public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramScheduleItemFlood>
{
private readonly List<ProgramScheduleItem> _sortedScheduleItems;
public PlayoutModeSchedulerFlood(List<ProgramScheduleItem> sortedScheduleItems, ILogger logger)
public PlayoutModeSchedulerFlood(ILogger logger)
: base(logger)
{
_sortedScheduleItems = sortedScheduleItems;
}
public override Tuple<PlayoutBuilderState, List<PlayoutItem>> Schedule(
@ -35,8 +32,7 @@ namespace ErsatzTV.Core.Scheduling @@ -35,8 +32,7 @@ namespace ErsatzTV.Core.Scheduling
IMediaCollectionEnumerator contentEnumerator =
collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)];
ProgramScheduleItem peekScheduleItem =
_sortedScheduleItems[(nextState.ScheduleItemIndex + 1) % _sortedScheduleItems.Count];
ProgramScheduleItem peekScheduleItem = nextScheduleItem;
while (contentEnumerator.Current.IsSome && nextState.CurrentTime < hardStop && willFinishInTime)
{
@ -81,7 +77,7 @@ namespace ErsatzTV.Core.Scheduling @@ -81,7 +77,7 @@ namespace ErsatzTV.Core.Scheduling
{
playoutItems.AddRange(
AddFiller(nextState, collectionEnumerators, scheduleItem, playoutItem, itemChapters));
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
DateTimeOffset actualEndTime = playoutItems.Max(p => p.FinishOffset);
if (Math.Abs((itemEndTimeWithFiller - actualEndTime).TotalSeconds) > 1)
@ -105,19 +101,19 @@ namespace ErsatzTV.Core.Scheduling @@ -105,19 +101,19 @@ namespace ErsatzTV.Core.Scheduling
}
}
// _logger.LogDebug(
// "Advancing to next schedule item after playout mode {PlayoutMode}",
// "Flood");
_logger.LogDebug(
"Advancing to next schedule item after playout mode {PlayoutMode}",
"Flood");
nextState = nextState with
{
ScheduleItemIndex = nextState.ScheduleItemIndex + 1,
InFlood = nextState.CurrentTime >= hardStop,
NextGuideGroup = nextState.DecrementGuideGroup
};
ProgramScheduleItem peekItem =
_sortedScheduleItems[nextState.ScheduleItemIndex % _sortedScheduleItems.Count];
nextState.ScheduleItemsEnumerator.MoveNext();
ProgramScheduleItem peekItem = nextScheduleItem;
DateTimeOffset peekItemStart = GetStartTimeAfter(nextState, peekItem);
if (scheduleItem.TailFiller != null)

3
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerMultiple.cs

@ -97,10 +97,11 @@ namespace ErsatzTV.Core.Scheduling @@ -97,10 +97,11 @@ namespace ErsatzTV.Core.Scheduling
nextState = nextState with
{
ScheduleItemIndex = nextState.ScheduleItemIndex + 1,
MultipleRemaining = None,
NextGuideGroup = nextState.DecrementGuideGroup
};
nextState.ScheduleItemsEnumerator.MoveNext();
}
DateTimeOffset nextItemStart = GetStartTimeAfter(nextState, nextScheduleItem);

4
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerOne.cs

@ -67,10 +67,10 @@ namespace ErsatzTV.Core.Scheduling @@ -67,10 +67,10 @@ namespace ErsatzTV.Core.Scheduling
PlayoutBuilderState nextState = playoutBuilderState with
{
CurrentTime = itemEndTimeWithFiller,
ScheduleItemIndex = playoutBuilderState.ScheduleItemIndex + 1
CurrentTime = itemEndTimeWithFiller
};
nextState.ScheduleItemsEnumerator.MoveNext();
contentEnumerator.MoveNext();
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime);

107
ErsatzTV.Core/Scheduling/ShuffledScheduleItemsEnumerator.cs

@ -0,0 +1,107 @@ @@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling;
public class ShuffledScheduleItemsEnumerator : IScheduleItemsEnumerator
{
private readonly int _scheduleItemsCount;
private readonly IList<ProgramScheduleItem> _scheduleItems;
private CloneableRandom _random;
private IList<ProgramScheduleItem> _shuffled;
public ShuffledScheduleItemsEnumerator(
IList<ProgramScheduleItem> scheduleItems,
CollectionEnumeratorState state)
{
_scheduleItemsCount = scheduleItems.Count;
_scheduleItems = scheduleItems;
if (state.Index >= _scheduleItems.Count)
{
state.Index = 0;
state.Seed = new Random(state.Seed).Next();
}
_random = new CloneableRandom(state.Seed);
_shuffled = Shuffle(_scheduleItems, _random);
State = new CollectionEnumeratorState { Seed = state.Seed };
while (State.Index < state.Index)
{
MoveNext();
}
}
public CollectionEnumeratorState State { get; }
public ProgramScheduleItem Current => _shuffled[State.Index % _scheduleItemsCount];
public void MoveNext()
{
if ((State.Index + 1) % _scheduleItemsCount == 0)
{
ProgramScheduleItem tail = Current;
State.Index = 0;
do
{
State.Seed = _random.Next();
_random = new CloneableRandom(State.Seed);
_shuffled = Shuffle(_scheduleItems, _random);
} while (_scheduleItems.Count > 1 && Current == tail);
}
else
{
State.Index++;
}
State.Index %= _scheduleItemsCount;
}
public ProgramScheduleItem Peek(int offset)
{
if (offset == 0)
{
return Current;
}
if ((State.Index + offset) % _scheduleItemsCount == 0)
{
IList<ProgramScheduleItem> shuffled;
ProgramScheduleItem tail = Current;
// clone the random
CloneableRandom randomCopy = _random.Clone();
do
{
int newSeed = randomCopy.Next();
randomCopy = new CloneableRandom(newSeed);
shuffled = Shuffle(_scheduleItems, randomCopy);
} while (_scheduleItems.Count > 1 && shuffled[0] == tail);
return shuffled[0];
}
return _shuffled[(State.Index + offset) % _scheduleItemsCount];
}
private IList<ProgramScheduleItem> Shuffle(IEnumerable<ProgramScheduleItem> list, CloneableRandom random)
{
ProgramScheduleItem[] copy = list.ToArray();
int n = copy.Length;
while (n > 1)
{
n--;
int k = random.Next(n + 1);
(copy[k], copy[n]) = (copy[n], copy[k]);
}
return copy;
}
}

4
ErsatzTV.Infrastructure/Data/Configurations/PlayoutConfiguration.cs

@ -16,7 +16,9 @@ namespace ErsatzTV.Infrastructure.Data.Configurations @@ -16,7 +16,9 @@ namespace ErsatzTV.Infrastructure.Data.Configurations
.OnDelete(DeleteBehavior.Cascade);
builder.OwnsOne(p => p.Anchor)
.ToTable("PlayoutAnchor");
.ToTable("PlayoutAnchor")
.OwnsOne(a => a.ScheduleItemsEnumeratorState)
.ToTable("ScheduleItemsEnumeratorState");
builder.HasMany(p => p.ProgramScheduleAnchors)
.WithOne(a => a.Playout)

3875
ErsatzTV.Infrastructure/Migrations/20220223000405_Add_ProgramScheduleShuffleScheduleItems.Designer.cs generated

File diff suppressed because it is too large Load Diff

26
ErsatzTV.Infrastructure/Migrations/20220223000405_Add_ProgramScheduleShuffleScheduleItems.cs

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_ProgramScheduleShuffleScheduleItems : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ShuffleScheduleItems",
table: "ProgramSchedule",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ShuffleScheduleItems",
table: "ProgramSchedule");
}
}
}

3883
ErsatzTV.Infrastructure/Migrations/20220223020421_Add_PlayoutAnchorScheduleItemsEnumeratorState.Designer.cs generated

File diff suppressed because it is too large Load Diff

69
ErsatzTV.Infrastructure/Migrations/20220223020421_Add_PlayoutAnchorScheduleItemsEnumeratorState.cs

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_PlayoutAnchorScheduleItemsEnumeratorState : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PlayoutAnchor_ProgramScheduleItem_NextScheduleItemId",
table: "PlayoutAnchor");
migrationBuilder.DropIndex(
name: "IX_PlayoutAnchor_NextScheduleItemId",
table: "PlayoutAnchor");
migrationBuilder.DropColumn(
name: "NextScheduleItemId",
table: "PlayoutAnchor");
migrationBuilder.CreateTable(
name: "ScheduleItemsEnumeratorState",
columns: table => new
{
PlayoutAnchorPlayoutId = table.Column<int>(type: "INTEGER", nullable: false),
Seed = table.Column<int>(type: "INTEGER", nullable: false),
Index = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ScheduleItemsEnumeratorState", x => x.PlayoutAnchorPlayoutId);
table.ForeignKey(
name: "FK_ScheduleItemsEnumeratorState_PlayoutAnchor_PlayoutAnchorPlayoutId",
column: x => x.PlayoutAnchorPlayoutId,
principalTable: "PlayoutAnchor",
principalColumn: "PlayoutId",
onDelete: ReferentialAction.Cascade);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ScheduleItemsEnumeratorState");
migrationBuilder.AddColumn<int>(
name: "NextScheduleItemId",
table: "PlayoutAnchor",
type: "INTEGER",
nullable: false,
defaultValue: 0);
migrationBuilder.CreateIndex(
name: "IX_PlayoutAnchor_NextScheduleItemId",
table: "PlayoutAnchor",
column: "NextScheduleItemId");
migrationBuilder.AddForeignKey(
name: "FK_PlayoutAnchor_ProgramScheduleItem_NextScheduleItemId",
table: "PlayoutAnchor",
column: "NextScheduleItemId",
principalTable: "ProgramScheduleItem",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

3883
ErsatzTV.Infrastructure/Migrations/20220223031713_Rebuild_AllPlayouts20220222.Designer.cs generated

File diff suppressed because it is too large Load Diff

20
ErsatzTV.Infrastructure/Migrations/20220223031713_Rebuild_AllPlayouts20220222.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Rebuild_AllPlayouts20220222 : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"DELETE FROM PlayoutItem");
migrationBuilder.Sql(@"DELETE FROM PlayoutProgramScheduleAnchor");
migrationBuilder.Sql(@"DELETE FROM PlayoutAnchor");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

35
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -1438,6 +1438,9 @@ namespace ErsatzTV.Infrastructure.Migrations @@ -1438,6 +1438,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<string>("Name")
.HasColumnType("TEXT");
b.Property<bool>("ShuffleScheduleItems")
.HasColumnType("INTEGER");
b.Property<bool>("TreatCollectionsAsShows")
.HasColumnType("INTEGER");
@ -2877,28 +2880,36 @@ namespace ErsatzTV.Infrastructure.Migrations @@ -2877,28 +2880,36 @@ namespace ErsatzTV.Infrastructure.Migrations
b1.Property<int>("NextGuideGroup")
.HasColumnType("INTEGER");
b1.Property<int>("NextScheduleItemId")
.HasColumnType("INTEGER");
b1.Property<DateTime>("NextStart")
.HasColumnType("TEXT");
b1.HasKey("PlayoutId");
b1.HasIndex("NextScheduleItemId");
b1.ToTable("PlayoutAnchor", (string)null);
b1.HasOne("ErsatzTV.Core.Domain.ProgramScheduleItem", "NextScheduleItem")
.WithMany()
.HasForeignKey("NextScheduleItemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b1.WithOwner()
.HasForeignKey("PlayoutId");
b1.Navigation("NextScheduleItem");
b1.OwnsOne("ErsatzTV.Core.Domain.CollectionEnumeratorState", "ScheduleItemsEnumeratorState", b2 =>
{
b2.Property<int>("PlayoutAnchorPlayoutId")
.HasColumnType("INTEGER");
b2.Property<int>("Index")
.HasColumnType("INTEGER");
b2.Property<int>("Seed")
.HasColumnType("INTEGER");
b2.HasKey("PlayoutAnchorPlayoutId");
b2.ToTable("ScheduleItemsEnumeratorState", (string)null);
b2.WithOwner()
.HasForeignKey("PlayoutAnchorPlayoutId");
});
b1.Navigation("ScheduleItemsEnumeratorState");
});
b.Navigation("Anchor");

8
ErsatzTV/Pages/ScheduleEditor.razor

@ -31,6 +31,13 @@ @@ -31,6 +31,13 @@
For="@(() => _model.TreatCollectionsAsShows)"/>
</MudTooltip>
</MudElement>
<MudElement HtmlTag="div" Class="mt-3">
<MudTooltip Text="Note: this disables fixed start times and flood mode">
<MudCheckBox Label="Shuffle Schedule Items"
@bind-Checked="@_model.ShuffleScheduleItems"
For="@(() => _model.ShuffleScheduleItems)"/>
</MudTooltip>
</MudElement>
</MudCardContent>
<MudCardActions>
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary">
@ -61,6 +68,7 @@ @@ -61,6 +68,7 @@
{
_model.Id = viewModel.Id;
_model.Name = viewModel.Name;
_model.ShuffleScheduleItems = viewModel.ShuffleScheduleItems;
_model.KeepMultiPartEpisodesTogether = viewModel.KeepMultiPartEpisodesTogether;
_model.TreatCollectionsAsShows = viewModel.TreatCollectionsAsShows;
},

30
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -57,16 +57,22 @@ @@ -57,16 +57,22 @@
</MudText>
</MudTd>
<MudTd>
@if (!_schedule.ShuffleScheduleItems)
{
<MudIconButton Icon="@Icons.Material.Filled.ArrowUpward"
OnClick="@(_ => MoveItemUp(context))"
Disabled="@(_schedule.Items.All(x => x.Index >= context.Index))">
Disabled="@(_schedule.ShuffleScheduleItems || _schedule.Items.All(x => x.Index >= context.Index))">
</MudIconButton>
}
</MudTd>
<MudTd>
@if (!_schedule.ShuffleScheduleItems)
{
<MudIconButton Icon="@Icons.Material.Filled.ArrowDownward"
OnClick="@(_ => MoveItemDown(context))"
Disabled="@(_schedule.Items.All(x => x.Index <= context.Index))">
Disabled="@(_schedule.ShuffleScheduleItems || _schedule.Items.All(x => x.Index <= context.Index))">
</MudIconButton>
}
</MudTd>
<MudTd>
<MudIconButton Icon="@Icons.Material.Filled.Delete"
@ -91,9 +97,10 @@ @@ -91,9 +97,10 @@
<MudCard>
<MudCardContent>
<MudSelect Label="Start Type" @bind-Value="_selectedItem.StartType" For="@(() => _selectedItem.StartType)">
@foreach (StartType startType in Enum.GetValues<StartType>())
<MudSelectItem Value="StartType.Dynamic">Dynamic</MudSelectItem>
@if (!_schedule.ShuffleScheduleItems)
{
<MudSelectItem Value="@startType">@startType</MudSelectItem>
<MudSelectItem Value="StartType.Fixed">Fixed</MudSelectItem>
}
</MudSelect>
<MudTimePicker Class="mt-3" Label="Start Time" @bind-Time="@_selectedItem.StartTime" For="@(() => _selectedItem.StartTime)" Disabled="@(_selectedItem.StartType == StartType.Dynamic)"/>
@ -197,10 +204,13 @@ @@ -197,10 +204,13 @@
}
</MudSelect>
<MudSelect Class="mt-3" Label="Playout Mode" @bind-Value="@_selectedItem.PlayoutMode" For="@(() => _selectedItem.PlayoutMode)">
@foreach (PlayoutMode playoutMode in Enum.GetValues<PlayoutMode>())
@if (!_schedule.ShuffleScheduleItems)
{
<MudSelectItem Value="@playoutMode">@playoutMode</MudSelectItem>
<MudSelectItem Value="PlayoutMode.Flood">Flood</MudSelectItem>
}
<MudSelectItem Value="PlayoutMode.One">One</MudSelectItem>
<MudSelectItem Value="PlayoutMode.Multiple">Multiple</MudSelectItem>
<MudSelectItem Value="PlayoutMode.Duration">Duration</MudSelectItem>
</MudSelect>
<MudTextField Class="mt-3" Label="Multiple Count" @bind-Value="@_selectedItem.MultipleCount" For="@(() => _selectedItem.MultipleCount)" Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Multiple)"/>
<MudTimePicker Class="mt-3" Label="Playout Duration" @bind-Time="@_selectedItem.PlayoutDuration" For="@(() => _selectedItem.PlayoutDuration)" Disabled="@(_selectedItem.PlayoutMode != PlayoutMode.Duration)"/>
@ -315,8 +325,13 @@ @@ -315,8 +325,13 @@
.Map(list => list.OrderBy(vm => vm.Name, StringComparer.CurrentCultureIgnoreCase).ToList());
string name = string.Empty;
var shuffleScheduleItems = false;
Option<ProgramScheduleViewModel> maybeSchedule = await _mediator.Send(new GetProgramScheduleById(Id));
maybeSchedule.IfSome(vm => name = vm.Name);
foreach (ProgramScheduleViewModel schedule in maybeSchedule)
{
name = schedule.Name;
shuffleScheduleItems = schedule.ShuffleScheduleItems;
}
Option<IEnumerable<ProgramScheduleItemViewModel>> maybeResults = await _mediator.Send(new GetProgramScheduleItems(Id));
foreach (IEnumerable<ProgramScheduleItemViewModel> items in maybeResults)
@ -324,6 +339,7 @@ @@ -324,6 +339,7 @@
_schedule = new ProgramScheduleItemsEditViewModel
{
Name = name,
ShuffleScheduleItems = shuffleScheduleItems,
Items = items.Map(ProjectToEditViewModel).ToList()
};

5
ErsatzTV/ViewModels/ProgramScheduleEditViewModel.cs

@ -9,11 +9,12 @@ namespace ErsatzTV.ViewModels @@ -9,11 +9,12 @@ namespace ErsatzTV.ViewModels
public string Name { get; set; }
public bool KeepMultiPartEpisodesTogether { get; set; }
public bool TreatCollectionsAsShows { get; set; }
public bool ShuffleScheduleItems { get; set; }
public UpdateProgramSchedule ToUpdate() =>
new(Id, Name, KeepMultiPartEpisodesTogether, TreatCollectionsAsShows);
new(Id, Name, KeepMultiPartEpisodesTogether, TreatCollectionsAsShows, ShuffleScheduleItems);
public CreateProgramSchedule ToCreate() =>
new(Name, KeepMultiPartEpisodesTogether, TreatCollectionsAsShows);
new(Name, KeepMultiPartEpisodesTogether, TreatCollectionsAsShows, ShuffleScheduleItems);
}
}

1
ErsatzTV/ViewModels/ProgramScheduleItemsEditViewModel.cs

@ -5,6 +5,7 @@ namespace ErsatzTV.ViewModels @@ -5,6 +5,7 @@ namespace ErsatzTV.ViewModels
public class ProgramScheduleItemsEditViewModel
{
public string Name { get; set; }
public bool ShuffleScheduleItems { get; set; }
public List<ProgramScheduleItemEditViewModel> Items { get; set; }
}
}

Loading…
Cancel
Save