Browse Source

add pad_until instruction (#1831)

* revert dotnet workaround

* add pad_until instruction
pull/1832/head
Jason Dove 10 months ago committed by GitHub
parent
commit
391528cd94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutContentHandler.cs
  2. 78
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutPadUntilHandler.cs
  3. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRepeatHandler.cs
  4. 18
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPadUntilInstruction.cs
  5. 81
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs
  6. 3
      ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
  7. 3
      ErsatzTV/ErsatzTV.csproj

5
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutContentHandler.cs

@ -23,6 +23,11 @@ public abstract class YamlPlayoutContentHandler(EnumeratorCache enumeratorCache) @@ -23,6 +23,11 @@ public abstract class YamlPlayoutContentHandler(EnumeratorCache enumeratorCache)
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(contentKey))
{
return Option<IMediaCollectionEnumerator>.None;
}
Option<IMediaCollectionEnumerator> maybeEnumerator = await enumeratorCache.GetCachedEnumeratorForContent(
context,
contentKey,

78
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutPadUntilHandler.cs

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
using ErsatzTV.Core.Interfaces.Scheduling;
using ErsatzTV.Core.Scheduling.YamlScheduling.Models;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Handlers;
public class YamlPlayoutPadUntilHandler(EnumeratorCache enumeratorCache) : YamlPlayoutDurationHandler(enumeratorCache)
{
public override async Task<bool> Handle(
YamlPlayoutContext context,
YamlPlayoutInstruction instruction,
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlPlayoutPadUntilInstruction padUntil)
{
return false;
}
DateTimeOffset targetTime = context.CurrentTime;
if (TimeOnly.TryParse(padUntil.PadUntil, out TimeOnly result))
{
//logger.LogDebug("Will pad until time {Time}", result);
var dayOnly = DateOnly.FromDateTime(targetTime.LocalDateTime);
var timeOnly = TimeOnly.FromDateTime(targetTime.LocalDateTime);
if (timeOnly > result)
{
if (padUntil.Tomorrow)
{
// this is wrong when offset changes
dayOnly = dayOnly.AddDays(1);
targetTime = new DateTimeOffset(dayOnly, result, targetTime.Offset);
}
}
else
{
// this is wrong when offset changes
targetTime = new DateTimeOffset(dayOnly, result, targetTime.Offset);
}
}
// logger.LogDebug(
// "Padding from {CurrentTime} until {TargetTime}",
// context.CurrentTime,
// targetTime);
Option<IMediaCollectionEnumerator> maybeEnumerator = await GetContentEnumerator(
context,
instruction.Content,
logger,
cancellationToken);
Option<IMediaCollectionEnumerator> fallbackEnumerator = await GetContentEnumerator(
context,
padUntil.Fallback,
logger,
cancellationToken);
foreach (IMediaCollectionEnumerator enumerator in maybeEnumerator)
{
context.CurrentTime = Schedule(
context,
targetTime,
padUntil.DiscardAttempts,
padUntil.Trim,
GetFillerKind(padUntil),
enumerator,
fallbackEnumerator);
return true;
}
return false;
}
}

2
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutRepeatHandler.cs

@ -23,7 +23,7 @@ public class YamlPlayoutRepeatHandler : IYamlPlayoutHandler @@ -23,7 +23,7 @@ public class YamlPlayoutRepeatHandler : IYamlPlayoutHandler
if (_itemsSinceLastRepeat == context.Playout.Items.Count)
{
logger.LogWarning("Repeat encountered without adding any playout items; aborting");
return Task.FromResult(false);
throw new InvalidOperationException("YAML playout loop detected");
}
_itemsSinceLastRepeat = context.Playout.Items.Count;

18
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPadUntilInstruction.cs

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlPlayoutPadUntilInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "pad_until", ApplyNamingConventions = false)]
public string PadUntil { get; set; }
public bool Tomorrow { get; set; }
public bool Trim { get; set; }
public string Fallback { get; set; }
[YamlMember(Alias = "discard_attempts", ApplyNamingConventions = false)]
public int DiscardAttempts { get; set; }
}

81
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs

