Browse Source

add graphics_on and graphics_off yaml playout instructions (#2283)

pull/2284/head
Jason Dove 12 months ago committed by GitHub
parent
commit
2dc5bf58a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 20
      ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs
  3. 8
      ErsatzTV.Core/Interfaces/Repositories/IGraphicsElementRepository.cs
  4. 13
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutAllHandler.cs
  5. 13
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutCountHandler.cs
  6. 13
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutDurationHandler.cs
  7. 64
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutGraphicsOffHandler.cs
  8. 62
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutGraphicsOnHandler.cs
  9. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutMidRollHandler.cs
  10. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutPostRollHandler.cs
  11. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutPreRollHandler.cs
  12. 9
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutGraphicsOffInstruction.cs
  13. 9
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutGraphicsOnInstruction.cs
  14. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutMidRollInstruction.cs
  15. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPostRollInstruction.cs
  16. 2
      ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPreRollInstruction.cs
  17. 17
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs
  18. 65
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContext.cs
  19. 24
      ErsatzTV.Infrastructure/Data/Repositories/GraphicsElementRepository.cs
  20. 18
      ErsatzTV/Resources/yaml-playout-import.schema.json
  21. 20
      ErsatzTV/Resources/yaml-playout.schema.json
  22. 1
      ErsatzTV/Startup.cs

3
CHANGELOG.md

@ -25,6 +25,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -25,6 +25,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Supported in playback troubleshooting
- Displays multi-line text in a specified font, color, location, z-index
- Supports constant opacity and opacity expression
- YAML playout: add `graphics_on` and `graphics_off` instructions to control graphics elements
- `graphics_on` requires the name of a graphics element template, e.g. `text/cool_element.yml`
- `graphics_off` will turn off a specific element, or all elements if none are specified
### Fix
- Fix database operations that were slowing down playout builds

20
ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs

@ -136,7 +136,8 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -136,7 +136,8 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
changeCount += 1;
var bulkConfig = new BulkConfig();
bool anyWatermarks = result.AddedItems.Any(i => i.PlayoutItemWatermarks is not null && i.PlayoutItemWatermarks.Count > 0);
if (anyWatermarks)
bool anyGraphicsElements = result.AddedItems.Any(i => i.PlayoutItemGraphicsElements is not null && i.PlayoutItemGraphicsElements.Count > 0);
if (anyWatermarks || anyGraphicsElements)
{
bulkConfig.SetOutputIdentity = true;
}
@ -157,6 +158,23 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -157,6 +158,23 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
await dbContext.BulkInsertAsync(allWatermarks, cancellationToken: cancellationToken);
}
if (anyGraphicsElements)
{
Console.WriteLine("has graphics elements!");
// copy playout item ids back to graphics elements
var allGraphicsElements = result.AddedItems.SelectMany(item =>
item.PlayoutItemGraphicsElements.Select(graphicsElement =>
{
graphicsElement.PlayoutItemId = item.Id;
graphicsElement.PlayoutItem = null;
return graphicsElement;
})
).ToList();
await dbContext.BulkInsertAsync(allGraphicsElements, cancellationToken: cancellationToken);
}
}
if (result.HistoryToRemove.Count > 0)

8
ErsatzTV.Core/Interfaces/Repositories/IGraphicsElementRepository.cs

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
using ErsatzTV.Core.Domain;
namespace ErsatzTV.Core.Interfaces.Repositories;
public interface IGraphicsElementRepository
{
Task<Option<GraphicsElement>> GetGraphicsElementByPath(string path);
}

13
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutAllHandler.cs

@ -65,7 +65,8 @@ public class YamlPlayoutAllHandler(EnumeratorCache enumeratorCache) : YamlPlayou @@ -65,7 +65,8 @@ public class YamlPlayoutAllHandler(EnumeratorCache enumeratorCache) : YamlPlayou
//BlockKey = JsonConvert.SerializeObject(effectiveBlock.BlockKey),
//CollectionKey = JsonConvert.SerializeObject(collectionKey, JsonSettings),
//CollectionEtag = collectionEtags[collectionKey]
PlayoutItemWatermarks = []
PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
};
foreach (int watermarkId in context.GetChannelWatermarkIds())
@ -78,6 +79,16 @@ public class YamlPlayoutAllHandler(EnumeratorCache enumeratorCache) : YamlPlayou @@ -78,6 +79,16 @@ public class YamlPlayoutAllHandler(EnumeratorCache enumeratorCache) : YamlPlayou
});
}
foreach (int graphicsElementId in context.GetGraphicsElementIds())
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = graphicsElementId
});
}
await AddItemAndMidRoll(context, playoutItem, mediaItem, executeSequence);
context.AdvanceGuideGroup();

