make count an expression in classic schedules (#2794)
* make count an expression in classic schedules * add tests
This commit is contained in:
22
CHANGELOG.md
22
CHANGELOG.md
@@ -22,6 +22,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Disable automatic artwork database cleanup
|
||||
- This will be re-enabled at some point in the future (after more testing)
|
||||
- For now, the API should be used to clean as needed
|
||||
- Classic Schedules: make multiple `count` an expression
|
||||
- The following parameters can be used:
|
||||
- `count`: the total number of items in the collection
|
||||
- `random`: a random number between zero and (count - 1)
|
||||
- For example:
|
||||
- `count / 2` will play half of the items in the collection
|
||||
- `random % 4 + 1` will play between 1 and 4 items
|
||||
- `2` (similar to before this change) will play exactly two items
|
||||
|
||||
### Fixed
|
||||
- Use code signing on all Windows executables (`ErsatzTV-Windows.exe`, `ErsatzTV.exe`, `ErsatzTV.Scanner.exe`)
|
||||
@@ -760,13 +768,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- `random` will start at a random point in the content
|
||||
- `2` (similar to before this change) will skip the first two items in the content
|
||||
- YAML playout: make `count` an expression
|
||||
- The following parameters can be used:
|
||||
- `count`: the total number of items in the content
|
||||
- `random`: a random number between zero and (count - 1)
|
||||
- For example:
|
||||
- `count / 2` will play half of the items in the content
|
||||
- `random % 4 + 1` will play between 1 and 4 items
|
||||
- `2` (similar to before this change) will play exactly two items
|
||||
- The following parameters can be used:
|
||||
- `count`: the total number of items in the content
|
||||
- `random`: a random number between zero and (count - 1)
|
||||
- For example:
|
||||
- `count / 2` will play half of the items in the content
|
||||
- `random % 4 + 1` will play between 1 and 4 items
|
||||
- `2` (similar to before this change) will play exactly two items
|
||||
- YAML playout: add `disable_watermarks` property to all content instructions
|
||||
- This property defaults to `false` (meaning watermarks are allowed by default)
|
||||
- Setting to `true` will prevent watermarks from ever appearing over the content
|
||||
|
||||
@@ -26,7 +26,7 @@ public record AddProgramScheduleItem(
|
||||
int? MarathonBatchSize,
|
||||
FillWithGroupMode FillWithGroupMode,
|
||||
MultipleMode MultipleMode,
|
||||
int? MultipleCount,
|
||||
string MultipleCount,
|
||||
TimeSpan? PlayoutDuration,
|
||||
TailMode TailMode,
|
||||
int? DiscardToFillAttempts,
|
||||
|
||||
@@ -24,7 +24,7 @@ public interface IProgramScheduleItemRequest
|
||||
int? MarathonBatchSize { get; }
|
||||
FillWithGroupMode FillWithGroupMode { get; }
|
||||
MultipleMode MultipleMode { get; }
|
||||
int? MultipleCount { get; }
|
||||
string MultipleCount { get; }
|
||||
TimeSpan? PlayoutDuration { get; }
|
||||
TailMode TailMode { get; }
|
||||
int? DiscardToFillAttempts { get; }
|
||||
|
||||
@@ -79,10 +79,10 @@ public abstract class ProgramScheduleItemCommandBase
|
||||
"[MultipleMode] cannot be [PlaylistItemSize] when collection is not a playlist");
|
||||
}
|
||||
|
||||
if (item.MultipleMode is MultipleMode.Count && item.MultipleCount.GetValueOrDefault() < 1)
|
||||
if (item.MultipleMode is MultipleMode.Count && string.IsNullOrWhiteSpace(item.MultipleCount))
|
||||
{
|
||||
return BaseError.New(
|
||||
"[MultipleCount] must be greater than 0 for playout mode 'multiple / count'");
|
||||
"[MultipleCount] must be valid for playout mode 'multiple / count'");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -298,7 +298,7 @@ public abstract class ProgramScheduleItemCommandBase
|
||||
MarathonBatchSize = item.MarathonBatchSize,
|
||||
FillWithGroupMode = item.FillWithGroupMode,
|
||||
MultipleMode = item.MultipleMode,
|
||||
Count = item.MultipleMode is MultipleMode.Count ? item.MultipleCount.GetValueOrDefault() : 0,
|
||||
Count = item.MultipleMode is MultipleMode.Count ? item.MultipleCount ?? "0" : "0",
|
||||
CustomTitle = item.CustomTitle,
|
||||
GuideMode = item.GuideMode,
|
||||
PreRollFillerId = item.PreRollFillerId,
|
||||
|
||||
@@ -26,7 +26,7 @@ public record ReplaceProgramScheduleItem(
|
||||
int? MarathonBatchSize,
|
||||
FillWithGroupMode FillWithGroupMode,
|
||||
MultipleMode MultipleMode,
|
||||
int? MultipleCount,
|
||||
string MultipleCount,
|
||||
TimeSpan? PlayoutDuration,
|
||||
TailMode TailMode,
|
||||
int? DiscardToFillAttempts,
|
||||
|
||||
@@ -32,7 +32,7 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
|
||||
int? marathonBatchSize,
|
||||
FillWithGroupMode fillWithGroupMode,
|
||||
MultipleMode multipleMode,
|
||||
int count,
|
||||
string count,
|
||||
string customTitle,
|
||||
GuideMode guideMode,
|
||||
FillerPresetViewModel preRollFiller,
|
||||
@@ -87,5 +87,5 @@ public record ProgramScheduleItemMultipleViewModel : ProgramScheduleItemViewMode
|
||||
|
||||
public MultipleMode MultipleMode { get; set; }
|
||||
|
||||
public int Count { get; }
|
||||
public string Count { get; }
|
||||
}
|
||||
|
||||
@@ -666,7 +666,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = collectionOne,
|
||||
CollectionId = collectionOne.Id,
|
||||
StartTime = null,
|
||||
Count = 3,
|
||||
Count = "3",
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
},
|
||||
new ProgramScheduleItemMultiple
|
||||
@@ -676,7 +676,7 @@ public class ContinuePlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = collectionTwo,
|
||||
CollectionId = collectionTwo.Id,
|
||||
StartTime = null,
|
||||
Count = 3,
|
||||
Count = "3",
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
}
|
||||
};
|
||||
|
||||
@@ -852,7 +852,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = fixedCollection,
|
||||
CollectionId = fixedCollection.Id,
|
||||
StartTime = TimeSpan.FromHours(3),
|
||||
Count = 2,
|
||||
Count = "2",
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
}
|
||||
};
|
||||
@@ -981,7 +981,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = fixedCollection,
|
||||
CollectionId = fixedCollection.Id,
|
||||
StartTime = TimeSpan.FromHours(3),
|
||||
Count = 2,
|
||||
Count = "2",
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
}
|
||||
};
|
||||
@@ -1361,7 +1361,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = multipleCollection,
|
||||
CollectionId = multipleCollection.Id,
|
||||
StartTime = null,
|
||||
Count = 2,
|
||||
Count = "2",
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
},
|
||||
new ProgramScheduleItemDuration
|
||||
@@ -1494,7 +1494,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = collectionOne,
|
||||
CollectionId = collectionOne.Id,
|
||||
StartTime = null,
|
||||
Count = 0,
|
||||
Count = "0",
|
||||
MultipleMode = MultipleMode.CollectionSize,
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
},
|
||||
@@ -1505,7 +1505,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = collectionTwo,
|
||||
CollectionId = collectionTwo.Id,
|
||||
StartTime = null,
|
||||
Count = 0,
|
||||
Count = "0",
|
||||
MultipleMode = MultipleMode.CollectionSize,
|
||||
PlaybackOrder = PlaybackOrder.Chronological
|
||||
}
|
||||
@@ -1777,7 +1777,7 @@ public class NewPlayoutTests : PlayoutBuilderTestBase
|
||||
Collection = collectionOne,
|
||||
CollectionId = collectionOne.Id,
|
||||
StartTime = null,
|
||||
Count = 1,
|
||||
Count = "1",
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
PostRollFiller = new FillerPreset
|
||||
{
|
||||
|
||||
34
ErsatzTV.Core.Tests/Scheduling/CountExpressionTests.cs
Normal file
34
ErsatzTV.Core.Tests/Scheduling/CountExpressionTests.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using ErsatzTV.Core.Interfaces.Scheduling;
|
||||
using ErsatzTV.Core.Scheduling;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using Shouldly;
|
||||
|
||||
namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
|
||||
[TestFixture]
|
||||
public class CountExpressionTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("2", 2)]
|
||||
[TestCase("count", 10)]
|
||||
[TestCase("count / 2", 5)]
|
||||
[TestCase("count * 2", 20)]
|
||||
[TestCase("count + 1", 11)]
|
||||
[TestCase("count - 1", 9)]
|
||||
[TestCase("random % 4 + 1", 3)]
|
||||
[TestCase("invalid", 0)]
|
||||
[TestCase("count / 0", 0)]
|
||||
public void Should_Evaluate_Expression(string expression, int expected)
|
||||
{
|
||||
var enumerator = Substitute.For<IMediaCollectionEnumerator>();
|
||||
enumerator.Count.Returns(10);
|
||||
|
||||
var random = Substitute.For<Random>();
|
||||
random.Next().Returns(2);
|
||||
|
||||
int result = CountExpression.Evaluate(expression, enumerator, random, CancellationToken.None);
|
||||
|
||||
result.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
@@ -796,6 +796,7 @@ public class PlayoutModeSchedulerBaseTests : SchedulerTestBase
|
||||
ProgramScheduleItem scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken) =>
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -13,9 +13,14 @@ namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
public void SetUp()
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
private CancellationToken _cancellationToken;
|
||||
private Random _random;
|
||||
private readonly ILogger<PlayoutModeSchedulerDuration> _logger;
|
||||
|
||||
public PlayoutModeSchedulerDurationTests()
|
||||
@@ -66,6 +71,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -139,6 +145,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -211,6 +218,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
|
||||
@@ -280,6 +288,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
// duration block should end after exact duration, with gap
|
||||
@@ -363,6 +372,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -450,6 +460,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -549,6 +560,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -665,6 +677,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -816,6 +829,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddMinutes(30));
|
||||
@@ -880,6 +894,7 @@ public class PlayoutModeSchedulerDurationTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutItems.ShouldBeEmpty();
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
public void SetUp()
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
private CancellationToken _cancellationToken;
|
||||
private Random _random;
|
||||
|
||||
[Test]
|
||||
public void Should_Fill_Exactly_To_Next_Schedule_Item()
|
||||
@@ -57,6 +62,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -132,6 +138,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
scheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(6));
|
||||
@@ -229,6 +236,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -314,6 +322,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -402,6 +411,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
|
||||
@@ -484,6 +494,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -582,6 +593,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -670,6 +682,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
|
||||
@@ -784,6 +797,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -896,6 +910,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
hardStop,
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(2));
|
||||
@@ -1002,6 +1017,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
hardStop,
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(2));
|
||||
@@ -1116,6 +1132,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -1190,6 +1207,7 @@ public class PlayoutModeSchedulerFloodTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutItems.ShouldBeEmpty();
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
public void SetUp()
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
private CancellationToken _cancellationToken;
|
||||
private Random _random;
|
||||
|
||||
[Test]
|
||||
public void Should_Respect_Fixed_Start_Time()
|
||||
@@ -32,7 +37,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
TailFiller = null,
|
||||
FallbackFiller = null,
|
||||
Count = 0,
|
||||
Count = "0",
|
||||
MultipleMode = MultipleMode.CollectionSize,
|
||||
CustomTitle = "CustomTitle"
|
||||
};
|
||||
@@ -59,6 +64,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -134,7 +140,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
TailFiller = null,
|
||||
FallbackFiller = null,
|
||||
Count = 0,
|
||||
Count = "0",
|
||||
MultipleMode = MultipleMode.MultiEpisodeGroupSize,
|
||||
CustomTitle = "CustomTitle"
|
||||
};
|
||||
@@ -161,6 +167,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -206,7 +213,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
TailFiller = null,
|
||||
FallbackFiller = null,
|
||||
Count = 3,
|
||||
Count = "3",
|
||||
CustomTitle = "CustomTitle"
|
||||
};
|
||||
|
||||
@@ -232,6 +239,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -282,7 +290,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
TailFiller = null,
|
||||
FallbackFiller = null,
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -307,6 +315,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 45, 0)));
|
||||
@@ -360,7 +369,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
CollectionId = collectionTwo.Id
|
||||
},
|
||||
FallbackFiller = null,
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -390,6 +399,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -459,7 +469,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
Collection = collectionTwo,
|
||||
CollectionId = collectionTwo.Id
|
||||
},
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -489,6 +499,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -548,7 +559,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
CollectionId = collectionTwo.Id
|
||||
},
|
||||
FallbackFiller = null,
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -578,6 +589,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
|
||||
@@ -653,7 +665,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
Collection = collectionThree,
|
||||
CollectionId = collectionThree.Id
|
||||
},
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -694,6 +706,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -775,7 +788,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
Collection = collectionThree,
|
||||
CollectionId = collectionThree.Id
|
||||
},
|
||||
Count = 3
|
||||
Count = "3"
|
||||
};
|
||||
|
||||
var scheduleItemsEnumerator = new OrderedScheduleItemsEnumerator(
|
||||
@@ -816,6 +829,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -865,7 +879,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
PlaybackOrder = PlaybackOrder.Chronological,
|
||||
TailFiller = null,
|
||||
FallbackFiller = null,
|
||||
Count = 2
|
||||
Count = "2"
|
||||
};
|
||||
|
||||
var enumerator = new ChronologicalMediaCollectionEnumerator(
|
||||
@@ -896,6 +910,7 @@ public class PlayoutModeSchedulerMultipleTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutItems.ShouldBeEmpty();
|
||||
|
||||
@@ -12,9 +12,14 @@ namespace ErsatzTV.Core.Tests.Scheduling;
|
||||
public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => _cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
public void SetUp()
|
||||
{
|
||||
_cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token;
|
||||
_random = new Random();
|
||||
}
|
||||
|
||||
private CancellationToken _cancellationToken;
|
||||
private Random _random;
|
||||
|
||||
[Test]
|
||||
public void Should_Have_Gap_With_No_Tail_No_Fallback()
|
||||
@@ -51,6 +56,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(1));
|
||||
@@ -134,6 +140,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(1));
|
||||
@@ -202,6 +209,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -284,6 +292,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -356,6 +365,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.Add(new TimeSpan(2, 57, 0)));
|
||||
@@ -454,6 +464,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -558,6 +569,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -644,6 +656,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -744,6 +757,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutBuilderState.CurrentTime.ShouldBe(startState.CurrentTime.AddHours(3));
|
||||
@@ -823,6 +837,7 @@ public class PlayoutModeSchedulerOneTests : SchedulerTestBase
|
||||
scheduleItem,
|
||||
NextScheduleItem,
|
||||
HardStop(scheduleItemsEnumerator),
|
||||
_random,
|
||||
_cancellationToken);
|
||||
|
||||
playoutItems.ShouldBeEmpty();
|
||||
|
||||
@@ -4,5 +4,5 @@ public class ProgramScheduleItemMultiple : ProgramScheduleItem
|
||||
{
|
||||
public MultipleMode MultipleMode { get; set; }
|
||||
|
||||
public int Count { get; set; }
|
||||
public string Count { get; set; }
|
||||
}
|
||||
|
||||
@@ -11,5 +11,6 @@ public interface IPlayoutModeScheduler<in T> where T : ProgramScheduleItem
|
||||
T scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
47
ErsatzTV.Core/Scheduling/CountExpression.cs
Normal file
47
ErsatzTV.Core/Scheduling/CountExpression.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using ErsatzTV.Core.Interfaces.Scheduling;
|
||||
using NCalc;
|
||||
|
||||
namespace ErsatzTV.Core.Scheduling;
|
||||
|
||||
public static class CountExpression
|
||||
{
|
||||
public static int Evaluate(
|
||||
string countExpression,
|
||||
IMediaCollectionEnumerator enumerator,
|
||||
Random random,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
int enumeratorCount = enumerator is PlaylistEnumerator playlistEnumerator
|
||||
? playlistEnumerator.CountForRandom
|
||||
: enumerator.Count;
|
||||
var expression = new Expression(countExpression);
|
||||
expression.EvaluateParameter += (name, e) =>
|
||||
{
|
||||
e.Result = name switch
|
||||
{
|
||||
"count" => enumeratorCount,
|
||||
"random" => enumeratorCount > 0 ? random.Next() % enumeratorCount : 0,
|
||||
_ => e.Result
|
||||
};
|
||||
};
|
||||
|
||||
object expressionResult = 0;
|
||||
try
|
||||
{
|
||||
expressionResult = expression.Evaluate(cancellationToken);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
return expressionResult switch
|
||||
{
|
||||
double d when double.IsInfinity(d) || double.IsNaN(d) => 0,
|
||||
double doubleResult => (int)Math.Floor(doubleResult),
|
||||
int intResult => intResult,
|
||||
long longResult => (int)longResult,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -857,6 +857,7 @@ public class PlayoutBuilder : IPlayoutBuilder
|
||||
multiple,
|
||||
nextScheduleItem,
|
||||
playoutFinish,
|
||||
random,
|
||||
cancellationToken),
|
||||
ProgramScheduleItemDuration duration => schedulerDuration.Schedule(
|
||||
playoutBuilderState,
|
||||
@@ -864,6 +865,7 @@ public class PlayoutBuilder : IPlayoutBuilder
|
||||
duration,
|
||||
nextScheduleItem,
|
||||
playoutFinish,
|
||||
random,
|
||||
cancellationToken),
|
||||
ProgramScheduleItemFlood flood => schedulerFlood.Schedule(
|
||||
playoutBuilderState,
|
||||
@@ -871,6 +873,7 @@ public class PlayoutBuilder : IPlayoutBuilder
|
||||
flood,
|
||||
nextScheduleItem,
|
||||
playoutFinish,
|
||||
random,
|
||||
cancellationToken),
|
||||
ProgramScheduleItemOne one => schedulerOne.Schedule(
|
||||
playoutBuilderState,
|
||||
@@ -878,6 +881,7 @@ public class PlayoutBuilder : IPlayoutBuilder
|
||||
one,
|
||||
nextScheduleItem,
|
||||
playoutFinish,
|
||||
random,
|
||||
cancellationToken),
|
||||
_ => throw new NotSupportedException(nameof(scheduleItem))
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@ public abstract class PlayoutModeSchedulerBase<T>(ILogger logger) : IPlayoutMode
|
||||
T scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken);
|
||||
|
||||
public static DateTimeOffset GetFillerStartTimeAfter(
|
||||
|
||||
@@ -16,6 +16,7 @@ public class PlayoutModeSchedulerDuration(ILogger logger)
|
||||
ProgramScheduleItemDuration scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var warnings = new PlayoutBuildWarnings();
|
||||
|
||||
@@ -15,6 +15,7 @@ public class PlayoutModeSchedulerFlood(ILogger logger) : PlayoutModeSchedulerBas
|
||||
ProgramScheduleItemFlood scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var warnings = new PlayoutBuildWarnings();
|
||||
|
||||
@@ -16,6 +16,7 @@ public class PlayoutModeSchedulerMultiple(Map<CollectionKey, int> collectionItem
|
||||
ProgramScheduleItemMultiple scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var warnings = new PlayoutBuildWarnings();
|
||||
@@ -28,15 +29,16 @@ public class PlayoutModeSchedulerMultiple(Map<CollectionKey, int> collectionItem
|
||||
return new PlayoutSchedulerResult(playoutBuilderState, playoutItems, warnings);
|
||||
}
|
||||
|
||||
IMediaCollectionEnumerator contentEnumerator =
|
||||
collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)];
|
||||
|
||||
PlayoutBuilderState nextState = playoutBuilderState with
|
||||
{
|
||||
CurrentTime = firstStart,
|
||||
MultipleRemaining = playoutBuilderState.MultipleRemaining.IfNone(scheduleItem.Count)
|
||||
MultipleRemaining = playoutBuilderState.MultipleRemaining.IfNone(
|
||||
CountExpression.Evaluate(scheduleItem.Count, contentEnumerator, random, cancellationToken))
|
||||
};
|
||||
|
||||
IMediaCollectionEnumerator contentEnumerator =
|
||||
collectionEnumerators[CollectionKey.ForScheduleItem(scheduleItem)];
|
||||
|
||||
if (nextState.MultipleRemaining == 0)
|
||||
{
|
||||
switch (scheduleItem.MultipleMode)
|
||||
|
||||
@@ -14,6 +14,7 @@ public class PlayoutModeSchedulerOne(ILogger logger) : PlayoutModeSchedulerBase<
|
||||
ProgramScheduleItemOne scheduleItem,
|
||||
ProgramScheduleItem nextScheduleItem,
|
||||
DateTimeOffset hardStop,
|
||||
Random random,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var warnings = new PlayoutBuildWarnings();
|
||||
|
||||
@@ -5,7 +5,6 @@ using ErsatzTV.Core.Extensions;
|
||||
using ErsatzTV.Core.Interfaces.Scheduling;
|
||||
using ErsatzTV.Core.Scheduling.YamlScheduling.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NCalc;
|
||||
|
||||
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Handlers;
|
||||
|
||||
@@ -34,27 +33,7 @@ public class YamlPlayoutCountHandler(EnumeratorCache enumeratorCache) : YamlPlay
|
||||
{
|
||||
int seed = context.Playout.Seed + context.InstructionIndex + context.CurrentTime.DayOfYear;
|
||||
var random = new Random(seed);
|
||||
int enumeratorCount = enumerator is PlaylistEnumerator playlistEnumerator
|
||||
? playlistEnumerator.CountForRandom
|
||||
: enumerator.Count;
|
||||
var expression = new Expression(count.Count);
|
||||
expression.EvaluateParameter += (name, e) =>
|
||||
{
|
||||
e.Result = name switch
|
||||
{
|
||||
"count" => enumeratorCount,
|
||||
"random" => enumeratorCount > 0 ? random.Next() % enumeratorCount : 0,
|
||||
_ => e.Result
|
||||
};
|
||||
};
|
||||
|
||||
object expressionResult = expression.Evaluate(cancellationToken);
|
||||
int countValue = expressionResult switch
|
||||
{
|
||||
double doubleResult => (int)Math.Floor(doubleResult),
|
||||
int intResult => intResult,
|
||||
_ => 0
|
||||
};
|
||||
int countValue = CountExpression.Evaluate(count.Count, enumerator, random, cancellationToken);
|
||||
|
||||
for (var i = 0; i < countValue; i++)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Change_ProgramScheduleItemMultipleCountString : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Count",
|
||||
table: "ProgramScheduleMultipleItem",
|
||||
type: "longtext",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int")
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "Count",
|
||||
table: "ProgramScheduleMultipleItem",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "longtext",
|
||||
oldNullable: true)
|
||||
.OldAnnotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.11")
|
||||
.HasAnnotation("ProductVersion", "9.0.12")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||
@@ -4130,8 +4130,8 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
|
||||
{
|
||||
b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem");
|
||||
|
||||
b.Property<int>("Count")
|
||||
.HasColumnType("int");
|
||||
b.Property<string>("Count")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("MultipleMode")
|
||||
.HasColumnType("int");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Change_ProgramScheduleItemMultipleCountString : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Count",
|
||||
table: "ProgramScheduleMultipleItem",
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "INTEGER");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "Count",
|
||||
table: "ProgramScheduleMultipleItem",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "TEXT",
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.11");
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.12");
|
||||
|
||||
modelBuilder.Entity("ErsatzTV.Core.Domain.Actor", b =>
|
||||
{
|
||||
@@ -3957,8 +3957,8 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
|
||||
{
|
||||
b.HasBaseType("ErsatzTV.Core.Domain.ProgramScheduleItem");
|
||||
|
||||
b.Property<int>("Count")
|
||||
.HasColumnType("INTEGER");
|
||||
b.Property<string>("Count")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("MultipleMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -532,7 +532,8 @@
|
||||
</div>
|
||||
<MudTextField @bind-Value="@_selectedItem.MultipleCount"
|
||||
For="@(() => _selectedItem.MultipleCount)"
|
||||
Disabled="@(_selectedItem.PlayoutMode is not PlayoutMode.Multiple || _selectedItem.MultipleMode is not MultipleMode.Count)"/>
|
||||
Disabled="@(_selectedItem.PlayoutMode is not PlayoutMode.Multiple || _selectedItem.MultipleMode is not MultipleMode.Count)"
|
||||
HelperText="Can be an expression with 'count' (collection size) and 'random' (0 to count-1)"/>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ProgramScheduleItemEditViewModelValidator : AbstractValidator<Progr
|
||||
{
|
||||
When(
|
||||
i => i.MultipleMode is MultipleMode.Count,
|
||||
() => RuleFor(i => i.MultipleCount).NotNull().GreaterThan(0));
|
||||
() => RuleFor(i => i.MultipleCount).NotEmpty());
|
||||
});
|
||||
When(
|
||||
i => i.PlayoutMode == PlayoutMode.Duration,
|
||||
|
||||
@@ -16,7 +16,7 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
|
||||
private CollectionType _collectionType;
|
||||
private int? _discardToFillAttempts;
|
||||
private FixedStartTimeBehavior? _fixedStartTimeBehavior;
|
||||
private int? _multipleCount;
|
||||
private string _multipleCount;
|
||||
private PlaybackOrder _playbackOrder;
|
||||
private TimeSpan? _playoutDuration;
|
||||
private int _playoutDurationHours;
|
||||
@@ -171,7 +171,7 @@ public class ProgramScheduleItemEditViewModel : INotifyPropertyChanged
|
||||
|
||||
public MultipleMode MultipleMode { get; set; }
|
||||
|
||||
public int? MultipleCount
|
||||
public string MultipleCount
|
||||
{
|
||||
get => PlayoutMode == PlayoutMode.Multiple ? _multipleCount : null;
|
||||
set => _multipleCount = value;
|
||||
|
||||
Reference in New Issue
Block a user