schedule filler using ticks instead of milliseconds (#1454)
* add script to set db provider * don't extract embedded subtitles with DEBUG_NO_SYNC * fix playout filler precision bug
This commit is contained in:
@@ -15,6 +15,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix playout bug that caused some schedule items with fixed start times to be pushed to the next day
|
- Fix playout bug that caused some schedule items with fixed start times to be pushed to the next day
|
||||||
|
- Fix playout bug that prevented padded durations from fitting within a schedule item of the same duration
|
||||||
|
- For example, filler that padded to 30 minutes would often not fit in a 30 minute duration schedule item
|
||||||
- Fix VAAPI transcoding 8-bit source content to 10-bit
|
- Fix VAAPI transcoding 8-bit source content to 10-bit
|
||||||
- Fix NVIDIA subtitle scaling when `scale_npp` filter is unavailable
|
- Fix NVIDIA subtitle scaling when `scale_npp` filter is unavailable
|
||||||
- Remove ffmpeg and ffprobe as required dependencies for scanning media server libraries
|
- Remove ffmpeg and ffprobe as required dependencies for scanning media server libraries
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
using ErsatzTV.Core.Domain;
|
using Destructurama;
|
||||||
|
using ErsatzTV.Core.Domain;
|
||||||
using ErsatzTV.Core.Domain.Filler;
|
using ErsatzTV.Core.Domain.Filler;
|
||||||
using ErsatzTV.Core.Scheduling;
|
using ErsatzTV.Core.Scheduling;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NSubstitute;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace ErsatzTV.Core.Tests.Scheduling;
|
namespace ErsatzTV.Core.Tests.Scheduling;
|
||||||
|
|
||||||
@@ -15,6 +16,20 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||||
|
|
||||||
private CancellationToken _cancellationToken;
|
private CancellationToken _cancellationToken;
|
||||||
|
private readonly ILogger<PlayoutModeSchedulerDuration> _logger;
|
||||||
|
|
||||||
|
public PlayoutModeSchedulerDurationTests()
|
||||||
|
{
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Debug()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.Destructure.UsingAttributes()
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
ILoggerFactory loggerFactory = new LoggerFactory().AddSerilog(Log.Logger);
|
||||||
|
|
||||||
|
_logger = loggerFactory.CreateLogger<PlayoutModeSchedulerDuration>();
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Should_Fill_Exact_Duration()
|
public void Should_Fill_Exact_Duration()
|
||||||
@@ -44,7 +59,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator),
|
CollectionEnumerators(scheduleItem, enumerator),
|
||||||
@@ -117,7 +132,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator),
|
CollectionEnumerators(scheduleItem, enumerator),
|
||||||
@@ -189,7 +204,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator),
|
CollectionEnumerators(scheduleItem, enumerator),
|
||||||
@@ -258,7 +273,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator),
|
CollectionEnumerators(scheduleItem, enumerator),
|
||||||
@@ -341,7 +356,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
|
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.FallbackFiller, enumerator2),
|
||||||
@@ -428,7 +443,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
|
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
|
||||||
@@ -527,7 +542,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
|
CollectionEnumerators(scheduleItem, enumerator1, scheduleItem.TailFiller, enumerator2),
|
||||||
@@ -637,7 +652,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(
|
CollectionEnumerators(
|
||||||
@@ -710,6 +725,119 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback);
|
playoutItems[6].FillerKind.Should().Be(FillerKind.Fallback);
|
||||||
playoutItems[6].GuideFinish.HasValue.Should().BeFalse();
|
playoutItems[6].GuideFinish.HasValue.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Should_Not_Have_Gap_With_Post_Roll_Pad_And_Fallback_Filler()
|
||||||
|
{
|
||||||
|
Collection collectionPre = TwoItemCollection(1, 2, TimeSpan.Parse("00:00:15.6734470"));
|
||||||
|
Collection collectionOne = TwoItemCollection(3, 4, TimeSpan.Parse("00:22:58.1220000"));
|
||||||
|
Collection collectionTwo = CollectionOf(
|
||||||
|
new Dictionary<int, TimeSpan>
|
||||||
|
{
|
||||||
|
{ 5, TimeSpan.Parse("00:00:31.3004760") },
|
||||||
|
{ 6, TimeSpan.Parse("00:00:31.7880950") },
|
||||||
|
{ 7, TimeSpan.Parse("00:00:31.1147170") },
|
||||||
|
{ 8, TimeSpan.Parse("00:00:46.4863270") },
|
||||||
|
{ 9, TimeSpan.Parse("00:00:31.4165760") },
|
||||||
|
{ 10, TimeSpan.Parse("00:00:31.5791160") },
|
||||||
|
{ 11, TimeSpan.Parse("00:00:31.2540360") },
|
||||||
|
{ 12, TimeSpan.Parse("00:00:36.2231070") },
|
||||||
|
{ 13, TimeSpan.Parse("00:02:00.0471430") },
|
||||||
|
});
|
||||||
|
Collection collectionThree = TwoItemCollection(14, 15, TimeSpan.Parse("00:00:55.6349890"));
|
||||||
|
|
||||||
|
var scheduleItem = new ProgramScheduleItemDuration
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
Index = 1,
|
||||||
|
Collection = collectionOne,
|
||||||
|
CollectionId = collectionOne.Id,
|
||||||
|
StartTime = null,
|
||||||
|
PlayoutDuration = TimeSpan.FromMinutes(30),
|
||||||
|
PlaybackOrder = PlaybackOrder.Chronological,
|
||||||
|
PreRollFiller = new FillerPreset
|
||||||
|
{
|
||||||
|
FillerKind = FillerKind.PreRoll,
|
||||||
|
FillerMode = FillerMode.Count,
|
||||||
|
Count = 1,
|
||||||
|
Collection = collectionPre,
|
||||||
|
CollectionId = collectionPre.Id
|
||||||
|
},
|
||||||
|
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 scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||||
|
new List<ProgramScheduleItem> { scheduleItem },
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator1 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionPre.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator2 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionOne.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator3 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionTwo.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
var enumerator4 = new ChronologicalMediaCollectionEnumerator(
|
||||||
|
collectionThree.MediaItems,
|
||||||
|
new CollectionEnumeratorState());
|
||||||
|
|
||||||
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
|
startState,
|
||||||
|
CollectionEnumerators(
|
||||||
|
scheduleItem,
|
||||||
|
enumerator2,
|
||||||
|
scheduleItem.PreRollFiller,
|
||||||
|
enumerator1,
|
||||||
|
scheduleItem.PostRollFiller,
|
||||||
|
enumerator3,
|
||||||
|
scheduleItem.FallbackFiller,
|
||||||
|
enumerator4),
|
||||||
|
scheduleItem,
|
||||||
|
NextScheduleItem,
|
||||||
|
HardStop(scheduleItemsEnumerator),
|
||||||
|
_cancellationToken);
|
||||||
|
|
||||||
|
playoutBuilderState.CurrentTime.Should().Be(startState.CurrentTime.AddMinutes(30));
|
||||||
|
playoutItems.Last().FinishOffset.Should().Be(playoutBuilderState.CurrentTime);
|
||||||
|
|
||||||
|
// THIS IS THE KEY TEST - needs to be exactly 30 minutes
|
||||||
|
(playoutItems.Last().FinishOffset - playoutItems.First().StartOffset).Should().Be(TimeSpan.FromMinutes(30));
|
||||||
|
|
||||||
|
// playoutBuilderState.NextGuideGroup.Should().Be(3);
|
||||||
|
playoutBuilderState.DurationFinish.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InFlood.Should().BeFalse();
|
||||||
|
playoutBuilderState.MultipleRemaining.IsNone.Should().BeTrue();
|
||||||
|
playoutBuilderState.InDurationFiller.Should().BeFalse();
|
||||||
|
playoutBuilderState.ScheduleItemsEnumerator.State.Index.Should().Be(0);
|
||||||
|
|
||||||
|
enumerator1.State.Index.Should().Be(1);
|
||||||
|
enumerator2.State.Index.Should().Be(1);
|
||||||
|
enumerator3.State.Index.Should().Be(0);
|
||||||
|
enumerator4.State.Index.Should().Be(1);
|
||||||
|
|
||||||
|
playoutItems.Count.Should().Be(12);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Should_Not_Schedule_At_HardStop()
|
public void Should_Not_Schedule_At_HardStop()
|
||||||
@@ -745,7 +873,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
|||||||
|
|
||||||
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
PlayoutBuilderState startState = StartState(scheduleItemsEnumerator);
|
||||||
|
|
||||||
var scheduler = new PlayoutModeSchedulerDuration(Substitute.For<ILogger>());
|
var scheduler = new PlayoutModeSchedulerDuration(_logger);
|
||||||
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
(PlayoutBuilderState playoutBuilderState, List<PlayoutItem> playoutItems) = scheduler.Schedule(
|
||||||
startState,
|
startState,
|
||||||
CollectionEnumerators(scheduleItem, enumerator),
|
CollectionEnumerators(scheduleItem, enumerator),
|
||||||
|
|||||||
@@ -45,6 +45,23 @@ public abstract class SchedulerTestBase
|
|||||||
{ CollectionKey.ForFillerPreset(fillerPreset), enumerator2 },
|
{ CollectionKey.ForFillerPreset(fillerPreset), enumerator2 },
|
||||||
{ CollectionKey.ForFillerPreset(fillerPreset2), enumerator3 }
|
{ CollectionKey.ForFillerPreset(fillerPreset2), enumerator3 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected static Dictionary<CollectionKey, IMediaCollectionEnumerator> CollectionEnumerators(
|
||||||
|
ProgramScheduleItem scheduleItem,
|
||||||
|
IMediaCollectionEnumerator enumerator1,
|
||||||
|
FillerPreset fillerPreset,
|
||||||
|
IMediaCollectionEnumerator enumerator2,
|
||||||
|
FillerPreset fillerPreset2,
|
||||||
|
IMediaCollectionEnumerator enumerator3,
|
||||||
|
FillerPreset fillerPreset3,
|
||||||
|
IMediaCollectionEnumerator enumerator4) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
{ CollectionKey.ForScheduleItem(scheduleItem), enumerator1 },
|
||||||
|
{ CollectionKey.ForFillerPreset(fillerPreset), enumerator2 },
|
||||||
|
{ CollectionKey.ForFillerPreset(fillerPreset2), enumerator3 },
|
||||||
|
{ CollectionKey.ForFillerPreset(fillerPreset3), enumerator4 }
|
||||||
|
};
|
||||||
|
|
||||||
private static Movie TestMovie(int id, TimeSpan duration, DateTime aired, int chapterCount = 0)
|
private static Movie TestMovie(int id, TimeSpan duration, DateTime aired, int chapterCount = 0)
|
||||||
{
|
{
|
||||||
@@ -81,6 +98,22 @@ public abstract class SchedulerTestBase
|
|||||||
TestMovie(id2, duration, new DateTime(2020, 1, 2), chapterCount)
|
TestMovie(id2, duration, new DateTime(2020, 1, 2), chapterCount)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected static Collection CollectionOf(IDictionary<int, TimeSpan> idsAndDurations, int chapterCount = 0)
|
||||||
|
{
|
||||||
|
var mediaItems = new List<MediaItem>();
|
||||||
|
foreach ((int id, TimeSpan duration) in idsAndDurations)
|
||||||
|
{
|
||||||
|
mediaItems.Add(TestMovie(id, duration, new DateTime(2020, 1, id), chapterCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Collection
|
||||||
|
{
|
||||||
|
Id = idsAndDurations.Head().Key,
|
||||||
|
Name = $"Collection of Items {idsAndDurations.Head().Key}",
|
||||||
|
MediaItems = mediaItems
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
protected static Dictionary<CollectionKey, IMediaCollectionEnumerator> CollectionEnumerators(
|
protected static Dictionary<CollectionKey, IMediaCollectionEnumerator> CollectionEnumerators(
|
||||||
ProgramScheduleItem scheduleItem,
|
ProgramScheduleItem scheduleItem,
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
|
|||||||
public static DateTimeOffset GetStartTimeAfter(PlayoutBuilderState state, ProgramScheduleItem scheduleItem)
|
public static DateTimeOffset GetStartTimeAfter(PlayoutBuilderState state, ProgramScheduleItem scheduleItem)
|
||||||
{
|
{
|
||||||
DateTimeOffset startTime = state.CurrentTime.ToLocalTime();
|
DateTimeOffset startTime = state.CurrentTime.ToLocalTime();
|
||||||
startTime = startTime.AddTicks(-(startTime.Ticks % TimeSpan.TicksPerSecond));
|
|
||||||
|
|
||||||
bool isIncomplete = scheduleItem is ProgramScheduleItemMultiple && state.MultipleRemaining.IsSome ||
|
bool isIncomplete = scheduleItem is ProgramScheduleItemMultiple && state.MultipleRemaining.IsSome ||
|
||||||
scheduleItem is ProgramScheduleItemDuration && state.DurationFinish.IsSome ||
|
scheduleItem is ProgramScheduleItemDuration && state.DurationFinish.IsSome ||
|
||||||
@@ -51,7 +50,6 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
|
|||||||
if (scheduleItem.StartType == StartType.Fixed && !isIncomplete)
|
if (scheduleItem.StartType == StartType.Fixed && !isIncomplete)
|
||||||
{
|
{
|
||||||
TimeSpan itemStartTime = scheduleItem.StartTime.GetValueOrDefault();
|
TimeSpan itemStartTime = scheduleItem.StartTime.GetValueOrDefault();
|
||||||
itemStartTime = TimeSpan.FromMilliseconds((int)itemStartTime.TotalMilliseconds);
|
|
||||||
|
|
||||||
DateTime date = startTime.Date;
|
DateTime date = startTime.Date;
|
||||||
DateTimeOffset result = new DateTimeOffset(
|
DateTimeOffset result = new DateTimeOffset(
|
||||||
@@ -352,13 +350,12 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
|
|||||||
foreach (FillerPreset padFiller in Optional(
|
foreach (FillerPreset padFiller in Optional(
|
||||||
allFiller.FirstOrDefault(f => f.FillerMode == FillerMode.Pad && f.PadToNearestMinute.HasValue)))
|
allFiller.FirstOrDefault(f => f.FillerMode == FillerMode.Pad && f.PadToNearestMinute.HasValue)))
|
||||||
{
|
{
|
||||||
var totalDuration = TimeSpan.FromMilliseconds(result.Sum(pi => (pi.Finish - pi.Start).TotalMilliseconds));
|
var totalDuration = TimeSpan.FromTicks(result.Sum(pi => (pi.Finish - pi.Start).Ticks));
|
||||||
|
|
||||||
// add primary content to totalDuration only if it hasn't already been added
|
// add primary content to totalDuration only if it hasn't already been added
|
||||||
if (result.All(pi => pi.MediaItemId != playoutItem.MediaItemId))
|
if (result.All(pi => pi.MediaItemId != playoutItem.MediaItemId))
|
||||||
{
|
{
|
||||||
totalDuration += TimeSpan.FromMilliseconds(
|
totalDuration += TimeSpan.FromTicks(effectiveChapters.Sum(c => (c.EndTime - c.StartTime).Ticks));
|
||||||
effectiveChapters.Sum(c => (c.EndTime - c.StartTime).TotalMilliseconds));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int currentMinute = (playoutItem.StartOffset + totalDuration).Minute;
|
int currentMinute = (playoutItem.StartOffset + totalDuration).Minute;
|
||||||
@@ -402,8 +399,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
|
|||||||
padFiller.AllowWatermarks,
|
padFiller.AllowWatermarks,
|
||||||
log,
|
log,
|
||||||
cancellationToken));
|
cancellationToken));
|
||||||
totalDuration =
|
totalDuration = TimeSpan.FromTicks(result.Sum(pi => (pi.Finish - pi.Start).Ticks));
|
||||||
TimeSpan.FromMilliseconds(result.Sum(pi => (pi.Finish - pi.Start).TotalMilliseconds));
|
|
||||||
remainingToFill = targetTime - totalDuration - playoutItem.StartOffset;
|
remainingToFill = targetTime - totalDuration - playoutItem.StartOffset;
|
||||||
if (remainingToFill > TimeSpan.Zero)
|
if (remainingToFill > TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
@@ -493,8 +489,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
|
|||||||
padFiller.AllowWatermarks,
|
padFiller.AllowWatermarks,
|
||||||
log,
|
log,
|
||||||
cancellationToken));
|
cancellationToken));
|
||||||
totalDuration =
|
totalDuration = TimeSpan.FromTicks(result.Sum(pi => (pi.Finish - pi.Start).Ticks));
|
||||||
TimeSpan.FromMilliseconds(result.Sum(pi => (pi.Finish - pi.Start).TotalMilliseconds));
|
|
||||||
remainingToFill = targetTime - totalDuration - playoutItem.StartOffset;
|
remainingToFill = targetTime - totalDuration - playoutItem.StartOffset;
|
||||||
if (remainingToFill > TimeSpan.Zero)
|
if (remainingToFill > TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ public class PlayoutModeSchedulerDuration : PlayoutModeSchedulerBase<ProgramSche
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan durationBlock = itemEndTimeWithFiller - itemStartTime;
|
TimeSpan durationBlock = itemEndTimeWithFiller - itemStartTime;
|
||||||
if (itemEndTimeWithFiller - itemStartTime > scheduleItem.PlayoutDuration)
|
if (durationBlock > scheduleItem.PlayoutDuration)
|
||||||
{
|
{
|
||||||
Logger.LogWarning(
|
Logger.LogWarning(
|
||||||
"Unable to schedule duration block of {DurationBlock:hh\\:mm\\:ss} which is longer than the configured playout duration {PlayoutDuration:hh\\:mm\\:ss}",
|
"Unable to schedule duration block of {DurationBlock:hh\\:mm\\:ss} which is longer than the configured playout duration {PlayoutDuration:hh\\:mm\\:ss}",
|
||||||
|
|||||||
@@ -86,9 +86,11 @@ public class WorkerService : BackgroundService
|
|||||||
case MatchTraktListItems matchTraktListItems:
|
case MatchTraktListItems matchTraktListItems:
|
||||||
await mediator.Send(matchTraktListItems, stoppingToken);
|
await mediator.Send(matchTraktListItems, stoppingToken);
|
||||||
break;
|
break;
|
||||||
|
#if !DEBUG_NO_SYNC
|
||||||
case ExtractEmbeddedSubtitles extractEmbeddedSubtitles:
|
case ExtractEmbeddedSubtitles extractEmbeddedSubtitles:
|
||||||
await mediator.Send(extractEmbeddedSubtitles, stoppingToken);
|
await mediator.Send(extractEmbeddedSubtitles, stoppingToken);
|
||||||
break;
|
break;
|
||||||
|
#endif
|
||||||
case ReleaseMemory aggressivelyReleaseMemory:
|
case ReleaseMemory aggressivelyReleaseMemory:
|
||||||
await mediator.Send(aggressivelyReleaseMemory, stoppingToken);
|
await mediator.Send(aggressivelyReleaseMemory, stoppingToken);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]] ; then
|
||||||
|
echo 'Please specify a database provider'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd "$(git rev-parse --show-cdup)" || exit
|
||||||
|
cd ErsatzTV && dotnet user-secrets set "Provider" "$1"
|
||||||
|
|
||||||
|
cd "$(git rev-parse --show-cdup)" || exit
|
||||||
|
cd ErsatzTV.Scanner && dotnet user-secrets set "Provider" "$1"
|
||||||
Reference in New Issue
Block a user