Browse Source

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
pull/1455/head
Jason Dove 2 years ago committed by GitHub
parent
commit
bc845b1327
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 150
      ErsatzTV.Core.Tests/Scheduling/PlayoutModeSchedulerDurationTests.cs
  3. 33
      ErsatzTV.Core.Tests/Scheduling/SchedulerTestBase.cs
  4. 13
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs
  5. 2
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs
  6. 2
      ErsatzTV/Services/WorkerService.cs
  7. 12
      scripts/set-provider.sh

2
CHANGELOG.md

@ -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

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

@ -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),

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

@ -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,

13
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs

@ -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)
{ {

2
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerDuration.cs

@ -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}",

2
ErsatzTV/Services/WorkerService.cs

@ -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;

12
scripts/set-provider.sh

@ -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"
Loading…
Cancel
Save