13
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutCountHandler.cs

@ -90,7 +90,8 @@ public class YamlPlayoutCountHandler(EnumeratorCache enumeratorCache) : YamlPlay @@ -90,7 +90,8 @@ public class YamlPlayoutCountHandler(EnumeratorCache enumeratorCache) : YamlPlay
//BlockKey = JsonConvert.SerializeObject(effectiveBlock.BlockKey),
//CollectionKey = JsonConvert.SerializeObject(collectionKey, JsonSettings),
//CollectionEtag = collectionEtags[collectionKey],
PlayoutItemWatermarks = []
PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
};
foreach (int watermarkId in context.GetChannelWatermarkIds())
@ -103,6 +104,16 @@ public class YamlPlayoutCountHandler(EnumeratorCache enumeratorCache) : YamlPlay @@ -103,6 +104,16 @@ public class YamlPlayoutCountHandler(EnumeratorCache enumeratorCache) : YamlPlay
});
}
foreach (int graphicsElementId in context.GetGraphicsElementIds())
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = graphicsElementId
});
}
await AddItemAndMidRoll(context, playoutItem, mediaItem, executeSequence);
context.AdvanceGuideGroup();

13
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutDurationHandler.cs

@ -124,7 +124,8 @@ public class YamlPlayoutDurationHandler(EnumeratorCache enumeratorCache) : YamlP @@ -124,7 +124,8 @@ public class YamlPlayoutDurationHandler(EnumeratorCache enumeratorCache) : YamlP
FillerKind = fillerKind,
CustomTitle = string.IsNullOrWhiteSpace(customTitle) ? null : customTitle,
DisableWatermarks = disableWatermarks,
PlayoutItemWatermarks = []
PlayoutItemWatermarks = [],
PlayoutItemGraphicsElements = []
};
foreach (int watermarkId in context.GetChannelWatermarkIds())
@ -137,6 +138,16 @@ public class YamlPlayoutDurationHandler(EnumeratorCache enumeratorCache) : YamlP @@ -137,6 +138,16 @@ public class YamlPlayoutDurationHandler(EnumeratorCache enumeratorCache) : YamlP
});
}
foreach (int graphicsElementId in context.GetGraphicsElementIds())
{
playoutItem.PlayoutItemGraphicsElements.Add(
new PlayoutItemGraphicsElement
{
PlayoutItem = playoutItem,
GraphicsElementId = graphicsElementId
});
}
if (remainingToFill - itemDuration >= TimeSpan.Zero || !stopBeforeEnd)
{
context.AddedItems.Add(playoutItem);

64
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutGraphicsOffHandler.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Scheduling.YamlScheduling.Models;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Handlers;
public class YamlPlayoutGraphicsOffHandler(IGraphicsElementRepository graphicsElementRepository) : IYamlPlayoutHandler
{
private readonly Dictionary<string, Option<GraphicsElement>> _graphicsElementCache = new();
public bool Reset => false;
public async Task<bool> Handle(
YamlPlayoutContext context,
YamlPlayoutInstruction instruction,
PlayoutBuildMode mode,
Func<string, Task> executeSequence,
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlPlayoutGraphicsOffInstruction graphicsOff)
{
return false;
}
if (string.IsNullOrWhiteSpace(graphicsOff.GraphicsOff))
{
context.ClearGraphicsElements();
}
else
{
foreach (var ge in await GetGraphicsElementByPath(graphicsOff.GraphicsOff))
{
context.RemoveGraphicsElementId(ge.Id);
}
}
return true;
}
private async Task<Option<GraphicsElement>> GetGraphicsElementByPath(string path)
{
if (_graphicsElementCache.TryGetValue(path, out var cachedGraphicsElement))
{
foreach (GraphicsElement graphicsElement in cachedGraphicsElement)
{
return graphicsElement;
}
}
else
{
Option<GraphicsElement> maybeGraphicsElement =
await graphicsElementRepository.GetGraphicsElementByPath(path);
_graphicsElementCache.Add(path, maybeGraphicsElement);
foreach (GraphicsElement graphicsElement in maybeGraphicsElement)
{
return graphicsElement;
}
}
return Option<GraphicsElement>.None;
}
}

