@page "/playouts" @using System.Globalization @using ErsatzTV.Application.Configuration @using ErsatzTV.Application.Playouts @using ErsatzTV.Application.ProgramSchedules @using ErsatzTV.Core.Notifications @using ErsatzTV.Core.Scheduling @using MediatR.Courier @implements IDisposable @inject IDialogService Dialog @inject IMediator Mediator @inject ChannelWriter WorkerChannel @inject IEntityLocker EntityLocker; @inject ICourier Courier;
Add Playout Reset All Playouts
Playouts Channel Default Schedule Schedule Kind @context.ChannelNumber - @context.ChannelName @if (!string.IsNullOrWhiteSpace(context.ScheduleName)) { @context.ScheduleName } else if (!string.IsNullOrWhiteSpace(context.ScheduleFile)) { @Path.GetFileName(context.ScheduleFile) } @switch (context.ScheduleKind) { case PlayoutScheduleKind.Block: Block break; case PlayoutScheduleKind.Sequential: Sequential break; case PlayoutScheduleKind.Scripted: Scripted break; case PlayoutScheduleKind.ExternalJson: JSON (dizqueTV) break; default: break; }
@if (EntityLocker.IsPlayoutLocked(context.PlayoutId)) { }
@if (context.ScheduleKind == PlayoutScheduleKind.Classic) { } else if (context.ScheduleKind == PlayoutScheduleKind.ExternalJson) {
} else if (context.ScheduleKind == PlayoutScheduleKind.Sequential) {
} else if (context.ScheduleKind == PlayoutScheduleKind.Scripted) {
} else if (context.ScheduleKind == PlayoutScheduleKind.Block) {
}
@if (_selectedPlayoutId != null) { Playout Detail @if (!string.IsNullOrWhiteSpace(_buildMessage)) { @_buildMessage } else { Start Finish Media Item Duration @context.Start.ToString("G", _dtf) @context.Finish.ToString("G", _dtf) @context.Title @context.Duration @if (!string.IsNullOrWhiteSpace(context.SchedulingContext)) {
}
} }
@code { private CancellationTokenSource _cts; private readonly DateTimeFormatInfo _dtf = CultureInfo.CurrentCulture.DateTimeFormat; private readonly List _currentPage = []; private MudTable _table; private MudTable _detailTable; private int _rowsPerPage = 10; private int _detailRowsPerPage = 10; private string _searchString; private int? _selectedPlayoutId; private bool _showFiller; private string _buildMessage; private bool ShowFiller { get => _showFiller; set { if (_showFiller != value) { _showFiller = value; if (_detailTable != null && _selectedPlayoutId != null) { _detailTable.ReloadServerData(); } } } } protected override void OnInitialized() => Courier.Subscribe(HandlePlayoutUpdated); public void Dispose() { Courier.UnSubscribe(HandlePlayoutUpdated); _cts?.Cancel(); _cts?.Dispose(); } public async Task HandlePlayoutUpdated(PlayoutUpdatedNotification notification, CancellationToken cancellationToken) { // only refresh detail table on unlock operations (after playout has been modified) if (!notification.IsLocked) { int? previouslySelected = _selectedPlayoutId; await InvokeAsync(() => _table.ReloadServerData()); _buildMessage = string.Empty; _selectedPlayoutId = null; if (notification.PlayoutId == previouslySelected) { Option maybeItem = _currentPage.Find(i => i.PlayoutId == previouslySelected); foreach (var item in maybeItem) { await InvokeAsync(() => PlayoutSelected(item)); } } } await InvokeAsync(StateHasChanged); } protected override async Task OnParametersSetAsync() { _cts?.Cancel(); _cts?.Dispose(); _cts = new CancellationTokenSource(); var token = _cts.Token; try { _rowsPerPage = await Mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsPageSize), token) .Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10)); _detailRowsPerPage = await Mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize), token) .Map(maybeRows => maybeRows.Match(ce => int.TryParse(ce.Value, out int rows) ? rows : 10, () => 10)); _showFiller = await Mediator.Send(new GetConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller), token) .Map(maybeShow => maybeShow.Match(ce => bool.TryParse(ce.Value, out bool show) && show, () => false)); } catch (OperationCanceledException) { // do nothing } } private async Task PlayoutSelected(PlayoutNameViewModel playout) { // only show details for classic, block, sequential and scripted schedules _selectedPlayoutId = playout.ScheduleKind is PlayoutScheduleKind.Classic or PlayoutScheduleKind.Block or PlayoutScheduleKind.Sequential or PlayoutScheduleKind.Scripted ? playout.PlayoutId : null; _buildMessage = !(playout.BuildStatus?.Success ?? false) && !string.IsNullOrWhiteSpace(playout.BuildStatus?.Message) ? playout.BuildStatus.Message : string.Empty; if (_detailTable != null) { await _detailTable.ReloadServerData(); } } private async Task EditExternalJsonFile(PlayoutNameViewModel playout) { var parameters = new DialogParameters { { "ScheduleFile", $"{playout.ScheduleFile}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraLarge }; IDialogReference dialog = await Dialog.ShowAsync("Edit External Json File", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false }) { await Mediator.Send(new UpdateExternalJsonPlayout(playout.PlayoutId, result.Data as string ?? playout.ScheduleFile), _cts.Token); if (_table != null) { await _table.ReloadServerData(); } _selectedPlayoutId = null; } } private async Task DeletePlayout(PlayoutNameViewModel playout) { var parameters = new DialogParameters { { "EntityType", "playout" }, { "EntityName", $"{playout.ScheduleName} on {playout.ChannelNumber} - {playout.ChannelName}" } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Delete Playout", parameters, options); DialogResult result = await dialog.Result; if (result is { Canceled: false }) { await Mediator.Send(new DeletePlayout(playout.PlayoutId), _cts.Token); if (_table != null) { await _table.ReloadServerData(); } if (_selectedPlayoutId == playout.PlayoutId) { _selectedPlayoutId = null; } } } private async Task ResetAllPlayouts() { _selectedPlayoutId = null; await Mediator.Send(new ResetAllPlayouts(), _cts.Token); } private async Task ResetPlayout(PlayoutNameViewModel playout) { PlayoutBuildMode mode = playout.ScheduleKind switch { PlayoutScheduleKind.Classic => PlayoutBuildMode.Refresh, _ => PlayoutBuildMode.Reset }; await WorkerChannel.WriteAsync(new BuildPlayout(playout.PlayoutId, mode), _cts.Token); } private async Task ScheduleReset(PlayoutNameViewModel playout) { var parameters = new DialogParameters { { "PlayoutId", playout.PlayoutId }, { "ChannelName", playout.ChannelName }, { "ScheduleName", playout.ScheduleName }, { "DailyResetTime", playout.DailyRebuildTime } }; var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall }; IDialogReference dialog = await Dialog.ShowAsync("Schedule Playout Reset", parameters, options); await dialog.Result; if (_table != null) { await _table.ReloadServerData(); } } private async Task> ServerReload(TableState state, CancellationToken cancellationToken) { await Mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsPageSize, state.PageSize.ToString()), cancellationToken); PagedPlayoutsViewModel data = await Mediator.Send(new GetPagedPlayouts(_searchString, state.Page, state.PageSize), cancellationToken); _currentPage.Clear(); _currentPage.AddRange(data.Page); return new TableData { TotalItems = data.TotalCount, Items = data.Page }; } private async Task> DetailServerReload(TableState state, CancellationToken cancellationToken) { await Mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailPageSize, state.PageSize.ToString()), cancellationToken); await Mediator.Send(new SaveConfigElementByKey(ConfigElementKey.PlayoutsDetailShowFiller, _showFiller.ToString()), cancellationToken); if (_selectedPlayoutId.HasValue) { PagedPlayoutItemsViewModel data = await Mediator.Send(new GetFuturePlayoutItemsById(_selectedPlayoutId.Value, _showFiller, state.Page, state.PageSize), cancellationToken); return new TableData { TotalItems = data.TotalCount, Items = data.Page }; } return new TableData { TotalItems = 0 }; } private void OnSearch(string query) { _selectedPlayoutId = null; _searchString = query; _table.ReloadServerData(); } private string PlayoutItemViewRowClassFunc(PlayoutItemViewModel item, int index) { return "playout-filler-" + item.FillerKind.Match( fk => fk.ToString().ToLower(), () => "unscheduled"); } private string SelectedRowClassFunc(PlayoutNameViewModel element, int rowNumber) { if (_selectedPlayoutId != null && _selectedPlayoutId == element.PlayoutId) { if (element.BuildStatus is { Success: false }) { return "playout-build-failure-selected"; } return "selected"; } if (element.BuildStatus is { Success: false }) { return "playout-build-failure"; } return string.Empty; } private async Task ShowSchedulingContext(PlayoutItemViewModel item) { Option maybeResults = await Mediator.Send(new ProcessSchedulingContext(item.SchedulingContext), _cts.Token); foreach (string result in maybeResults) { var parameters = new DialogParameters { { "Context", result } }; var options = new DialogOptions { CloseButton = true, CloseOnEscapeKey = true, MaxWidth = MaxWidth.Medium, FullWidth = true }; IDialogReference dialog = await Dialog.ShowAsync(item.Title, parameters, options); DialogResult _ = await dialog.Result; } } }