From 0e262f227d20bc493b86bbd7889d0b36359357e0 Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Wed, 10 Feb 2021 07:43:18 -0600 Subject: [PATCH] playout builder bugfixes --- .../Scheduling/ChronologicalContentTests.cs | 20 ---- .../Scheduling/PlayoutBuilderTests.cs | 106 ++++++++++++++++-- .../Scheduling/RandomizedContentTests.cs | 18 --- .../Scheduling/ShuffledContentTests.cs | 25 ----- .../Scheduling/IMediaCollectionEnumerator.cs | 1 - .../Interfaces/Scheduling/IPlayoutBuilder.cs | 4 +- .../ChronologicalMediaCollectionEnumerator.cs | 4 - ErsatzTV.Core/Scheduling/PlayoutBuilder.cs | 63 +++++++---- .../RandomizedMediaCollectionEnumerator.cs | 37 +----- .../ShuffledMediaCollectionEnumerator.cs | 37 +----- ErsatzTV/Pages/PlayoutEditor.razor | 6 +- ErsatzTV/Pages/Playouts.razor | 16 +-- ErsatzTV/ViewModels/PlayoutEditViewModel.cs | 2 +- 13 files changed, 155 insertions(+), 184 deletions(-) diff --git a/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs index b4fd5df3..6473f626 100644 --- a/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/ChronologicalContentTests.cs @@ -59,26 +59,6 @@ namespace ErsatzTV.Core.Tests.Scheduling } } - [Test] - public void Peek_Should_Not_Impact_Current_Or_Wrapping() - { - List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState(); - - var chronologicalContent = new ChronologicalMediaCollectionEnumerator(contents, state); - - for (var i = 0; i < 100; i++) - { - chronologicalContent.Current.IsSome.Should().BeTrue(); - - chronologicalContent.Current.Map(x => x.Id).IfNone(-1).Should().Be(i % 10 + 1); - chronologicalContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be((i + 1) % 10 + 1); - chronologicalContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be((i + 1) % 10 + 1); - - chronologicalContent.MoveNext(); - } - } - private static List Episodes(int count) => Range(1, count).Map( i => new MediaItem diff --git a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs index ee477bbb..bcce1b59 100644 --- a/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/PlayoutBuilderTests.cs @@ -413,7 +413,7 @@ namespace ErsatzTV.Core.Tests.Scheduling } [Test] - public async Task FloodContent_Should_FloodAroundFixedContent_DurationWithOfflineTail() + public async Task FloodContent_Should_FloodAroundFixedContent_DurationWithoutOfflineTail() { var floodCollection = new SimpleMediaCollection { @@ -433,7 +433,7 @@ namespace ErsatzTV.Core.Tests.Scheduling Items = new List { TestMovie(3, TimeSpan.FromHours(0.75), new DateTime(2020, 1, 1)), - TestMovie(4, TimeSpan.FromHours(0.75), new DateTime(2020, 1, 2)) + TestMovie(4, TimeSpan.FromHours(1.5), new DateTime(2020, 1, 2)) } }; @@ -458,7 +458,96 @@ namespace ErsatzTV.Core.Tests.Scheduling MediaCollectionId = fixedCollection.Id, StartTime = TimeSpan.FromHours(2), PlayoutDuration = TimeSpan.FromHours(2), - OfflineTail = true // last 30 minutes will be offline + OfflineTail = false // immediately continue + } + }; + + var playout = new Playout + { + ProgramSchedule = new ProgramSchedule + { + Items = items, + MediaCollectionPlaybackOrder = PlaybackOrder.Chronological + }, + Channel = new Channel(Guid.Empty) { Id = 1, Name = "Test Channel" } + }; + + var builder = new PlayoutBuilder(fakeRepository, _logger); + + DateTimeOffset start = HoursAfterMidnight(0); + DateTimeOffset finish = start + TimeSpan.FromHours(6); + + Playout result = await builder.BuildPlayoutItems(playout, start, finish); + + result.Items.Count.Should().Be(7); + + result.Items[0].Start.TimeOfDay.Should().Be(TimeSpan.Zero); + result.Items[0].MediaItemId.Should().Be(1); + result.Items[1].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(1)); + result.Items[1].MediaItemId.Should().Be(2); + + result.Items[2].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(2)); + result.Items[2].MediaItemId.Should().Be(3); + + result.Items[3].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(2.75)); + result.Items[3].MediaItemId.Should().Be(1); + result.Items[4].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(3.75)); + result.Items[4].MediaItemId.Should().Be(2); + + result.Items[5].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(4.75)); + result.Items[5].MediaItemId.Should().Be(1); + result.Items[6].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(5.75)); + result.Items[6].MediaItemId.Should().Be(2); + } + + [Test] + public async Task MultipleContent_Should_WrapAroundDynamicContent_DurationWithoutOfflineTail() + { + var multipleCollection = new SimpleMediaCollection + { + Id = 1, + Name = "Multiple Items", + Items = new List + { + TestMovie(1, TimeSpan.FromHours(1), new DateTime(2020, 1, 1)), + TestMovie(2, TimeSpan.FromHours(1), new DateTime(2020, 2, 1)) + } + }; + + var dynamicCollection = new SimpleMediaCollection + { + Id = 2, + Name = "Dynamic Items", + Items = new List + { + TestMovie(3, TimeSpan.FromHours(0.75), new DateTime(2020, 1, 1)), + TestMovie(4, TimeSpan.FromHours(1.5), new DateTime(2020, 1, 2)) + } + }; + + var fakeRepository = new FakeMediaCollectionRepository( + Map( + (multipleCollection.Id, multipleCollection.Items.ToList()), + (dynamicCollection.Id, dynamicCollection.Items.ToList()))); + + var items = new List + { + new ProgramScheduleItemMultiple + { + Index = 1, + MediaCollection = multipleCollection, + MediaCollectionId = multipleCollection.Id, + StartTime = null, + Count = 2 + }, + new ProgramScheduleItemDuration + { + Index = 2, + MediaCollection = dynamicCollection, + MediaCollectionId = dynamicCollection.Id, + StartTime = null, + PlayoutDuration = TimeSpan.FromHours(2), + OfflineTail = false // immediately continue } }; @@ -488,13 +577,14 @@ namespace ErsatzTV.Core.Tests.Scheduling result.Items[2].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(2)); result.Items[2].MediaItemId.Should().Be(3); + result.Items[3].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(2.75)); - result.Items[3].MediaItemId.Should().Be(4); + result.Items[3].MediaItemId.Should().Be(1); + result.Items[4].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(3.75)); + result.Items[4].MediaItemId.Should().Be(2); - result.Items[4].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(4)); - result.Items[4].MediaItemId.Should().Be(1); - result.Items[5].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(5)); - result.Items[5].MediaItemId.Should().Be(2); + result.Items[5].Start.TimeOfDay.Should().Be(TimeSpan.FromHours(4.75)); + result.Items[5].MediaItemId.Should().Be(4); } private static DateTimeOffset HoursAfterMidnight(int hours) diff --git a/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs index 7c12b12a..d0250917 100644 --- a/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/RandomizedContentTests.cs @@ -77,24 +77,6 @@ namespace ErsatzTV.Core.Tests.Scheduling } } - [Test] - public void Peek_Should_Not_Impact_Current_Or_Wrapping() - { - List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState { Seed = KnownSeed }; - - var randomizedContent = new RandomizedMediaCollectionEnumerator(contents, state); - - for (var i = 0; i < 97; i++) - { - randomizedContent.MoveNext(); - randomizedContent.Current.IsSome.Should().BeTrue(); - randomizedContent.Current.Map(x => x.Id).IfNone(-1).Should().Be(_expected[i]); - randomizedContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be(_expected[i + 1]); - randomizedContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be(_expected[i + 1]); - } - } - private static List Episodes(int count) => Range(1, count).Map( i => new MediaItem diff --git a/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs b/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs index 0b665982..65c28120 100644 --- a/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs +++ b/ErsatzTV.Core.Tests/Scheduling/ShuffledContentTests.cs @@ -67,31 +67,6 @@ namespace ErsatzTV.Core.Tests.Scheduling } } - [Test] - public void Peek_Should_Not_Impact_Current_Or_Wrapping() - { - List contents = Episodes(10); - var state = new MediaCollectionEnumeratorState { Seed = MagicSeed }; - var expected = new List - { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 6, 1, 4, 2, 10, 7, 3, 5, 8, 9, 10, 9, 4, 5, 1, 7, 3, 2, 8, 6, 3, 5, 4, 2, - 10, 8, 7, 1, 6, 9, 3, 4, 7, 10, 6, 9, 1, 2, 8, 5, 8, 1, 3, 6, 5, 7, 9, 4, 2, 10, 6, 1, 4, 3, 5, 10, 2, - 7, 8, 9, 6, 10, 4, 3, 8, 1, 5, 9, 2, 7, 8, 6, 4, 1, 9, 7, 3, 10, 5, 2, 5, 9, 2, 6, 7, 10, 3, 4, 1, 8 - }; - - var shuffledContent = new ShuffledMediaCollectionEnumerator(contents, state); - - for (var i = 0; i < 99; i++) - { - shuffledContent.Current.IsSome.Should().BeTrue(); - shuffledContent.Current.Map(x => x.Id).IfNone(-1).Should().Be(expected[i]); - shuffledContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be(expected[i + 1]); - shuffledContent.Peek.Map(x => x.Id).IfNone(-1).Should().Be(expected[i + 1]); - - shuffledContent.MoveNext(); - } - } - private static List Episodes(int count) => Range(1, count).Map( i => new MediaItem diff --git a/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs b/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs index fc0c37bb..684badcf 100644 --- a/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Interfaces/Scheduling/IMediaCollectionEnumerator.cs @@ -7,7 +7,6 @@ namespace ErsatzTV.Core.Interfaces.Scheduling { MediaCollectionEnumeratorState State { get; } public Option Current { get; } - public Option Peek { get; } public void MoveNext(); } } diff --git a/ErsatzTV.Core/Interfaces/Scheduling/IPlayoutBuilder.cs b/ErsatzTV.Core/Interfaces/Scheduling/IPlayoutBuilder.cs index f33cce3b..6492dc83 100644 --- a/ErsatzTV.Core/Interfaces/Scheduling/IPlayoutBuilder.cs +++ b/ErsatzTV.Core/Interfaces/Scheduling/IPlayoutBuilder.cs @@ -10,8 +10,8 @@ namespace ErsatzTV.Core.Interfaces.Scheduling public Task BuildPlayoutItems( Playout playout, - DateTimeOffset start, - DateTimeOffset finish, + DateTimeOffset playoutStart, + DateTimeOffset playoutFinish, bool rebuild = false); } } diff --git a/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs index a82f72e7..d2f64d40 100644 --- a/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/ChronologicalMediaCollectionEnumerator.cs @@ -32,10 +32,6 @@ namespace ErsatzTV.Core.Scheduling public Option Current => _sortedMediaItems.Any() ? _sortedMediaItems[State.Index] : None; - public Option Peek => _sortedMediaItems.Any() - ? _sortedMediaItems[(State.Index + 1) % _sortedMediaItems.Count] - : None; - public void MoveNext() => State.Index = (State.Index + 1) % _sortedMediaItems.Count; } } diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index c3b7aea7..9a8dfc44 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -34,8 +34,8 @@ namespace ErsatzTV.Core.Scheduling public async Task BuildPlayoutItems( Playout playout, - DateTimeOffset start, - DateTimeOffset finish, + DateTimeOffset playoutStart, + DateTimeOffset playoutFinish, bool rebuild = false) { var collections = playout.ProgramSchedule.Items.Map(i => i.MediaCollection).Distinct().ToList(); @@ -71,7 +71,7 @@ namespace ErsatzTV.Core.Scheduling MapExtensions.Map(collectionMediaItems, (c, i) => GetMediaCollectionEnumerator(playout, c, i)); // find start anchor - PlayoutAnchor startAnchor = FindStartAnchor(playout, start, sortedScheduleItems); + PlayoutAnchor startAnchor = FindStartAnchor(playout, playoutStart, sortedScheduleItems); // start at the previously-decided time DateTimeOffset currentTime = startAnchor.NextStart; @@ -88,35 +88,39 @@ namespace ErsatzTV.Core.Scheduling Option multipleRemaining = None; Option durationFinish = None; // loop until we're done filling the desired amount of time - while (currentTime < finish) + while (currentTime < playoutFinish) { // get the schedule item out of the sorted list ProgramScheduleItem scheduleItem = sortedScheduleItems[index % sortedScheduleItems.Count]; // find when we should start this item, based on the current time - DateTimeOffset startTime = GetStartTimeAfter( + DateTimeOffset itemStartTime = GetStartTimeAfter( scheduleItem, currentTime, multipleRemaining.IsSome, durationFinish.IsSome); - _logger.LogDebug( - "Schedule item: {ScheduleItemNumber} / {MediaCollectionName} / {StartTime}", - scheduleItem.Index, - scheduleItem.MediaCollection.Name, - startTime); IMediaCollectionEnumerator enumerator = collectionEnumerators[scheduleItem.MediaCollection]; enumerator.Current.IfSome( mediaItem => { + _logger.LogDebug( + "Scheduling media item: {ScheduleItemNumber} / {MediaCollectionId} - {MediaCollectionName} / {MediaItemId} - {MediaItemTitle} / {StartTime}", + scheduleItem.Index, + scheduleItem.MediaCollection.Id, + scheduleItem.MediaCollection.Name, + mediaItem.Id, + DisplayTitle(mediaItem), + itemStartTime); + var playoutItem = new PlayoutItem { MediaItemId = mediaItem.Id, - Start = startTime, - Finish = startTime + mediaItem.Metadata.Duration + Start = itemStartTime, + Finish = itemStartTime + mediaItem.Metadata.Duration }; - currentTime = startTime + mediaItem.Metadata.Duration; + currentTime = itemStartTime + mediaItem.Metadata.Duration; enumerator.MoveNext(); playout.Items.Add(playoutItem); @@ -126,7 +130,7 @@ namespace ErsatzTV.Core.Scheduling case ProgramScheduleItemOne: // only play one item from collection, so always advance to the next item _logger.LogDebug( - "Advancing to next playout item after playout mode {PlayoutMode}", + "Advancing to next schedule item after playout mode {PlayoutMode}", "One"); index++; break; @@ -139,13 +143,16 @@ namespace ErsatzTV.Core.Scheduling multipleRemaining = multipleRemaining.Map(i => i - 1); if (multipleRemaining.IfNone(-1) == 0) { + _logger.LogDebug( + "Advancing to next schedule item after playout mode {PlayoutMode}", + "Multiple"); index++; multipleRemaining = None; } break; case ProgramScheduleItemFlood: - enumerator.Peek.Do( + enumerator.Current.Do( peekMediaItem => { ProgramScheduleItem peekScheduleItem = @@ -163,25 +170,32 @@ namespace ErsatzTV.Core.Scheduling peekScheduleItemStart; if (willNotFinishInTime) { + _logger.LogDebug( + "Advancing to next schedule item after playout mode {PlayoutMode}", + "Flood"); index++; } }); break; case ProgramScheduleItemDuration duration: - enumerator.Peek.Do( + enumerator.Current.Do( peekMediaItem => { + // remember when we need to finish this duration item if (durationFinish.IsNone) { - durationFinish = startTime + duration.PlayoutDuration; + durationFinish = itemStartTime + duration.PlayoutDuration; } - DateTimeOffset finish = durationFinish.IfNone(DateTime.MinValue); - bool willNotFinishInTime = currentTime <= finish && - currentTime + peekMediaItem.Metadata.Duration > - finish; + bool willNotFinishInTime = + currentTime <= durationFinish.IfNone(DateTime.MinValue) && + currentTime + peekMediaItem.Metadata.Duration > + durationFinish.IfNone(DateTime.MinValue); if (willNotFinishInTime) { + _logger.LogDebug( + "Advancing to next schedule item after playout mode {PlayoutMode}", + "Duration"); index++; if (duration.OfflineTail) @@ -211,7 +225,7 @@ namespace ErsatzTV.Core.Scheduling playout.ProgramScheduleAnchors = BuildProgramScheduleAnchors(playout, collectionEnumerators); // remove any items outside the desired range - playout.Items.RemoveAll(old => old.Finish < start || old.Start > finish); + playout.Items.RemoveAll(old => old.Finish < playoutStart || old.Start > playoutFinish); return playout; } @@ -332,5 +346,10 @@ namespace ErsatzTV.Core.Scheduling return new RandomizedMediaCollectionEnumerator(mediaItems, state); } } + + private static string DisplayTitle(MediaItem mediaItem) => + mediaItem.Metadata.MediaType == MediaType.TvShow + ? $"{mediaItem.Metadata.Title} - s{mediaItem.Metadata.SeasonNumber:00}e{mediaItem.Metadata.EpisodeNumber:00}" + : mediaItem.Metadata.Title; } } diff --git a/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs index 0bd39a11..660c7210 100644 --- a/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/RandomizedMediaCollectionEnumerator.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Scheduling; @@ -14,13 +13,11 @@ namespace ErsatzTV.Core.Scheduling private readonly IList _mediaItems; private readonly Random _random; private int _index; - private Option _peekNext; public RandomizedMediaCollectionEnumerator(IList mediaItems, MediaCollectionEnumeratorState state) { _mediaItems = mediaItems; _random = new Random(state.Seed); - _peekNext = None; State = new MediaCollectionEnumeratorState { Seed = state.Seed }; // we want to move at least once so we start with a random item and not the first @@ -35,41 +32,9 @@ namespace ErsatzTV.Core.Scheduling public Option Current => _mediaItems.Any() ? _mediaItems[_index] : None; - public Option Peek - { - get - { - if (_mediaItems.Any()) - { - return _peekNext.Match( - peek => - { - Debug.WriteLine("returning existing peek"); - return _mediaItems[peek]; - }, - () => - { - Debug.WriteLine("setting peek"); - // gen a random index but save it so we can use it again when - // we actually move next - int index = _random.Next() % _mediaItems.Count; - _peekNext = index; - return _mediaItems[index]; - }); - } - - return None; - } - } - public void MoveNext() { - // TODO: reset seed at some predictable point so we don't overflow the index - Debug.WriteLine("resetting peek"); - - _index = _peekNext.IfNone(() => _random.Next() % _mediaItems.Count); - _peekNext = None; - + _index = _random.Next() % _mediaItems.Count; State.Index++; } } diff --git a/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs b/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs index fe5b3957..a81bae44 100644 --- a/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs +++ b/ErsatzTV.Core/Scheduling/ShuffledMediaCollectionEnumerator.cs @@ -4,7 +4,6 @@ using System.Linq; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Scheduling; using LanguageExt; -using LanguageExt.UnsafeValueAccess; using static LanguageExt.Prelude; namespace ErsatzTV.Core.Scheduling @@ -12,7 +11,6 @@ namespace ErsatzTV.Core.Scheduling public class ShuffledMediaCollectionEnumerator : IMediaCollectionEnumerator { private readonly IList _mediaItems; - private Option _peekNextSeed; private Random _random; private IList _shuffled; @@ -34,51 +32,18 @@ namespace ErsatzTV.Core.Scheduling public Option Current => _shuffled.Any() ? _shuffled[State.Index % _mediaItems.Count] : None; - public Option Peek - { - get - { - if (_shuffled.Any()) - { - // if we aren't peeking past the end of the list, things are simple - if (State.Index + 1 < _shuffled.Count) - { - return _shuffled[State.Index + 1]; - } - - // if we are peeking past the end of the list... - // gen a random seed but save it so we can use it again when we actually move next - Random random; - if (_peekNextSeed.IsSome) - { - random = new Random(_peekNextSeed.Value()); - } - else - { - _peekNextSeed = _random.Next(); - random = new Random(_peekNextSeed.Value()); - } - - return Shuffle(_mediaItems, random).Head(); - } - - return None; - } - } - public void MoveNext() { State.Index++; if (State.Index % _shuffled.Count == 0) { State.Index = 0; - State.Seed = _peekNextSeed.IfNone(_random.Next()); + State.Seed = _random.Next(); _random = new Random(State.Seed); _shuffled = Shuffle(_mediaItems, _random); } State.Index %= _shuffled.Count; - _peekNextSeed = None; } private static IList Shuffle(IEnumerable list, Random random) diff --git a/ErsatzTV/Pages/PlayoutEditor.razor b/ErsatzTV/Pages/PlayoutEditor.razor index c7260358..9e3c66b4 100644 --- a/ErsatzTV/Pages/PlayoutEditor.razor +++ b/ErsatzTV/Pages/PlayoutEditor.razor @@ -1,8 +1,8 @@ @page "/playouts/add" -@using ErsatzTV.Application.ProgramSchedules -@using ErsatzTV.Application.ProgramSchedules.Queries @using ErsatzTV.Application.Channels @using ErsatzTV.Application.Channels.Queries +@using ErsatzTV.Application.ProgramSchedules +@using ErsatzTV.Application.ProgramSchedules.Queries @inject NavigationManager NavigationManager @inject ILogger Logger @inject ISnackbar Snackbar @@ -32,7 +32,7 @@ private readonly PlayoutEditViewModel _model = new(); private List _channels; private List _programSchedules; - + private EditContext _editContext; private ValidationMessageStore _messageStore; diff --git a/ErsatzTV/Pages/Playouts.razor b/ErsatzTV/Pages/Playouts.razor index e815d22c..7acb1daf 100644 --- a/ErsatzTV/Pages/Playouts.razor +++ b/ErsatzTV/Pages/Playouts.razor @@ -9,12 +9,12 @@ Playouts - - - - - - + + + + + + Id Channel @@ -67,7 +67,7 @@ private async Task PlayoutSelected(PlayoutViewModel playout) => _selectedPlayoutItems = await Mediator.Send(new GetPlayoutItemsById(playout.Id)); - + private async Task DeletePlayout(PlayoutViewModel playout) { var parameters = new DialogParameters { { "EntityType", "playout" }, { "EntityName", $"{playout.ProgramSchedule.Name} on {playout.Channel.Number} - {playout.Channel.Name}" } }; @@ -84,6 +84,6 @@ private async Task LoadAllPlayouts() => _playouts = await Mediator.Send(new GetAllPlayouts()); - + } \ No newline at end of file diff --git a/ErsatzTV/ViewModels/PlayoutEditViewModel.cs b/ErsatzTV/ViewModels/PlayoutEditViewModel.cs index 924da2d9..33222c18 100644 --- a/ErsatzTV/ViewModels/PlayoutEditViewModel.cs +++ b/ErsatzTV/ViewModels/PlayoutEditViewModel.cs @@ -11,6 +11,6 @@ namespace ErsatzTV.ViewModels public ProgramScheduleViewModel ProgramSchedule { get; set; } public CreatePlayout ToCreate() => - new CreatePlayout(Channel.Id, ProgramSchedule.Id, ProgramSchedulePlayoutType.Flood); + new(Channel.Id, ProgramSchedule.Id, ProgramSchedulePlayoutType.Flood); } }