Browse Source

template playout => yaml playout (#1813)

pull/1814/head
Jason Dove 1 year ago committed by GitHub
parent
commit
fa20c5e01e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 10
      ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs
  3. 4
      ErsatzTV.Application/Playouts/Commands/CreatePlayout.cs
  4. 28
      ErsatzTV.Application/Playouts/Commands/CreateYamlPlayoutHandler.cs
  5. 10
      ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs
  6. 2
      ErsatzTV.Application/Playouts/Commands/UpdateYamlPlayout.cs
  7. 2
      ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs
  8. 2
      ErsatzTV.Core/Interfaces/Scheduling/IYamlPlayoutBuilder.cs
  9. 7
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs
  10. 7
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs
  11. 7
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs
  12. 7
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs
  13. 7
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs
  14. 6
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs
  15. 6
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs
  16. 5
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs
  17. 6
      ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs
  18. 76
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs
  19. 7
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs
  20. 7
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs
  21. 7
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs
  22. 7
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs
  23. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs
  24. 7
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs
  25. 4
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDurationInstruction.cs
  26. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs
  27. 4
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutPadToNextInstruction.cs
  28. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs
  29. 4
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutScheduler.cs
  30. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerCount.cs
  31. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerDuration.cs
  32. 6
      ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerPadToNext.cs
  33. 8
      ErsatzTV/Pages/PlayoutEditor.razor
  34. 26
      ErsatzTV/Pages/Playouts.razor
  35. 2
      ErsatzTV/PlayoutKind.cs
  36. 14
      ErsatzTV/Shared/EditYamlFileDialog.razor
  37. 4
      ErsatzTV/Startup.cs
  38. 4
      ErsatzTV/ViewModels/PlayoutEditViewModel.cs

5
CHANGELOG.md

@ -22,13 +22,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Default filler will stop scheduling when the next item would extend into primary content - Default filler will stop scheduling when the next item would extend into primary content
- Alternatively, default filler can be configured to `Trim To Fit` - Alternatively, default filler can be configured to `Trim To Fit`
- In this case, the last item that would extend into primary content is trimmed to end exactly when the primary content starts - In this case, the last item that would extend into primary content is trimmed to end exactly when the primary content starts
- Add **experimental** playout type `Template` - Add **experimental** playout type `YAML`
- This playout type uses a YAML file to declare content and describe how the playout should be built - This playout type uses a YAML file to declare content and describe how the playout should be built
- Content currently supports search queries - Content currently supports search queries
- Playout instructions currently include `count`, `pad to next`, and `repeat` - Playout instructions currently include `count`, `pad to next`, and `repeat`
- `count`: add the specified number of items (from the referenced content) to the playout - `count`: add the specified number of items (from the referenced content) to the playout
- `duration`: play the referenced content for the specified duration
- `pad to next`: add items from the referenced content until the wall clock is a multiple of the specified minutes value - `pad to next`: add items from the referenced content until the wall clock is a multiple of the specified minutes value
- `repeat`: continue building the playout from the first instruction in the template - `repeat`: continue building the playout from the first instruction in the YAML file
### Fixed ### Fixed
- Add basic cache busting to XMLTV image URLs - Add basic cache busting to XMLTV image URLs

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

@ -19,7 +19,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
{ {
private readonly IBlockPlayoutBuilder _blockPlayoutBuilder; private readonly IBlockPlayoutBuilder _blockPlayoutBuilder;
private readonly IBlockPlayoutFillerBuilder _blockPlayoutFillerBuilder; private readonly IBlockPlayoutFillerBuilder _blockPlayoutFillerBuilder;
private readonly ITemplatePlayoutBuilder _templatePlayoutBuilder; private readonly IYamlPlayoutBuilder _yamlPlayoutBuilder;
private readonly IClient _client; private readonly IClient _client;
private readonly IDbContextFactory<TvContext> _dbContextFactory; private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IEntityLocker _entityLocker; private readonly IEntityLocker _entityLocker;
@ -34,7 +34,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
IPlayoutBuilder playoutBuilder, IPlayoutBuilder playoutBuilder,
IBlockPlayoutBuilder blockPlayoutBuilder, IBlockPlayoutBuilder blockPlayoutBuilder,
IBlockPlayoutFillerBuilder blockPlayoutFillerBuilder, IBlockPlayoutFillerBuilder blockPlayoutFillerBuilder,
ITemplatePlayoutBuilder templatePlayoutBuilder, IYamlPlayoutBuilder yamlPlayoutBuilder,
IExternalJsonPlayoutBuilder externalJsonPlayoutBuilder, IExternalJsonPlayoutBuilder externalJsonPlayoutBuilder,
IFFmpegSegmenterService ffmpegSegmenterService, IFFmpegSegmenterService ffmpegSegmenterService,
IEntityLocker entityLocker, IEntityLocker entityLocker,
@ -45,7 +45,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
_playoutBuilder = playoutBuilder; _playoutBuilder = playoutBuilder;
_blockPlayoutBuilder = blockPlayoutBuilder; _blockPlayoutBuilder = blockPlayoutBuilder;
_blockPlayoutFillerBuilder = blockPlayoutFillerBuilder; _blockPlayoutFillerBuilder = blockPlayoutFillerBuilder;
_templatePlayoutBuilder = templatePlayoutBuilder; _yamlPlayoutBuilder = yamlPlayoutBuilder;
_externalJsonPlayoutBuilder = externalJsonPlayoutBuilder; _externalJsonPlayoutBuilder = externalJsonPlayoutBuilder;
_ffmpegSegmenterService = ffmpegSegmenterService; _ffmpegSegmenterService = ffmpegSegmenterService;
_entityLocker = entityLocker; _entityLocker = entityLocker;
@ -77,8 +77,8 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
await _blockPlayoutBuilder.Build(playout, request.Mode, cancellationToken); await _blockPlayoutBuilder.Build(playout, request.Mode, cancellationToken);
await _blockPlayoutFillerBuilder.Build(playout, request.Mode, cancellationToken); await _blockPlayoutFillerBuilder.Build(playout, request.Mode, cancellationToken);
break; break;
case ProgramSchedulePlayoutType.Template: case ProgramSchedulePlayoutType.Yaml:
await _templatePlayoutBuilder.Build(playout, request.Mode, cancellationToken); await _yamlPlayoutBuilder.Build(playout, request.Mode, cancellationToken);
break; break;
case ProgramSchedulePlayoutType.ExternalJson: case ProgramSchedulePlayoutType.ExternalJson:
await _externalJsonPlayoutBuilder.Build(playout, request.Mode, cancellationToken); await _externalJsonPlayoutBuilder.Build(playout, request.Mode, cancellationToken);

4
ErsatzTV.Application/Playouts/Commands/CreatePlayout.cs

@ -12,8 +12,8 @@ public record CreateFloodPlayout(int ChannelId, int ProgramScheduleId)
public record CreateBlockPlayout(int ChannelId) public record CreateBlockPlayout(int ChannelId)
: CreatePlayout(ChannelId, ProgramSchedulePlayoutType.Block); : CreatePlayout(ChannelId, ProgramSchedulePlayoutType.Block);
public record CreateTemplatePlayout(int ChannelId, string TemplateFile) public record CreateYamlPlayout(int ChannelId, string TemplateFile)
: CreatePlayout(ChannelId, ProgramSchedulePlayoutType.Template); : CreatePlayout(ChannelId, ProgramSchedulePlayoutType.Yaml);
public record CreateExternalJsonPlayout(int ChannelId, string ExternalJsonFile) public record CreateExternalJsonPlayout(int ChannelId, string ExternalJsonFile)
: CreatePlayout(ChannelId, ProgramSchedulePlayoutType.ExternalJson); : CreatePlayout(ChannelId, ProgramSchedulePlayoutType.ExternalJson);

28
ErsatzTV.Application/Playouts/Commands/CreateTemplatePlayoutHandler.cs → ErsatzTV.Application/Playouts/Commands/CreateYamlPlayoutHandler.cs

@ -11,14 +11,14 @@ using Channel = ErsatzTV.Core.Domain.Channel;
namespace ErsatzTV.Application.Playouts; namespace ErsatzTV.Application.Playouts;
public class CreateTemplatePlayoutHandler public class CreateYamlPlayoutHandler
: IRequestHandler<CreateTemplatePlayout, Either<BaseError, CreatePlayoutResponse>> : IRequestHandler<CreateYamlPlayout, Either<BaseError, CreatePlayoutResponse>>
{ {
private readonly ChannelWriter<IBackgroundServiceRequest> _channel; private readonly ChannelWriter<IBackgroundServiceRequest> _channel;
private readonly IDbContextFactory<TvContext> _dbContextFactory; private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ILocalFileSystem _localFileSystem; private readonly ILocalFileSystem _localFileSystem;
public CreateTemplatePlayoutHandler( public CreateYamlPlayoutHandler(
ILocalFileSystem localFileSystem, ILocalFileSystem localFileSystem,
ChannelWriter<IBackgroundServiceRequest> channel, ChannelWriter<IBackgroundServiceRequest> channel,
IDbContextFactory<TvContext> dbContextFactory) IDbContextFactory<TvContext> dbContextFactory)
@ -29,7 +29,7 @@ public class CreateTemplatePlayoutHandler
} }
public async Task<Either<BaseError, CreatePlayoutResponse>> Handle( public async Task<Either<BaseError, CreatePlayoutResponse>> Handle(
CreateTemplatePlayout request, CreateYamlPlayout request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
@ -48,8 +48,8 @@ public class CreateTemplatePlayoutHandler
private async Task<Validation<BaseError, Playout>> Validate( private async Task<Validation<BaseError, Playout>> Validate(
TvContext dbContext, TvContext dbContext,
CreateTemplatePlayout request) => CreateYamlPlayout request) =>
(await ValidateChannel(dbContext, request), ValidateTemplateFile(request), ValidatePlayoutType(request)) (await ValidateChannel(dbContext, request), ValidateYamlFile(request), ValidatePlayoutType(request))
.Apply( .Apply(
(channel, externalJsonFile, playoutType) => new Playout (channel, externalJsonFile, playoutType) => new Playout
{ {
@ -60,10 +60,10 @@ public class CreateTemplatePlayoutHandler
private static Task<Validation<BaseError, Channel>> ValidateChannel( private static Task<Validation<BaseError, Channel>> ValidateChannel(
TvContext dbContext, TvContext dbContext,
CreateTemplatePlayout createTemplatePlayout) => CreateYamlPlayout createYamlPlayout) =>
dbContext.Channels dbContext.Channels
.Include(c => c.Playouts) .Include(c => c.Playouts)
.SelectOneAsync(c => c.Id, c => c.Id == createTemplatePlayout.ChannelId) .SelectOneAsync(c => c.Id, c => c.Id == createYamlPlayout.ChannelId)
.Map(o => o.ToValidation<BaseError>("Channel does not exist")) .Map(o => o.ToValidation<BaseError>("Channel does not exist"))
.BindT(ChannelMustNotHavePlayouts); .BindT(ChannelMustNotHavePlayouts);
@ -73,19 +73,19 @@ public class CreateTemplatePlayoutHandler
.Map(_ => channel) .Map(_ => channel)
.ToValidation<BaseError>("Channel already has one playout"); .ToValidation<BaseError>("Channel already has one playout");
private Validation<BaseError, string> ValidateTemplateFile(CreateTemplatePlayout request) private Validation<BaseError, string> ValidateYamlFile(CreateYamlPlayout request)
{ {
if (!_localFileSystem.FileExists(request.TemplateFile)) if (!_localFileSystem.FileExists(request.TemplateFile))
{ {
return BaseError.New("Template file does not exist!"); return BaseError.New("YAML file does not exist!");
} }
return request.TemplateFile; return request.TemplateFile;
} }
private static Validation<BaseError, ProgramSchedulePlayoutType> ValidatePlayoutType( private static Validation<BaseError, ProgramSchedulePlayoutType> ValidatePlayoutType(
CreateTemplatePlayout createTemplatePlayout) => CreateYamlPlayout createYamlPlayout) =>
Optional(createTemplatePlayout.ProgramSchedulePlayoutType) Optional(createYamlPlayout.ProgramSchedulePlayoutType)
.Filter(playoutType => playoutType == ProgramSchedulePlayoutType.Template) .Filter(playoutType => playoutType == ProgramSchedulePlayoutType.Yaml)
.ToValidation<BaseError>("[ProgramSchedulePlayoutType] must be Template"); .ToValidation<BaseError>("[ProgramSchedulePlayoutType] must be YAML");
} }

10
ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayoutHandler.cs

@ -9,7 +9,7 @@ using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.Playouts; namespace ErsatzTV.Application.Playouts;
public class public class
UpdateTemplatePlayoutHandler : IRequestHandler<UpdateTemplatePlayout, UpdateTemplatePlayoutHandler : IRequestHandler<UpdateYamlPlayout,
Either<BaseError, PlayoutNameViewModel>> Either<BaseError, PlayoutNameViewModel>>
{ {
private readonly IDbContextFactory<TvContext> _dbContextFactory; private readonly IDbContextFactory<TvContext> _dbContextFactory;
@ -24,7 +24,7 @@ public class
} }
public async Task<Either<BaseError, PlayoutNameViewModel>> Handle( public async Task<Either<BaseError, PlayoutNameViewModel>> Handle(
UpdateTemplatePlayout request, UpdateYamlPlayout request,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
@ -34,7 +34,7 @@ public class
private async Task<PlayoutNameViewModel> ApplyUpdateRequest( private async Task<PlayoutNameViewModel> ApplyUpdateRequest(
TvContext dbContext, TvContext dbContext,
UpdateTemplatePlayout request, UpdateYamlPlayout request,
Playout playout) Playout playout)
{ {
playout.TemplateFile = request.TemplateFile; playout.TemplateFile = request.TemplateFile;
@ -58,12 +58,12 @@ public class
private static Task<Validation<BaseError, Playout>> Validate( private static Task<Validation<BaseError, Playout>> Validate(
TvContext dbContext, TvContext dbContext,
UpdateTemplatePlayout request) => UpdateYamlPlayout request) =>
PlayoutMustExist(dbContext, request); PlayoutMustExist(dbContext, request);
private static Task<Validation<BaseError, Playout>> PlayoutMustExist( private static Task<Validation<BaseError, Playout>> PlayoutMustExist(
TvContext dbContext, TvContext dbContext,
UpdateTemplatePlayout updatePlayout) => UpdateYamlPlayout updatePlayout) =>
dbContext.Playouts dbContext.Playouts
.Include(p => p.Channel) .Include(p => p.Channel)
.SelectOneAsync(p => p.Id, p => p.Id == updatePlayout.PlayoutId) .SelectOneAsync(p => p.Id, p => p.Id == updatePlayout.PlayoutId)

2
ErsatzTV.Application/Playouts/Commands/UpdateTemplatePlayout.cs → ErsatzTV.Application/Playouts/Commands/UpdateYamlPlayout.cs

@ -2,5 +2,5 @@
namespace ErsatzTV.Application.Playouts; namespace ErsatzTV.Application.Playouts;
public record UpdateTemplatePlayout(int PlayoutId, string TemplateFile) public record UpdateYamlPlayout(int PlayoutId, string TemplateFile)
: IRequest<Either<BaseError, PlayoutNameViewModel>>; : IRequest<Either<BaseError, PlayoutNameViewModel>>;

2
ErsatzTV.Core/Domain/ProgramSchedulePlayoutType.cs

@ -5,7 +5,7 @@ public enum ProgramSchedulePlayoutType
None = 0, None = 0,
Flood = 1, Flood = 1,
Block = 2, Block = 2,
Template = 3, Yaml = 3,
ExternalJson = 20 ExternalJson = 20
} }

2
ErsatzTV.Core/Interfaces/Scheduling/ITemplatePlayoutBuilder.cs → ErsatzTV.Core/Interfaces/Scheduling/IYamlPlayoutBuilder.cs

@ -3,7 +3,7 @@ using ErsatzTV.Core.Scheduling;
namespace ErsatzTV.Core.Interfaces.Scheduling; namespace ErsatzTV.Core.Interfaces.Scheduling;
public interface ITemplatePlayoutBuilder public interface IYamlPlayoutBuilder
{ {
Task<Playout> Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken); Task<Playout> Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken);
} }

7
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplate.cs

@ -1,7 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplate
{
public List<PlayoutTemplateContentItem> Content { get; set; } = [];
public List<PlayoutTemplateItem> Playout { get; set; } = [];
}

7
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentGuid.cs

@ -1,7 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateContentGuid
{
public string Source { get; set; }
public string Value { get; set; }
}

7
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentItem.cs

@ -1,7 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateContentItem
{
public string Key { get; set; }
public string Order { get; set; }
}

7
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentSearchItem.cs

@ -1,7 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateContentSearchItem : PlayoutTemplateContentItem
{
public string Search { get; set; }
public string Query { get; set; }
}

7
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateContentShowItem.cs

@ -1,7 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateContentShowItem : PlayoutTemplateContentItem
{
public string Show { get; set; }
public List<PlayoutTemplateContentGuid> Guids { get; set; } = [];
}

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateCountItem.cs

@ -1,6 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateCountItem : PlayoutTemplateItem
{
public int Count { get; set; }
}

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateItem.cs

@ -1,6 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateItem
{
public string Content { get; set; }
}

5
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePlayout.cs

@ -1,5 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplatePlayout
{
}

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateRepeatItem.cs

@ -1,6 +0,0 @@
namespace ErsatzTV.Core.Scheduling.TemplateScheduling;
public class PlayoutTemplateRepeatItem : PlayoutTemplateItem
{
public bool Repeat { get; set; }
}

76
ErsatzTV.Core/Scheduling/TemplateScheduling/TemplatePlayoutBuilder.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutBuilder.cs

@ -7,24 +7,24 @@ using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions; using YamlDotNet.Serialization.NamingConventions;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class TemplatePlayoutBuilder( public class YamlPlayoutBuilder(
ILocalFileSystem localFileSystem, ILocalFileSystem localFileSystem,
IConfigElementRepository configElementRepository, IConfigElementRepository configElementRepository,
IMediaCollectionRepository mediaCollectionRepository, IMediaCollectionRepository mediaCollectionRepository,
ILogger<TemplatePlayoutBuilder> logger) ILogger<YamlPlayoutBuilder> logger)
: ITemplatePlayoutBuilder : IYamlPlayoutBuilder
{ {
public async Task<Playout> Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken) public async Task<Playout> Build(Playout playout, PlayoutBuildMode mode, CancellationToken cancellationToken)
{ {
if (!localFileSystem.FileExists(playout.TemplateFile)) if (!localFileSystem.FileExists(playout.TemplateFile))
{ {
logger.LogWarning("Playout template file {File} does not exist; aborting.", playout.TemplateFile); logger.LogWarning("YAML playout file {File} does not exist; aborting.", playout.TemplateFile);
return playout; return playout;
} }
PlayoutTemplate playoutTemplate = await LoadTemplate(playout, cancellationToken); YamlPlayoutDefinition playoutDefinition = await LoadYamlDefinition(playout, cancellationToken);
DateTimeOffset start = DateTimeOffset.Now; DateTimeOffset start = DateTimeOffset.Now;
int daysToBuild = await GetDaysToBuild(); int daysToBuild = await GetDaysToBuild();
@ -32,7 +32,7 @@ public class TemplatePlayoutBuilder(
if (mode is not PlayoutBuildMode.Reset) if (mode is not PlayoutBuildMode.Reset)
{ {
logger.LogWarning("Template playouts can only be reset; ignoring build mode {Mode}", mode.ToString()); logger.LogWarning("YAML playouts can only be reset; ignoring build mode {Mode}", mode.ToString());
return playout; return playout;
} }
@ -50,16 +50,16 @@ public class TemplatePlayoutBuilder(
var index = 0; var index = 0;
while (currentTime < finish) while (currentTime < finish)
{ {
if (index >= playoutTemplate.Playout.Count) if (index >= playoutDefinition.Playout.Count)
{ {
logger.LogInformation("Reached the end of the playout template; stopping"); logger.LogInformation("Reached the end of the YAML playout definition; stopping");
break; break;
} }
PlayoutTemplateItem playoutItem = playoutTemplate.Playout[index]; YamlPlayoutInstruction playoutItem = playoutDefinition.Playout[index];
// repeat resets index into template playout // repeat resets index into YAML playout
if (playoutItem is PlayoutTemplateRepeatItem) if (playoutItem is YamlPlayoutRepeatInstruction)
{ {
index = 0; index = 0;
if (playout.Items.Count == itemsAfterRepeat) if (playout.Items.Count == itemsAfterRepeat)
@ -74,7 +74,7 @@ public class TemplatePlayoutBuilder(
Option<IMediaCollectionEnumerator> maybeEnumerator = await GetCachedEnumeratorForContent( Option<IMediaCollectionEnumerator> maybeEnumerator = await GetCachedEnumeratorForContent(
playout, playout,
playoutTemplate, playoutDefinition,
enumerators, enumerators,
playoutItem.Content, playoutItem.Content,
cancellationToken); cancellationToken);
@ -92,31 +92,31 @@ public class TemplatePlayoutBuilder(
{ {
switch (playoutItem) switch (playoutItem)
{ {
case PlayoutTemplateCountItem count: case YamlPlayoutCountInstruction count:
currentTime = PlayoutTemplateSchedulerCount.Schedule(playout, currentTime, count, enumerator); currentTime = YamlPlayoutSchedulerCount.Schedule(playout, currentTime, count, enumerator);
break; break;
case PlayoutTemplateDurationItem duration: case YamlPlayoutDurationInstruction duration:
Option<IMediaCollectionEnumerator> durationFallbackEnumerator = await GetCachedEnumeratorForContent( Option<IMediaCollectionEnumerator> durationFallbackEnumerator = await GetCachedEnumeratorForContent(
playout, playout,
playoutTemplate, playoutDefinition,
enumerators, enumerators,
duration.Fallback, duration.Fallback,
cancellationToken); cancellationToken);
currentTime = PlayoutTemplateSchedulerDuration.Schedule( currentTime = YamlPlayoutSchedulerDuration.Schedule(
playout, playout,
currentTime, currentTime,
duration, duration,
enumerator, enumerator,
durationFallbackEnumerator); durationFallbackEnumerator);
break; break;
case PlayoutTemplatePadToNextItem padToNext: case YamlPlayoutPadToNextInstruction padToNext:
Option<IMediaCollectionEnumerator> fallbackEnumerator = await GetCachedEnumeratorForContent( Option<IMediaCollectionEnumerator> fallbackEnumerator = await GetCachedEnumeratorForContent(
playout, playout,
playoutTemplate, playoutDefinition,
enumerators, enumerators,
padToNext.Fallback, padToNext.Fallback,
cancellationToken); cancellationToken);
currentTime = PlayoutTemplateSchedulerPadToNext.Schedule( currentTime = YamlPlayoutSchedulerPadToNext.Schedule(
playout, playout,
currentTime, currentTime,
padToNext, padToNext,
@ -139,7 +139,7 @@ public class TemplatePlayoutBuilder(
private async Task<Option<IMediaCollectionEnumerator>> GetCachedEnumeratorForContent( private async Task<Option<IMediaCollectionEnumerator>> GetCachedEnumeratorForContent(
Playout playout, Playout playout,
PlayoutTemplate playoutTemplate, YamlPlayoutDefinition playoutDefinition,
Dictionary<string, IMediaCollectionEnumerator> enumerators, Dictionary<string, IMediaCollectionEnumerator> enumerators,
string contentKey, string contentKey,
CancellationToken cancellationToken) CancellationToken cancellationToken)
@ -152,7 +152,7 @@ public class TemplatePlayoutBuilder(
if (!enumerators.TryGetValue(contentKey, out IMediaCollectionEnumerator enumerator)) if (!enumerators.TryGetValue(contentKey, out IMediaCollectionEnumerator enumerator))
{ {
Option<IMediaCollectionEnumerator> maybeEnumerator = Option<IMediaCollectionEnumerator> maybeEnumerator =
await GetEnumeratorForContent(playout, contentKey, playoutTemplate, cancellationToken); await GetEnumeratorForContent(playout, contentKey, playoutDefinition, cancellationToken);
if (maybeEnumerator.IsNone) if (maybeEnumerator.IsNone)
{ {
@ -172,10 +172,10 @@ public class TemplatePlayoutBuilder(
private async Task<Option<IMediaCollectionEnumerator>> GetEnumeratorForContent( private async Task<Option<IMediaCollectionEnumerator>> GetEnumeratorForContent(
Playout playout, Playout playout,
string contentKey, string contentKey,
PlayoutTemplate playoutTemplate, YamlPlayoutDefinition playoutDefinition,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
int index = playoutTemplate.Content.FindIndex(c => c.Key == contentKey); int index = playoutDefinition.Content.FindIndex(c => c.Key == contentKey);
if (index < 0) if (index < 0)
{ {
return Option<IMediaCollectionEnumerator>.None; return Option<IMediaCollectionEnumerator>.None;
@ -183,13 +183,13 @@ public class TemplatePlayoutBuilder(
List<MediaItem> items = []; List<MediaItem> items = [];
PlayoutTemplateContentItem content = playoutTemplate.Content[index]; YamlPlayoutContentItem content = playoutDefinition.Content[index];
switch (content) switch (content)
{ {
case PlayoutTemplateContentSearchItem search: case YamlPlayoutContentSearchItem search:
items = await mediaCollectionRepository.GetSmartCollectionItems(search.Query); items = await mediaCollectionRepository.GetSmartCollectionItems(search.Query);
break; break;
case PlayoutTemplateContentShowItem show: case YamlPlayoutContentShowItem show:
items = await mediaCollectionRepository.GetShowItemsByShowGuids( items = await mediaCollectionRepository.GetShowItemsByShowGuids(
show.Guids.Map(g => $"{g.Source}://{g.Value}").ToList()); show.Guids.Map(g => $"{g.Source}://{g.Value}").ToList());
break; break;
@ -209,7 +209,7 @@ public class TemplatePlayoutBuilder(
return Option<IMediaCollectionEnumerator>.None; return Option<IMediaCollectionEnumerator>.None;
} }
private static async Task<PlayoutTemplate> LoadTemplate(Playout playout, CancellationToken cancellationToken) private static async Task<YamlPlayoutDefinition> LoadYamlDefinition(Playout playout, CancellationToken cancellationToken)
{ {
string yaml = await File.ReadAllTextAsync(playout.TemplateFile, cancellationToken); string yaml = await File.ReadAllTextAsync(playout.TemplateFile, cancellationToken);
@ -220,24 +220,24 @@ public class TemplatePlayoutBuilder(
{ {
var contentKeyMappings = new Dictionary<string, Type> var contentKeyMappings = new Dictionary<string, Type>
{ {
{ "search", typeof(PlayoutTemplateContentSearchItem) }, { "search", typeof(YamlPlayoutContentSearchItem) },
{ "show", typeof(PlayoutTemplateContentShowItem) } { "show", typeof(YamlPlayoutContentShowItem) }
}; };
o.AddUniqueKeyTypeDiscriminator<PlayoutTemplateContentItem>(contentKeyMappings); o.AddUniqueKeyTypeDiscriminator<YamlPlayoutContentItem>(contentKeyMappings);
var instructionKeyMappings = new Dictionary<string, Type> var instructionKeyMappings = new Dictionary<string, Type>
{ {
{ "count", typeof(PlayoutTemplateCountItem) }, { "count", typeof(YamlPlayoutCountInstruction) },
{ "duration", typeof(PlayoutTemplateDurationItem) }, { "duration", typeof(YamlPlayoutDurationInstruction) },
{ "pad_to_next", typeof(PlayoutTemplatePadToNextItem) }, { "pad_to_next", typeof(YamlPlayoutPadToNextInstruction) },
{ "repeat", typeof(PlayoutTemplateRepeatItem) } { "repeat", typeof(YamlPlayoutRepeatInstruction) }
}; };
o.AddUniqueKeyTypeDiscriminator<PlayoutTemplateItem>(instructionKeyMappings); o.AddUniqueKeyTypeDiscriminator<YamlPlayoutInstruction>(instructionKeyMappings);
}) })
.Build(); .Build();
return deserializer.Deserialize<PlayoutTemplate>(yaml); return deserializer.Deserialize<YamlPlayoutDefinition>(yaml);
} }
} }

7
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentGuid.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutContentGuid
{
public string Source { get; set; }
public string Value { get; set; }
}

7
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentItem.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutContentItem
{
public string Key { get; set; }
public string Order { get; set; }
}

7
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentSearchItem.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutContentSearchItem : YamlPlayoutContentItem
{
public string Search { get; set; }
public string Query { get; set; }
}

7
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutContentShowItem.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutContentShowItem : YamlPlayoutContentItem
{
public string Show { get; set; }
public List<YamlPlayoutContentGuid> Guids { get; set; } = [];
}

6
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutCountInstruction.cs

@ -0,0 +1,6 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutCountInstruction : YamlPlayoutInstruction
{
public int Count { get; set; }
}

7
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDefinition.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutDefinition
{
public List<YamlPlayoutContentItem> Content { get; set; } = [];
public List<YamlPlayoutInstruction> Playout { get; set; } = [];
}

4
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateDurationItem.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutDurationInstruction.cs

@ -1,8 +1,8 @@
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class PlayoutTemplateDurationItem : PlayoutTemplateItem public class YamlPlayoutDurationInstruction : YamlPlayoutInstruction
{ {
public string Duration { get; set; } public string Duration { get; set; }

6
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutInstruction.cs

@ -0,0 +1,6 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutInstruction
{
public string Content { get; set; }
}

4
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplatePadToNextItem.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutPadToNextInstruction.cs

@ -1,8 +1,8 @@
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class PlayoutTemplatePadToNextItem : PlayoutTemplateItem public class YamlPlayoutPadToNextInstruction : YamlPlayoutInstruction
{ {
[YamlMember(Alias = "pad_to_next", ApplyNamingConventions = false)] [YamlMember(Alias = "pad_to_next", ApplyNamingConventions = false)]
public int PadToNext { get; set; } public int PadToNext { get; set; }

6
ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutRepeatInstruction.cs

@ -0,0 +1,6 @@
namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class YamlPlayoutRepeatInstruction : YamlPlayoutInstruction
{
public bool Repeat { get; set; }
}

4
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateScheduler.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutScheduler.cs

@ -1,9 +1,9 @@
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions; using ErsatzTV.Core.Extensions;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public abstract class PlayoutTemplateScheduler public abstract class YamlPlayoutScheduler
{ {
protected static TimeSpan DurationForMediaItem(MediaItem mediaItem) protected static TimeSpan DurationForMediaItem(MediaItem mediaItem)
{ {

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerCount.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerCount.cs

@ -2,14 +2,14 @@ using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Filler; using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Interfaces.Scheduling; using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class PlayoutTemplateSchedulerCount : PlayoutTemplateScheduler public class YamlPlayoutSchedulerCount : YamlPlayoutScheduler
{ {
public static DateTimeOffset Schedule( public static DateTimeOffset Schedule(
Playout playout, Playout playout,
DateTimeOffset currentTime, DateTimeOffset currentTime,
PlayoutTemplateCountItem count, YamlPlayoutCountInstruction count,
IMediaCollectionEnumerator enumerator) IMediaCollectionEnumerator enumerator)
{ {
for (int i = 0; i < count.Count; i++) for (int i = 0; i < count.Count; i++)

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerDuration.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerDuration.cs

@ -3,14 +3,14 @@ using ErsatzTV.Core.Domain.Filler;
using ErsatzTV.Core.Interfaces.Scheduling; using ErsatzTV.Core.Interfaces.Scheduling;
using TimeSpanParserUtil; using TimeSpanParserUtil;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class PlayoutTemplateSchedulerDuration : PlayoutTemplateScheduler public class YamlPlayoutSchedulerDuration : YamlPlayoutScheduler
{ {
public static DateTimeOffset Schedule( public static DateTimeOffset Schedule(
Playout playout, Playout playout,
DateTimeOffset currentTime, DateTimeOffset currentTime,
PlayoutTemplateDurationItem duration, YamlPlayoutDurationInstruction duration,
IMediaCollectionEnumerator enumerator, IMediaCollectionEnumerator enumerator,
Option<IMediaCollectionEnumerator> fallbackEnumerator) Option<IMediaCollectionEnumerator> fallbackEnumerator)
{ {

6
ErsatzTV.Core/Scheduling/TemplateScheduling/PlayoutTemplateSchedulerPadToNext.cs → ErsatzTV.Core/Scheduling/YamlScheduling/YamlPlayoutSchedulerPadToNext.cs

@ -1,14 +1,14 @@
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Scheduling; using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling.TemplateScheduling; namespace ErsatzTV.Core.Scheduling.YamlScheduling;
public class PlayoutTemplateSchedulerPadToNext : PlayoutTemplateSchedulerDuration public class YamlPlayoutSchedulerPadToNext : YamlPlayoutSchedulerDuration
{ {
public static DateTimeOffset Schedule( public static DateTimeOffset Schedule(
Playout playout, Playout playout,
DateTimeOffset currentTime, DateTimeOffset currentTime,
PlayoutTemplatePadToNextItem padToNext, YamlPlayoutPadToNextInstruction padToNext,
IMediaCollectionEnumerator enumerator, IMediaCollectionEnumerator enumerator,
Option<IMediaCollectionEnumerator> fallbackEnumerator) Option<IMediaCollectionEnumerator> fallbackEnumerator)
{ {

8
ErsatzTV/Pages/PlayoutEditor.razor

@ -15,8 +15,8 @@
case PlayoutKind.ExternalJson: case PlayoutKind.ExternalJson:
<span>Add External Json Playout</span> <span>Add External Json Playout</span>
break; break;
case PlayoutKind.Template: case PlayoutKind.Yaml:
<span>Add Template Playout</span> <span>Add YAML Playout</span>
break; break;
case PlayoutKind.Block: case PlayoutKind.Block:
<span>Add Block Playout</span> <span>Add Block Playout</span>
@ -47,8 +47,8 @@
case PlayoutKind.ExternalJson: case PlayoutKind.ExternalJson:
<MudTextField Label="External Json File" @bind-Value="_model.ExternalJsonFile" For="@(() => _model.ExternalJsonFile)"/> <MudTextField Label="External Json File" @bind-Value="_model.ExternalJsonFile" For="@(() => _model.ExternalJsonFile)"/>
break; break;
case PlayoutKind.Template: case PlayoutKind.Yaml:
<MudTextField Label="Template File" @bind-Value="_model.TemplateFile" For="@(() => _model.TemplateFile)"/> <MudTextField Label="YAML File" @bind-Value="_model.YamlFile" For="@(() => _model.YamlFile)"/>
break; break;
default: default:
<MudSelect Class="mt-3" <MudSelect Class="mt-3"

26
ErsatzTV/Pages/Playouts.razor

@ -19,8 +19,8 @@
</MudButton> </MudButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="This feature is experimental"> <MudTooltip Text="This feature is experimental">
<MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Warning" Href="@($"playouts/add/{PlayoutKind.Template}")"> <MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Warning" Href="@($"playouts/add/{PlayoutKind.Yaml}")">
Add Template Playout Add YAML Playout
</MudButton> </MudButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="This feature is experimental"> <MudTooltip Text="This feature is experimental">
@ -68,8 +68,8 @@
case ProgramSchedulePlayoutType.Block: case ProgramSchedulePlayoutType.Block:
<span>Block</span> <span>Block</span>
break; break;
case ProgramSchedulePlayoutType.Template: case ProgramSchedulePlayoutType.Yaml:
<span>Template</span> <span>YAML</span>
break; break;
case ProgramSchedulePlayoutType.ExternalJson: case ProgramSchedulePlayoutType.ExternalJson:
<span>External Json</span> <span>External Json</span>
@ -131,12 +131,12 @@
<div style="width: 48px"></div> <div style="width: 48px"></div>
<div style="width: 48px"></div> <div style="width: 48px"></div>
} }
else if (context.PlayoutType == ProgramSchedulePlayoutType.Template) else if (context.PlayoutType == ProgramSchedulePlayoutType.Yaml)
{ {
<MudTooltip Text="Edit Template File"> <MudTooltip Text="Edit YAML File">
<MudIconButton Icon="@Icons.Material.Filled.Edit" <MudIconButton Icon="@Icons.Material.Filled.Edit"
Disabled="@EntityLocker.IsPlayoutLocked(context.PlayoutId)" Disabled="@EntityLocker.IsPlayoutLocked(context.PlayoutId)"
OnClick="@(_ => EditTemplateFile(context))"> OnClick="@(_ => EditYamlFile(context))">
</MudIconButton> </MudIconButton>
</MudTooltip> </MudTooltip>
<MudTooltip Text="Reset Playout"> <MudTooltip Text="Reset Playout">
@ -256,8 +256,8 @@
private async Task PlayoutSelected(PlayoutNameViewModel playout) private async Task PlayoutSelected(PlayoutNameViewModel playout)
{ {
// only show details for flood, block and template playouts // only show details for flood, block and YAML playouts
_selectedPlayoutId = playout.PlayoutType is ProgramSchedulePlayoutType.Flood or ProgramSchedulePlayoutType.Block or ProgramSchedulePlayoutType.Template _selectedPlayoutId = playout.PlayoutType is ProgramSchedulePlayoutType.Flood or ProgramSchedulePlayoutType.Block or ProgramSchedulePlayoutType.Yaml
? playout.PlayoutId ? playout.PlayoutId
: null; : null;
@ -286,16 +286,16 @@
} }
} }
private async Task EditTemplateFile(PlayoutNameViewModel playout) private async Task EditYamlFile(PlayoutNameViewModel playout)
{ {
var parameters = new DialogParameters { { "TemplateFile", $"{playout.TemplateFile}" } }; var parameters = new DialogParameters { { "YamlFile", $"{playout.TemplateFile}" } };
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraLarge }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraLarge };
IDialogReference dialog = await Dialog.ShowAsync<EditTemplateFileDialog>("Edit Template File", parameters, options); IDialogReference dialog = await Dialog.ShowAsync<EditYamlFileDialog>("Edit YAML File", parameters, options);
DialogResult result = await dialog.Result; DialogResult result = await dialog.Result;
if (!result.Canceled) if (!result.Canceled)
{ {
await Mediator.Send(new UpdateTemplatePlayout(playout.PlayoutId, result.Data as string ?? playout.TemplateFile), _cts.Token); await Mediator.Send(new UpdateYamlPlayout(playout.PlayoutId, result.Data as string ?? playout.TemplateFile), _cts.Token);
if (_table != null) if (_table != null)
{ {
await _table.ReloadServerData(); await _table.ReloadServerData();

2
ErsatzTV/PlayoutKind.cs

@ -3,6 +3,6 @@ namespace ErsatzTV;
public static class PlayoutKind public static class PlayoutKind
{ {
public const string ExternalJson = "externaljson"; public const string ExternalJson = "externaljson";
public const string Template = "template"; public const string Yaml = "yaml";
public const string Block = "block"; public const string Block = "block";
} }

14
ErsatzTV/Shared/EditTemplateFileDialog.razor → ErsatzTV/Shared/EditYamlFileDialog.razor

@ -4,14 +4,14 @@
<DialogContent> <DialogContent>
<MudContainer Class="mb-6"> <MudContainer Class="mb-6">
<MudText> <MudText>
Edit the playout's template file Edit the playout's YAML file
</MudText> </MudText>
</MudContainer> </MudContainer>
<MudTextField Label="Template File" @bind-Value="_templateFile"/> <MudTextField Label="YAML File" @bind-Value="_yamlFile"/>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<MudButton OnClick="Cancel" ButtonType="ButtonType.Reset">Cancel</MudButton> <MudButton OnClick="Cancel" ButtonType="ButtonType.Reset">Cancel</MudButton>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Disabled="@(string.IsNullOrWhiteSpace(_templateFile))" OnClick="Submit"> <MudButton Color="Color.Primary" Variant="Variant.Filled" Disabled="@(string.IsNullOrWhiteSpace(_yamlFile))" OnClick="Submit">
Save Changes Save Changes
</MudButton> </MudButton>
</DialogActions> </DialogActions>
@ -21,12 +21,12 @@
private readonly CancellationTokenSource _cts = new(); private readonly CancellationTokenSource _cts = new();
[Parameter] [Parameter]
public string TemplateFile { get; set; } public string YamlFile { get; set; }
[CascadingParameter] [CascadingParameter]
MudDialogInstance MudDialog { get; set; } MudDialogInstance MudDialog { get; set; }
private string _templateFile; private string _yamlFile;
public void Dispose() public void Dispose()
{ {
@ -34,9 +34,9 @@
_cts.Dispose(); _cts.Dispose();
} }
protected override void OnParametersSet() => _templateFile = TemplateFile; protected override void OnParametersSet() => _yamlFile = YamlFile;
private void Submit() => MudDialog.Close(DialogResult.Ok(_templateFile)); private void Submit() => MudDialog.Close(DialogResult.Ok(_yamlFile));
private void Cancel() => MudDialog.Cancel(); private void Cancel() => MudDialog.Cancel();
} }

4
ErsatzTV/Startup.cs

@ -36,7 +36,7 @@ using ErsatzTV.Core.Metadata;
using ErsatzTV.Core.Plex; using ErsatzTV.Core.Plex;
using ErsatzTV.Core.Scheduling; using ErsatzTV.Core.Scheduling;
using ErsatzTV.Core.Scheduling.BlockScheduling; using ErsatzTV.Core.Scheduling.BlockScheduling;
using ErsatzTV.Core.Scheduling.TemplateScheduling; using ErsatzTV.Core.Scheduling.YamlScheduling;
using ErsatzTV.Core.Trakt; using ErsatzTV.Core.Trakt;
using ErsatzTV.FFmpeg.Capabilities; using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Pipeline; using ErsatzTV.FFmpeg.Pipeline;
@ -656,7 +656,7 @@ public class Startup
services.AddScoped<IBlockPlayoutBuilder, BlockPlayoutBuilder>(); services.AddScoped<IBlockPlayoutBuilder, BlockPlayoutBuilder>();
services.AddScoped<IBlockPlayoutPreviewBuilder, BlockPlayoutPreviewBuilder>(); services.AddScoped<IBlockPlayoutPreviewBuilder, BlockPlayoutPreviewBuilder>();
services.AddScoped<IBlockPlayoutFillerBuilder, BlockPlayoutFillerBuilder>(); services.AddScoped<IBlockPlayoutFillerBuilder, BlockPlayoutFillerBuilder>();
services.AddScoped<ITemplatePlayoutBuilder, TemplatePlayoutBuilder>(); services.AddScoped<IYamlPlayoutBuilder, YamlPlayoutBuilder>();
services.AddScoped<IExternalJsonPlayoutBuilder, ExternalJsonPlayoutBuilder>(); services.AddScoped<IExternalJsonPlayoutBuilder, ExternalJsonPlayoutBuilder>();
services.AddScoped<IPlayoutTimeShifter, PlayoutTimeShifter>(); services.AddScoped<IPlayoutTimeShifter, PlayoutTimeShifter>();
services.AddScoped<IImageCache, ImageCache>(); services.AddScoped<IImageCache, ImageCache>();

4
ErsatzTV/ViewModels/PlayoutEditViewModel.cs

@ -10,13 +10,13 @@ public class PlayoutEditViewModel
public ChannelViewModel Channel { get; set; } public ChannelViewModel Channel { get; set; }
public ProgramScheduleViewModel ProgramSchedule { get; set; } public ProgramScheduleViewModel ProgramSchedule { get; set; }
public string ExternalJsonFile { get; set; } public string ExternalJsonFile { get; set; }
public string TemplateFile { get; set; } public string YamlFile { get; set; }
public CreatePlayout ToCreate() => public CreatePlayout ToCreate() =>
Kind switch Kind switch
{ {
PlayoutKind.ExternalJson => new CreateExternalJsonPlayout(Channel.Id, ExternalJsonFile), PlayoutKind.ExternalJson => new CreateExternalJsonPlayout(Channel.Id, ExternalJsonFile),
PlayoutKind.Template => new CreateTemplatePlayout(Channel.Id, TemplateFile), PlayoutKind.Yaml => new CreateYamlPlayout(Channel.Id, YamlFile),
PlayoutKind.Block => new CreateBlockPlayout(Channel.Id), PlayoutKind.Block => new CreateBlockPlayout(Channel.Id),
_ => new CreateFloodPlayout(Channel.Id, ProgramSchedule.Id) _ => new CreateFloodPlayout(Channel.Id, ProgramSchedule.Id)
}; };

Loading…
Cancel
Save