diff --git a/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContext.cs b/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContext.cs new file mode 100644 index 000000000..ae974d585 --- /dev/null +++ b/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContext.cs @@ -0,0 +1,3 @@ +namespace ErsatzTV.Application.ProgramSchedules; + +public record ProcessSchedulingContext(string SerializedContext) : IRequest>; diff --git a/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContextHandler.cs b/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContextHandler.cs new file mode 100644 index 000000000..c5863251e --- /dev/null +++ b/ErsatzTV.Application/ProgramSchedules/Queries/ProcessSchedulingContextHandler.cs @@ -0,0 +1,94 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Scheduling; +using ErsatzTV.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json; +using JsonSerializer = System.Text.Json.JsonSerializer; + +namespace ErsatzTV.Application.ProgramSchedules; + +public class ProcessSchedulingContextHandler(IDbContextFactory dbContextFactory) + : IRequestHandler> +{ + private static readonly JsonSerializerOptions Options = new() + { + Converters = { new JsonStringEnumConverter() }, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + WriteIndented = true + }; + + public async Task> Handle(ProcessSchedulingContext request, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(request.SerializedContext)) + { + return Option.None; + } + + var classicContext = JsonConvert.DeserializeObject(request.SerializedContext); + if (classicContext is not null) + { + await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); + + string scheduleName = await dbContext.ProgramSchedules + .Where(s => s.Id == classicContext.ScheduleId) + .Select(s => s.Name) + .SingleOrDefaultAsync(cancellationToken); + + var scheduleItem = await dbContext.ProgramScheduleItems + .AsNoTracking() + .AsSplitQuery() + .Include(si => si.SmartCollection) + .Include(si => si.Collection) + .Include(si => si.MultiCollection) + .Include(si => si.RerunCollection) + .Include(si => si.Playlist) + .SingleOrDefaultAsync(s => s.Id == classicContext.ItemId, cancellationToken); + + ClassicContextScheduleItem item; + if (scheduleItem is not null) + { + string collectionName = scheduleItem.CollectionType switch + { + CollectionType.SmartCollection => scheduleItem.SmartCollection.Name, + CollectionType.Collection => scheduleItem.Collection.Name, + CollectionType.MultiCollection => scheduleItem.MultiCollection.Name, + CollectionType.RerunRerun or CollectionType.RerunFirstRun => scheduleItem.RerunCollection.Name, + CollectionType.Playlist => scheduleItem.Playlist.Name, + _ => null + }; + + item = new ClassicContextScheduleItem(scheduleItem.Id, scheduleItem.CollectionType, collectionName); + } + else + { + item = new ClassicContextScheduleItem(classicContext.ItemId, null, null); + } + + var context = new ClassicContext( + new ContextScheduler("Classic", classicContext.Scheduler), + new ClassicContextSchedule(classicContext.ScheduleId, scheduleName ?? string.Empty), + item, + new ContextEnumerator(classicContext.Enumerator, classicContext.Seed, classicContext.Index)); + + return JsonSerializer.Serialize(context, Options); + } + + return request.SerializedContext; + } + + private sealed record ClassicContext( + ContextScheduler Scheduler, + ClassicContextSchedule Schedule, + ClassicContextScheduleItem ScheduleItem, + ContextEnumerator Enumerator); + + private sealed record ContextScheduler(string Type, string Mode); + + private sealed record ClassicContextSchedule(int Id, string Name); + + private sealed record ClassicContextScheduleItem(int Id, CollectionType? CollectionType, string CollectionName); + + private sealed record ContextEnumerator(string Name, int Seed, int Index); +} diff --git a/ErsatzTV.Core/Scheduling/SchedulingContext.cs b/ErsatzTV.Core/Scheduling/ClassicSchedulingContext.cs similarity index 78% rename from ErsatzTV.Core/Scheduling/SchedulingContext.cs rename to ErsatzTV.Core/Scheduling/ClassicSchedulingContext.cs index 807c4fa19..552ce3502 100644 --- a/ErsatzTV.Core/Scheduling/SchedulingContext.cs +++ b/ErsatzTV.Core/Scheduling/ClassicSchedulingContext.cs @@ -1,6 +1,6 @@ namespace ErsatzTV.Core.Scheduling; -public record SchedulingContext( +public record ClassicSchedulingContext( string Scheduler, int ScheduleId, int ItemId, diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs index 451331442..8714d5f61 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs @@ -20,7 +20,7 @@ public abstract class PlayoutModeSchedulerBase(ILogger logger) : IPlayoutMode { Converters = { new JsonStringEnumConverter() }, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - WriteIndented = true + WriteIndented = false }; private readonly Random _random = new(); @@ -914,7 +914,7 @@ public abstract class PlayoutModeSchedulerBase(ILogger logger) : IPlayoutMode protected string GetSchedulingContext(ProgramScheduleItem scheduleItem, IMediaCollectionEnumerator enumerator) { - var context = new SchedulingContext( + var context = new ClassicSchedulingContext( SchedulingContextName, scheduleItem.ProgramScheduleId, scheduleItem.Id, diff --git a/ErsatzTV/Pages/Playouts.razor b/ErsatzTV/Pages/Playouts.razor index fc7a168b1..9080bb525 100644 --- a/ErsatzTV/Pages/Playouts.razor +++ b/ErsatzTV/Pages/Playouts.razor @@ -2,6 +2,7 @@ @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 @@ -521,10 +522,14 @@ private async Task ShowSchedulingContext(PlayoutItemViewModel item) { - var parameters = new DialogParameters { { "PlayoutItem", item } }; - 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; + 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; + } } } diff --git a/ErsatzTV/Shared/SchedulingContextDialog.razor b/ErsatzTV/Shared/SchedulingContextDialog.razor index 270c1c2ed..b1bf1ccab 100644 --- a/ErsatzTV/Shared/SchedulingContextDialog.razor +++ b/ErsatzTV/Shared/SchedulingContextDialog.razor @@ -1,5 +1,4 @@ -@using ErsatzTV.Application.Playouts -@inject IJSRuntime JsRuntime +@inject IJSRuntime JsRuntime
@@ -25,7 +24,7 @@ IMudDialogInstance MudDialog { get; set; } [Parameter] - public PlayoutItemViewModel PlayoutItem { get; set; } + public string Context { get; set; } private string _info; private ElementReference _infoView; @@ -34,7 +33,7 @@ { try { - _info = PlayoutItem.SchedulingContext; + _info = Context; } catch (Exception ex) {