scheduling fixes (#451)
* scheduling fixes * restore plex service * restore plex service part 2
This commit is contained in:
@@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- Fix generated streams with mpeg2video
|
- Fix generated streams with mpeg2video
|
||||||
- Fix incorrect row count in playout detail table
|
- Fix incorrect row count in playout detail table
|
||||||
- Fix deleting movies that have been removed from Jellyfin and Emby
|
- Fix deleting movies that have been removed from Jellyfin and Emby
|
||||||
|
- Fix bug that caused large unscheduled gaps in playouts
|
||||||
|
- This was caused by schedule items with a fixed start of midnight
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- Add new filler system
|
- Add new filler system
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
|
|||||||
{
|
{
|
||||||
ProgramScheduleId = programSchedule.Id,
|
ProgramScheduleId = programSchedule.Id,
|
||||||
Index = index,
|
Index = index,
|
||||||
StartTime = item.StartTime,
|
StartTime = FixDuration(item.StartTime.GetValueOrDefault()),
|
||||||
CollectionType = item.CollectionType,
|
CollectionType = item.CollectionType,
|
||||||
CollectionId = item.CollectionId,
|
CollectionId = item.CollectionId,
|
||||||
MultiCollectionId = item.MultiCollectionId,
|
MultiCollectionId = item.MultiCollectionId,
|
||||||
@@ -188,7 +188,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
|
|||||||
{
|
{
|
||||||
ProgramScheduleId = programSchedule.Id,
|
ProgramScheduleId = programSchedule.Id,
|
||||||
Index = index,
|
Index = index,
|
||||||
StartTime = item.StartTime,
|
StartTime = FixDuration(item.StartTime.GetValueOrDefault()),
|
||||||
CollectionType = item.CollectionType,
|
CollectionType = item.CollectionType,
|
||||||
CollectionId = item.CollectionId,
|
CollectionId = item.CollectionId,
|
||||||
MultiCollectionId = item.MultiCollectionId,
|
MultiCollectionId = item.MultiCollectionId,
|
||||||
@@ -207,7 +207,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
|
|||||||
{
|
{
|
||||||
ProgramScheduleId = programSchedule.Id,
|
ProgramScheduleId = programSchedule.Id,
|
||||||
Index = index,
|
Index = index,
|
||||||
StartTime = item.StartTime,
|
StartTime = FixDuration(item.StartTime.GetValueOrDefault()),
|
||||||
CollectionType = item.CollectionType,
|
CollectionType = item.CollectionType,
|
||||||
CollectionId = item.CollectionId,
|
CollectionId = item.CollectionId,
|
||||||
MultiCollectionId = item.MultiCollectionId,
|
MultiCollectionId = item.MultiCollectionId,
|
||||||
@@ -227,7 +227,7 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
|
|||||||
{
|
{
|
||||||
ProgramScheduleId = programSchedule.Id,
|
ProgramScheduleId = programSchedule.Id,
|
||||||
Index = index,
|
Index = index,
|
||||||
StartTime = item.StartTime,
|
StartTime = FixDuration(item.StartTime.GetValueOrDefault()),
|
||||||
CollectionType = item.CollectionType,
|
CollectionType = item.CollectionType,
|
||||||
CollectionId = item.CollectionId,
|
CollectionId = item.CollectionId,
|
||||||
MultiCollectionId = item.MultiCollectionId,
|
MultiCollectionId = item.MultiCollectionId,
|
||||||
@@ -248,6 +248,6 @@ namespace ErsatzTV.Application.ProgramSchedules.Commands
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static TimeSpan FixDuration(TimeSpan duration) =>
|
private static TimeSpan FixDuration(TimeSpan duration) =>
|
||||||
duration > TimeSpan.FromDays(1) ? duration.Subtract(TimeSpan.FromDays(1)) : duration;
|
duration >= TimeSpan.FromDays(1) ? duration.Subtract(TimeSpan.FromDays(1)) : duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,6 +452,181 @@ namespace ErsatzTV.Core.Tests.Scheduling
|
|||||||
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
|
playoutItems[0].FillerKind.Should().Be(FillerKind.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Should_Have_No_Gap_With_Exact_Post_Roll_Pad()
|
||||||
|
{
|
||||||
|
Collection collectionOne = TwoItemCollection(1, 2, new TimeSpan(2, 45, 0));
|
||||||
|
Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(5));
|
||||||
|
Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
|
var scheduleItem = new ProgramScheduleItemOne
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Index = 1,
|
||||||
|
Collection = collectionOne,
|
||||||
|
CollectionId = collectionOne.Id,
|
||||||
|
StartTime = null,
|
||||||
|
PlaybackOrder = PlaybackOrder.Chronological,
|
||||||
|
PostRollFiller = new FillerPreset
|
||||||
|
{
|
||||||
|
FillerKind = FillerKind.PostRoll,
|
||||||
|
FillerMode = FillerMode.Pad,
|
||||||
|
PadToNearestMinute = 30,
|
||||||
|
Collection = collectionTwo,
|
||||||
|
CollectionId = collectionTwo.Id
|
||||||
|
},
|
||||||
|
FallbackFiller = new FillerPreset
|
||||||
|
{
|
||||||
|
FillerKind = FillerKind.Fallback,
|
||||||
|
Collection = collectionThree,
|
||||||
|
CollectionId = collectionThree.Id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionOne.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator2 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionTwo.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator3 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionThree.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
|
||||||
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
|
StartState,
|
||||||
|
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3),
|
||||||
|
scheduleItem,
|
||||||
|
NextScheduleItem,
|
||||||
|
HardStop);
|
||||||
|
|
||||||
|
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
|
||||||
|
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
|
||||||
|
|
||||||
|
playoutBuilderState.NextGuideGroup.Should().Be(2);
|
||||||
|
playoutBuilderState.DurationFinish.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InFlood.Should().BeFalse();
|
||||||
|
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InDurationFiller.Should().BeFalse();
|
||||||
|
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
|
||||||
|
|
||||||
|
enumerator1.State.Index.Should().Be(1);
|
||||||
|
enumerator2.State.Index.Should().Be(1);
|
||||||
|
|
||||||
|
playoutItems.Count.Should().Be(4);
|
||||||
|
|
||||||
|
playoutItems[0].MediaItemId.Should().Be(1);
|
||||||
|
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].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].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].GuideGroup.Should().Be(1);
|
||||||
|
playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Should_Have_No_Gap_With_Exact_Post_Roll_Pad_With_Chapters()
|
||||||
|
{
|
||||||
|
Collection collectionOne = TwoItemCollection(1, 2, new TimeSpan(2, 45, 0), 2);
|
||||||
|
Collection collectionTwo = TwoItemCollection(3, 4, TimeSpan.FromMinutes(5));
|
||||||
|
Collection collectionThree = TwoItemCollection(5, 6, TimeSpan.FromMinutes(1));
|
||||||
|
|
||||||
|
var scheduleItem = new ProgramScheduleItemOne
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Index = 1,
|
||||||
|
Collection = collectionOne,
|
||||||
|
CollectionId = collectionOne.Id,
|
||||||
|
StartTime = null,
|
||||||
|
PlaybackOrder = PlaybackOrder.Chronological,
|
||||||
|
PostRollFiller = new FillerPreset
|
||||||
|
{
|
||||||
|
FillerKind = FillerKind.PostRoll,
|
||||||
|
FillerMode = FillerMode.Pad,
|
||||||
|
PadToNearestMinute = 30,
|
||||||
|
Collection = collectionTwo,
|
||||||
|
CollectionId = collectionTwo.Id
|
||||||
|
},
|
||||||
|
FallbackFiller = new FillerPreset
|
||||||
|
{
|
||||||
|
FillerKind = FillerKind.Fallback,
|
||||||
|
Collection = collectionThree,
|
||||||
|
CollectionId = collectionThree.Id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionOne.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator2 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionTwo.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator3 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionThree.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var scheduler = new PlayoutModeSchedulerOne(new Mock<ILogger>().Object);
|
||||||
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
|
StartState,
|
||||||
|
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.PostRollFiller, enumerator2, scheduleItem.FallbackFiller, enumerator3),
|
||||||
|
scheduleItem,
|
||||||
|
NextScheduleItem,
|
||||||
|
HardStop);
|
||||||
|
|
||||||
|
playoutBuilderState.CurrentTime.Should().Be(StartState.CurrentTime.AddHours(3));
|
||||||
|
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
|
||||||
|
|
||||||
|
playoutBuilderState.NextGuideGroup.Should().Be(2);
|
||||||
|
playoutBuilderState.DurationFinish.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InFlood.Should().BeFalse();
|
||||||
|
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InDurationFiller.Should().BeFalse();
|
||||||
|
playoutBuilderState.ScheduleItemIndex.Should().Be(1);
|
||||||
|
|
||||||
|
enumerator1.State.Index.Should().Be(1);
|
||||||
|
enumerator2.State.Index.Should().Be(1);
|
||||||
|
enumerator3.State.Index.Should().Be(0);
|
||||||
|
|
||||||
|
playoutItems.Count.Should().Be(4);
|
||||||
|
|
||||||
|
playoutItems[0].MediaItemId.Should().Be(1);
|
||||||
|
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].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].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].GuideGroup.Should().Be(1);
|
||||||
|
playoutItems[3].FillerKind.Should().Be(FillerKind.PostRoll);
|
||||||
|
}
|
||||||
|
|
||||||
protected override ProgramScheduleItem NextScheduleItem => new ProgramScheduleItemOne
|
protected override ProgramScheduleItem NextScheduleItem => new ProgramScheduleItemOne
|
||||||
{
|
{
|
||||||
StartTime = TimeSpan.FromHours(3)
|
StartTime = TimeSpan.FromHours(3)
|
||||||
|
|||||||
@@ -44,25 +44,39 @@ namespace ErsatzTV.Core.Tests.Scheduling
|
|||||||
{ CollectionKey.ForFillerPreset(fillerPreset2), enumerator3 }
|
{ CollectionKey.ForFillerPreset(fillerPreset2), enumerator3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Movie TestMovie(int id, TimeSpan duration, DateTime aired) =>
|
private static Movie TestMovie(int id, TimeSpan duration, DateTime aired, int chapterCount = 0)
|
||||||
new()
|
{
|
||||||
|
var result = new Movie()
|
||||||
{
|
{
|
||||||
Id = id,
|
Id = id,
|
||||||
MovieMetadata = new List<MovieMetadata> { new() { ReleaseDate = aired } },
|
MovieMetadata = new List<MovieMetadata> { new() { ReleaseDate = aired } },
|
||||||
MediaVersions = new List<MediaVersion>
|
MediaVersions = new List<MediaVersion>
|
||||||
{
|
{
|
||||||
new() { Duration = duration }
|
new() { Duration = duration, Chapters = new List<MediaChapter>() }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
protected static Collection TwoItemCollection(int id1, int id2, TimeSpan duration) => new()
|
for (var i = 0; i < chapterCount; i++)
|
||||||
|
{
|
||||||
|
result.MediaVersions.Head().Chapters.Add(
|
||||||
|
new MediaChapter
|
||||||
|
{
|
||||||
|
StartTime = TimeSpan.FromMilliseconds(i * duration.TotalMilliseconds / chapterCount),
|
||||||
|
EndTime = TimeSpan.FromMilliseconds(i + 1 * duration.TotalMilliseconds / chapterCount)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Collection TwoItemCollection(int id1, int id2, TimeSpan duration, int chapterCount = 0) => new()
|
||||||
{
|
{
|
||||||
Id = id1,
|
Id = id1,
|
||||||
Name = $"Collection of Items {id1}",
|
Name = $"Collection of Items {id1}",
|
||||||
MediaItems = new List<MediaItem>
|
MediaItems = new List<MediaItem>
|
||||||
{
|
{
|
||||||
TestMovie(id1, duration, new DateTime(2020, 1, 1)),
|
TestMovie(id1, duration, new DateTime(2020, 1, 1), chapterCount),
|
||||||
TestMovie(id2, duration, new DateTime(2020, 1, 2))
|
TestMovie(id2, duration, new DateTime(2020, 1, 2), chapterCount)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -352,6 +352,12 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
return new List<PlayoutItem> { playoutItem };
|
return new List<PlayoutItem> { playoutItem };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<MediaChapter> effectiveChapters = chapters;
|
||||||
|
if (allFiller.All(fp => fp.FillerKind != FillerKind.MidRoll))
|
||||||
|
{
|
||||||
|
effectiveChapters = new List<MediaChapter>();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (FillerPreset filler in allFiller.Filter(
|
foreach (FillerPreset filler in allFiller.Filter(
|
||||||
f => f.FillerKind == FillerKind.PreRoll && f.FillerMode != FillerMode.Pad))
|
f => f.FillerKind == FillerKind.PreRoll && f.FillerMode != FillerMode.Pad))
|
||||||
{
|
{
|
||||||
@@ -370,7 +376,7 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allFiller.All(f => f.FillerKind != FillerKind.MidRoll) || !chapters.Any())
|
if (!effectiveChapters.Any())
|
||||||
{
|
{
|
||||||
result.Add(playoutItem);
|
result.Add(playoutItem);
|
||||||
}
|
}
|
||||||
@@ -383,10 +389,10 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
{
|
{
|
||||||
case FillerMode.Duration when filler.Duration.HasValue:
|
case FillerMode.Duration when filler.Duration.HasValue:
|
||||||
IMediaCollectionEnumerator e1 = enumerators[CollectionKey.ForFillerPreset(filler)];
|
IMediaCollectionEnumerator e1 = enumerators[CollectionKey.ForFillerPreset(filler)];
|
||||||
for (var i = 0; i < chapters.Count; i++)
|
for (var i = 0; i < effectiveChapters.Count; i++)
|
||||||
{
|
{
|
||||||
result.Add(playoutItem.ForChapter(chapters[i]));
|
result.Add(playoutItem.ForChapter(effectiveChapters[i]));
|
||||||
if (i < chapters.Count - 1)
|
if (i < effectiveChapters.Count - 1)
|
||||||
{
|
{
|
||||||
result.AddRange(
|
result.AddRange(
|
||||||
AddDurationFiller(
|
AddDurationFiller(
|
||||||
@@ -400,9 +406,9 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
break;
|
break;
|
||||||
case FillerMode.Count when filler.Count.HasValue:
|
case FillerMode.Count when filler.Count.HasValue:
|
||||||
IMediaCollectionEnumerator e2 = enumerators[CollectionKey.ForFillerPreset(filler)];
|
IMediaCollectionEnumerator e2 = enumerators[CollectionKey.ForFillerPreset(filler)];
|
||||||
for (var i = 0; i < chapters.Count - 1; i++)
|
for (var i = 0; i < effectiveChapters.Count - 1; i++)
|
||||||
{
|
{
|
||||||
result.Add(playoutItem.ForChapter(chapters[i]));
|
result.Add(playoutItem.ForChapter(effectiveChapters[i]));
|
||||||
result.AddRange(
|
result.AddRange(
|
||||||
AddCountFiller(
|
AddCountFiller(
|
||||||
playoutBuilderState,
|
playoutBuilderState,
|
||||||
@@ -440,7 +446,7 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
var totalDuration =
|
var totalDuration =
|
||||||
TimeSpan.FromMilliseconds(
|
TimeSpan.FromMilliseconds(
|
||||||
result.Sum(pi => (pi.Finish - pi.Start).TotalMilliseconds) +
|
result.Sum(pi => (pi.Finish - pi.Start).TotalMilliseconds) +
|
||||||
chapters.Sum(c => (c.EndTime - c.StartTime).TotalMilliseconds));
|
effectiveChapters.Sum(c => (c.EndTime - c.StartTime).TotalMilliseconds));
|
||||||
|
|
||||||
int currentMinute = (playoutItem.StartOffset + totalDuration).Minute;
|
int currentMinute = (playoutItem.StartOffset + totalDuration).Minute;
|
||||||
// ReSharper disable once PossibleInvalidOperationException
|
// ReSharper disable once PossibleInvalidOperationException
|
||||||
@@ -503,14 +509,14 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
mid1,
|
mid1,
|
||||||
remainingToFill,
|
remainingToFill,
|
||||||
FillerKind.MidRoll));
|
FillerKind.MidRoll));
|
||||||
TimeSpan average = chapters.Count == 0
|
TimeSpan average = effectiveChapters.Count == 0
|
||||||
? remainingToFill
|
? remainingToFill
|
||||||
: remainingToFill / (chapters.Count - 1);
|
: remainingToFill / (effectiveChapters.Count - 1);
|
||||||
TimeSpan filled = TimeSpan.Zero;
|
TimeSpan filled = TimeSpan.Zero;
|
||||||
for (var i = 0; i < chapters.Count; i++)
|
for (var i = 0; i < chapters.Count; i++)
|
||||||
{
|
{
|
||||||
result.Add(playoutItem.ForChapter(chapters[i]));
|
result.Add(playoutItem.ForChapter(effectiveChapters[i]));
|
||||||
if (i < chapters.Count - 1)
|
if (i < effectiveChapters.Count - 1)
|
||||||
{
|
{
|
||||||
TimeSpan current = TimeSpan.Zero;
|
TimeSpan current = TimeSpan.Zero;
|
||||||
while (current < average && filled < remainingToFill)
|
while (current < average && filled < remainingToFill)
|
||||||
@@ -534,7 +540,7 @@ namespace ErsatzTV.Core.Scheduling
|
|||||||
playoutBuilderState,
|
playoutBuilderState,
|
||||||
enumerators,
|
enumerators,
|
||||||
scheduleItem,
|
scheduleItem,
|
||||||
i < chapters.Count - 1 ? maxThisBreak : leftOverall);
|
i < effectiveChapters.Count - 1 ? maxThisBreak : leftOverall);
|
||||||
|
|
||||||
foreach (PlayoutItem fallback in maybeFallback)
|
foreach (PlayoutItem fallback in maybeFallback)
|
||||||
{
|
{
|
||||||
|
|||||||
+3657
File diff suppressed because it is too large
Load Diff
+38
@@ -0,0 +1,38 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
public partial class Fix_ProgramScheduleItemMidnightStartTime : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
"update ProgramScheduleItem set StartTime = '00:00:00' where StartTime = '1.00:00:00'");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"delete from PlayoutItem where PlayoutId in
|
||||||
|
(select Playout.Id from Playout
|
||||||
|
inner join ProgramSchedule PS on Playout.ProgramScheduleId = PS.Id
|
||||||
|
inner join ProgramScheduleItem PSI on PSI.ProgramScheduleId = PS.Id
|
||||||
|
where PSI.StartTime = '00:00:00')");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"delete from PlayoutProgramScheduleAnchor where PlayoutId in
|
||||||
|
(select Playout.Id from Playout
|
||||||
|
inner join ProgramSchedule PS on Playout.ProgramScheduleId = PS.Id
|
||||||
|
inner join ProgramScheduleItem PSI on PSI.ProgramScheduleId = PS.Id
|
||||||
|
where PSI.StartTime = '00:00:00')");
|
||||||
|
|
||||||
|
migrationBuilder.Sql(
|
||||||
|
@"UPDATE Playout SET Anchor_NextStart = null, Anchor_NextScheduleItemId = null where Id in
|
||||||
|
(select Playout.Id from Playout
|
||||||
|
inner join ProgramSchedule PS on Playout.ProgramScheduleId = PS.Id
|
||||||
|
inner join ProgramScheduleItem PSI on PSI.ProgramScheduleId = PS.Id
|
||||||
|
where PSI.StartTime = '00:00:00')");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user