62
ErsatzTV.Core/Scheduling/YamlScheduling/Handlers/YamlPlayoutGraphicsOnHandler.cs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Scheduling.YamlScheduling.Models;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Handlers;
public class YamlPlayoutGraphicsOnHandler(IGraphicsElementRepository graphicsElementRepository) : IYamlPlayoutHandler
{
private readonly Dictionary<string, Option<GraphicsElement>> _graphicsElementCache = new();
public bool Reset => false;
public async Task<bool> Handle(
YamlPlayoutContext context,
YamlPlayoutInstruction instruction,
PlayoutBuildMode mode,
Func<string, Task> executeSequence,
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlPlayoutGraphicsOnInstruction graphicsOn)
{
return false;
}
if (string.IsNullOrWhiteSpace(graphicsOn.GraphicsOn))
{
return false;
}
foreach (var ge in await GetGraphicsElementByPath(graphicsOn.GraphicsOn))
{
context.SetGraphicsElementId(ge.Id);
}
return true;
}
private async Task<Option<GraphicsElement>> GetGraphicsElementByPath(string path)
{
if (_graphicsElementCache.TryGetValue(path, out var cachedGraphicsElement))
{
foreach (GraphicsElement graphicsElement in cachedGraphicsElement)
{
return graphicsElement;
}
}
else
{
Option<GraphicsElement> maybeGraphicsElement =
await graphicsElementRepository.GetGraphicsElementByPath(path);
_graphicsElementCache.Add(path, maybeGraphicsElement);
foreach (GraphicsElement graphicsElement in maybeGraphicsElement)
{
return graphicsElement;
}
}
return Option<GraphicsElement>.None;
}
}

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

@ -15,7 +15,7 @@ public class YamlPlayoutMidRollHandler : IYamlPlayoutHandler @@ -15,7 +15,7 @@ public class YamlPlayoutMidRollHandler : IYamlPlayoutHandler
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlMidRollInstruction midRoll)
if (instruction is not YamlPlayoutMidRollInstruction midRoll)
{
return Task.FromResult(false);
}

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

@ -15,7 +15,7 @@ public class YamlPlayoutPostRollHandler : IYamlPlayoutHandler @@ -15,7 +15,7 @@ public class YamlPlayoutPostRollHandler : IYamlPlayoutHandler
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlPostRollInstruction postRoll)
if (instruction is not YamlPlayoutPostRollInstruction postRoll)
{
return Task.FromResult(false);
}

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

@ -15,7 +15,7 @@ public class YamlPlayoutPreRollHandler : IYamlPlayoutHandler @@ -15,7 +15,7 @@ public class YamlPlayoutPreRollHandler : IYamlPlayoutHandler
ILogger<YamlPlayoutBuilder> logger,
CancellationToken cancellationToken)
{
if (instruction is not YamlPreRollInstruction preRoll)
if (instruction is not YamlPlayoutPreRollInstruction preRoll)
{
return Task.FromResult(false);
}

9
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutGraphicsOffInstruction.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlPlayoutGraphicsOffInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "graphics_off", ApplyNamingConventions = false)]
public string GraphicsOff { get; set; }
}

9
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutGraphicsOnInstruction.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlPlayoutGraphicsOnInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "graphics_on", ApplyNamingConventions = false)]
public string GraphicsOn { get; set; }
}

2
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlMidRollInstruction.cs → ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutMidRollInstruction.cs

@ -2,7 +2,7 @@ using YamlDotNet.Serialization; @@ -2,7 +2,7 @@ using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlMidRollInstruction : YamlPlayoutInstruction
public class YamlPlayoutMidRollInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "mid_roll", ApplyNamingConventions = false)]
public bool MidRoll { get; set; }

2
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPostRollInstruction.cs → ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPostRollInstruction.cs