@ -91,6 +91,8 @@ public class YamlPlayoutBuilder( @@ -91,6 +91,8 @@ public class YamlPlayoutBuilder(
}
YamlPlayoutInstruction instruction = playoutDefinition.Playout[context.InstructionIndex];
//logger.LogDebug("Current playout instruction: {Instruction}", instruction.GetType().Name);
Option<IYamlPlayoutHandler> maybeHandler = GetHandlerForInstruction(handlers, enumeratorCache, instruction);
foreach (IYamlPlayoutHandler handler in maybeHandler)
@ -103,6 +105,7 @@ public class YamlPlayoutBuilder( @@ -103,6 +105,7 @@ public class YamlPlayoutBuilder(
if (!instruction.ChangesIndex)
{
//logger.LogDebug("Moving to next instruction");
context.InstructionIndex++;
}
}
@ -174,6 +177,7 @@ public class YamlPlayoutBuilder( @@ -174,6 +177,7 @@ public class YamlPlayoutBuilder(
YamlPlayoutCountInstruction => new YamlPlayoutCountHandler(enumeratorCache),
YamlPlayoutDurationInstruction => new YamlPlayoutDurationHandler(enumeratorCache),
YamlPlayoutPadToNextInstruction => new YamlPlayoutPadToNextHandler(enumeratorCache),
YamlPlayoutPadUntilInstruction => new YamlPlayoutPadUntilHandler(enumeratorCache),
_ => null
};
@ -186,42 +190,51 @@ public class YamlPlayoutBuilder( @@ -186,42 +190,51 @@ public class YamlPlayoutBuilder(
return Optional(handler);
}
private static async Task<YamlPlayoutDefinition> LoadYamlDefinition(Playout playout, CancellationToken cancellationToken)
private async Task<YamlPlayoutDefinition> LoadYamlDefinition(Playout playout, CancellationToken cancellationToken)
{
string yaml = await File.ReadAllTextAsync(playout.TemplateFile, cancellationToken);
IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.WithTypeDiscriminatingNodeDeserializer(
o =>
{
var contentKeyMappings = new Dictionary<string, Type>
{
{ "search", typeof(YamlPlayoutContentSearchItem) },
{ "show", typeof(YamlPlayoutContentShowItem) }
};
o.AddUniqueKeyTypeDiscriminator<YamlPlayoutContentItem>(contentKeyMappings);
try
{
string yaml = await File.ReadAllTextAsync(playout.TemplateFile, cancellationToken);
var instructionKeyMappings = new Dictionary<string, Type>
IDeserializer deserializer = new DeserializerBuilder()
.WithNamingConvention(CamelCaseNamingConvention.Instance)
.WithTypeDiscriminatingNodeDeserializer(
o =>
{
{ "all", typeof(YamlPlayoutAllInstruction) },
{ "count", typeof(YamlPlayoutCountInstruction) },
{ "duration", typeof(YamlPlayoutDurationInstruction) },
{ "new_epg_group", typeof(YamlPlayoutNewEpgGroupInstruction) },
{ "pad_to_next", typeof(YamlPlayoutPadToNextInstruction) },
{ "repeat", typeof(YamlPlayoutRepeatInstruction) },
{ "sequence", typeof(YamlPlayoutSequenceInstruction) },
{ "shuffle_sequence", typeof(YamlPlayoutShuffleSequenceInstruction) },
{ "skip_items", typeof(YamlPlayoutSkipItemsInstruction) },
{ "skip_to_item", typeof(YamlPlayoutSkipToItemInstruction) },
{ "wait_until", typeof(YamlPlayoutWaitUntilInstruction) }
};
o.AddUniqueKeyTypeDiscriminator<YamlPlayoutInstruction>(instructionKeyMappings);
})
.Build();
return deserializer.Deserialize<YamlPlayoutDefinition>(yaml);
var contentKeyMappings = new Dictionary<string, Type>
{
{ "search", typeof(YamlPlayoutContentSearchItem) },
{ "show", typeof(YamlPlayoutContentShowItem) }
};
o.AddUniqueKeyTypeDiscriminator<YamlPlayoutContentItem>(contentKeyMappings);
var instructionKeyMappings = new Dictionary<string, Type>
{
{ "all", typeof(YamlPlayoutAllInstruction) },
{ "count", typeof(YamlPlayoutCountInstruction) },
{ "duration", typeof(YamlPlayoutDurationInstruction) },
{ "new_epg_group", typeof(YamlPlayoutNewEpgGroupInstruction) },
{ "pad_to_next", typeof(YamlPlayoutPadToNextInstruction) },
{ "pad_until", typeof(YamlPlayoutPadUntilInstruction) },
{ "repeat", typeof(YamlPlayoutRepeatInstruction) },
{ "sequence", typeof(YamlPlayoutSequenceInstruction) },
{ "shuffle_sequence", typeof(YamlPlayoutShuffleSequenceInstruction) },
{ "skip_items", typeof(YamlPlayoutSkipItemsInstruction) },
{ "skip_to_item", typeof(YamlPlayoutSkipToItemInstruction) },
{ "wait_until", typeof(YamlPlayoutWaitUntilInstruction) }
};
o.AddUniqueKeyTypeDiscriminator<YamlPlayoutInstruction>(instructionKeyMappings);
})
.Build();
return deserializer.Deserialize<YamlPlayoutDefinition>(yaml);
}
catch (Exception ex)
{
logger.LogWarning(ex, "Error loading YAML");
throw;
}
}
}

3
ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj

@ -6,9 +6,6 @@ @@ -6,9 +6,6 @@
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<!-- works around MSB3374 error -->
<DisableFastUpToDateCheck>True</DisableFastUpToDateCheck>
</PropertyGroup>
<ItemGroup>

3
ErsatzTV/ErsatzTV.csproj

@ -13,9 +13,6 @@ @@ -13,9 +13,6 @@
<UserSecretsId>bf31217d-f4ec-4520-8cc3-138059044ede</UserSecretsId>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- works around MSB3374 error -->
<DisableFastUpToDateCheck>True</DisableFastUpToDateCheck>
</PropertyGroup>
<ItemGroup>

Loading…
Cancel
Save