@ -2,7 +2,7 @@ using YamlDotNet.Serialization; @@ -2,7 +2,7 @@ using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlPostRollInstruction : YamlPlayoutInstruction
public class YamlPlayoutPostRollInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "post_roll", ApplyNamingConventions = false)]
public bool PostRoll { get; set; }

2
ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPreRollInstruction.cs → ErsatzTV.Core/Scheduling/YamlScheduling/Models/YamlPlayoutPreRollInstruction.cs

@ -2,7 +2,7 @@ using YamlDotNet.Serialization; @@ -2,7 +2,7 @@ using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.YamlScheduling.Models;
public class YamlPreRollInstruction : YamlPlayoutInstruction
public class YamlPlayoutPreRollInstruction : YamlPlayoutInstruction
{
[YamlMember(Alias = "pre_roll", ApplyNamingConventions = false)]
public bool PreRoll { get; set; }

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

@ -19,6 +19,7 @@ public class YamlPlayoutBuilder( @@ -19,6 +19,7 @@ public class YamlPlayoutBuilder(
IConfigElementRepository configElementRepository,
IMediaCollectionRepository mediaCollectionRepository,
IChannelRepository channelRepository,
IGraphicsElementRepository graphicsElementRepository,
IYamlScheduleValidator yamlScheduleValidator,
ILogger<YamlPlayoutBuilder> logger)
: IYamlPlayoutBuilder
@ -395,9 +396,11 @@ public class YamlPlayoutBuilder( @@ -395,9 +396,11 @@ public class YamlPlayoutBuilder(
YamlPlayoutEpgGroupInstruction => new YamlPlayoutEpgGroupHandler(),
YamlPlayoutWatermarkInstruction => new YamlPlayoutWatermarkHandler(channelRepository),
YamlPlayoutShuffleSequenceInstruction => new YamlPlayoutShuffleSequenceHandler(),
YamlPreRollInstruction => new YamlPlayoutPreRollHandler(),
YamlPostRollInstruction => new YamlPlayoutPostRollHandler(),
YamlMidRollInstruction => new YamlPlayoutMidRollHandler(),
YamlPlayoutPreRollInstruction => new YamlPlayoutPreRollHandler(),
YamlPlayoutPostRollInstruction => new YamlPlayoutPostRollHandler(),
YamlPlayoutMidRollInstruction => new YamlPlayoutMidRollHandler(),
YamlPlayoutGraphicsOnInstruction => new YamlPlayoutGraphicsOnHandler(graphicsElementRepository),
YamlPlayoutGraphicsOffInstruction => new YamlPlayoutGraphicsOffHandler(graphicsElementRepository),
YamlPlayoutSkipItemsInstruction => new YamlPlayoutSkipItemsHandler(enumeratorCache),
YamlPlayoutSkipToItemInstruction => new YamlPlayoutSkipToItemHandler(enumeratorCache),
@ -457,12 +460,14 @@ public class YamlPlayoutBuilder( @@ -457,12 +460,14 @@ public class YamlPlayoutBuilder(
{ "count", typeof(YamlPlayoutCountInstruction) },
{ "duration", typeof(YamlPlayoutDurationInstruction) },
{ "epg_group", typeof(YamlPlayoutEpgGroupInstruction) },
{ "graphics_on", typeof(YamlPlayoutGraphicsOnInstruction) },
{ "graphics_off", typeof(YamlPlayoutGraphicsOffInstruction) },
{ "watermark", typeof(YamlPlayoutWatermarkInstruction) },
{ "pad_to_next", typeof(YamlPlayoutPadToNextInstruction) },
{ "pad_until", typeof(YamlPlayoutPadUntilInstruction) },
{ "pre_roll", typeof(YamlPreRollInstruction) },
{ "post_roll", typeof(YamlPostRollInstruction) },
{ "mid_roll", typeof(YamlMidRollInstruction) },
{ "pre_roll", typeof(YamlPlayoutPreRollInstruction) },
{ "post_roll", typeof(YamlPlayoutPostRollInstruction) },
{ "mid_roll", typeof(YamlPlayoutMidRollInstruction) },
{ "repeat", typeof(YamlPlayoutRepeatInstruction) },
{ "rewind", typeof(YamlPlayoutRewindInstruction) },
{ "sequence", typeof(YamlPlayoutSequenceInstruction) },

65
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContext.cs

@ -16,6 +16,7 @@ public class YamlPlayoutContext(Playout playout, YamlPlayoutDefinition definitio @@ -16,6 +16,7 @@ public class YamlPlayoutContext(Playout playout, YamlPlayoutDefinition definitio
private readonly System.Collections.Generic.HashSet<int> _visitedInstructions = [];
private readonly Stack<FillerKind> _fillerKind = new();
private readonly System.Collections.Generic.HashSet<int> _channelWatermarkIds = [];
private readonly System.Collections.Generic.HashSet<int> _graphicsElementIds = [];
private int _guideGroup = guideGroup;
private bool _guideGroupLocked;
private int _instructionIndex;
@ -87,66 +88,30 @@ public class YamlPlayoutContext(Playout playout, YamlPlayoutDefinition definitio @@ -87,66 +88,30 @@ public class YamlPlayoutContext(Playout playout, YamlPlayoutDefinition definitio
public void UnlockGuideGroup() => _guideGroupLocked = false;
public void SetChannelWatermarkId(int id)
{
_channelWatermarkIds.Add(id);
}
public void RemoveChannelWatermarkId(int id)
{
_channelWatermarkIds.Remove(id);
}
public void ClearChannelWatermarkIds()
{
_channelWatermarkIds.Clear();
}
public void SetChannelWatermarkId(int id) => _channelWatermarkIds.Add(id);
public void RemoveChannelWatermarkId(int id) => _channelWatermarkIds.Remove(id);
public void ClearChannelWatermarkIds() => _channelWatermarkIds.Clear();
public List<int> GetChannelWatermarkIds() => _channelWatermarkIds.ToList();
public void SetPreRollSequence(string sequence)
{
_preRollSequence = sequence;
}
public void ClearPreRollSequence()
{
_preRollSequence = Option<string>.None;
}
public void SetGraphicsElementId(int id) => _graphicsElementIds.Add(id);
public void RemoveGraphicsElementId(int id) => _graphicsElementIds.Remove(id);
public void ClearGraphicsElements() => _graphicsElementIds.Clear();
public List<int> GetGraphicsElementIds() => _graphicsElementIds.ToList();
public void SetPreRollSequence(string sequence) => _preRollSequence = sequence;
public void ClearPreRollSequence() => _preRollSequence = Option<string>.None;
public Option<string> GetPreRollSequence() => _preRollSequence;
public void SetPostRollSequence(string sequence)
{
_postRollSequence = sequence;
}
public void ClearPostRollSequence()
{
_postRollSequence = Option<string>.None;
}
public void SetPostRollSequence(string sequence) => _postRollSequence = sequence;
public void ClearPostRollSequence() => _postRollSequence = Option<string>.None;
public Option<string> GetPostRollSequence() => _postRollSequence;
public void SetMidRollSequence(MidRollSequence sequence)
{
_midRollSequence = sequence;
}
public void ClearMidRollSequence()
{
_midRollSequence = Option<MidRollSequence>.None;
}
public void SetMidRollSequence(MidRollSequence sequence) => _midRollSequence = sequence;
public void ClearMidRollSequence() => _midRollSequence = Option<MidRollSequence>.None;
public Option<MidRollSequence> GetMidRollSequence() => _midRollSequence;
public void PushFillerKind(FillerKind fillerKind)
{
_fillerKind.Push(fillerKind);
}
public void PushFillerKind(FillerKind fillerKind) => _fillerKind.Push(fillerKind);
public void PopFillerKind() => _fillerKind.Pop();
public Option<FillerKind> GetFillerKind() =>
_fillerKind.TryPeek(out FillerKind fillerKind) ? fillerKind : Option<FillerKind>.None;

24
ErsatzTV.Infrastructure/Data/Repositories/GraphicsElementRepository.cs

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Infrastructure.Data.Repositories;
public class GraphicsElementRepository(IDbContextFactory<TvContext> dbContextFactory) : IGraphicsElementRepository
{
public async Task<Option<GraphicsElement>> GetGraphicsElementByPath(string path)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync();
if (!path.StartsWith(FileSystemLayout.GraphicsElementsTemplatesFolder, StringComparison.Ordinal))
{
path = Path.Combine(FileSystemLayout.GraphicsElementsTemplatesFolder, path);
}
return await dbContext.GraphicsElements
.AsNoTracking()
.SelectOneAsync(ge => ge.Path, ge => ge.Path == path);
}
}

18
ErsatzTV/Resources/yaml-playout-import.schema.json

@ -39,6 +39,8 @@ @@ -39,6 +39,8 @@
{ "$ref": "#/$defs/scheduling/padUntilInstruction" },
{ "$ref": "#/$defs/scheduling/sequenceInstruction" },
{ "$ref": "#/$defs/control/epgGroupInstruction" },
{ "$ref": "#/$defs/control/graphicsOnInstruction" },
{ "$ref": "#/$defs/control/graphicsOffInstruction" },
{ "$ref": "#/$defs/control/preRollInstruction"},
{ "$ref": "#/$defs/control/postRollInstruction"},
{ "$ref": "#/$defs/control/midRollInstruction"},
@ -276,6 +278,22 @@ @@ -276,6 +278,22 @@
"required": [ "epg_group" ],
"additionalProperties": false
},
"graphicsOnInstruction": {
"type": "object",
"properties": {
"graphics_on": { "type": "string" }
},
"required": [ "graphics_on" ],
"additionalProperties": false
},
"graphicsOffInstruction": {
"type": "object",
"properties": {
"graphics_off": { "type": ["null", "string"] }
},
"required": [ "graphics_off" ],
"additionalProperties": false
},
"preRollInstruction": {
"type": "object",
"properties": {

20
ErsatzTV/Resources/yaml-playout.schema.json

@ -46,6 +46,8 @@ @@ -46,6 +46,8 @@
{ "$ref": "#/$defs/scheduling/padUntilInstruction" },
{ "$ref": "#/$defs/scheduling/sequenceInstruction" },
{ "$ref": "#/$defs/control/epgGroupInstruction" },
{ "$ref": "#/$defs/control/graphicsOnInstruction" },
{ "$ref": "#/$defs/control/graphicsOffInstruction" },
{ "$ref": "#/$defs/control/preRollInstruction"},
{ "$ref": "#/$defs/control/postRollInstruction"},
{ "$ref": "#/$defs/control/midRollInstruction"},
@ -88,6 +90,8 @@ @@ -88,6 +90,8 @@
{ "$ref": "#/$defs/scheduling/padUntilInstruction" },
{ "$ref": "#/$defs/scheduling/sequenceInstruction" },
{ "$ref": "#/$defs/control/epgGroupInstruction" },
{ "$ref": "#/$defs/control/graphicsOnInstruction" },
{ "$ref": "#/$defs/control/graphicsOffInstruction" },
{ "$ref": "#/$defs/control/preRollInstruction"},
{ "$ref": "#/$defs/control/postRollInstruction"},
{ "$ref": "#/$defs/control/midRollInstruction"},
@ -325,6 +329,22 @@ @@ -325,6 +329,22 @@
"required": [ "epg_group" ],
"additionalProperties": false
},
"graphicsOnInstruction": {
"type": "object",
"properties": {
"graphics_on": { "type": "string" }
},
"required": [ "graphics_on" ],
"additionalProperties": false
},
"graphicsOffInstruction": {
"type": "object",
"properties": {
"graphics_off": { "type": ["null", "string"] }
},
"required": [ "graphics_off" ],
"additionalProperties": false
},
"preRollInstruction": {
"type": "object",
"properties": {

1
ErsatzTV/Startup.cs

@ -719,6 +719,7 @@ public class Startup @@ -719,6 +719,7 @@ public class Startup
MultiEpisodeShuffleCollectionEnumeratorFactory>();
services.AddScoped<IChannelLogoGenerator, ChannelLogoGenerator>();
services.AddScoped<IGraphicsEngine, GraphicsEngine>();
services.AddScoped<IGraphicsElementRepository, GraphicsElementRepository>();
services.AddScoped<IFFmpegProcessService, FFmpegLibraryProcessService>();
services.AddScoped<IPipelineBuilderFactory, PipelineBuilderFactory>();

Loading…
Cancel
Save