diff --git a/CHANGELOG.md b/CHANGELOG.md index c6268ab2..c3dd7202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Added +- Add `Reset All Playouts` button to top of playouts page + ### Changed - **BREAKING CHANGE**: Change channel identifiers used in XMLTV to work around bad behavior in Plex diff --git a/ErsatzTV.Application/Playouts/Commands/ResetAllPlayouts.cs b/ErsatzTV.Application/Playouts/Commands/ResetAllPlayouts.cs new file mode 100644 index 00000000..dbf41139 --- /dev/null +++ b/ErsatzTV.Application/Playouts/Commands/ResetAllPlayouts.cs @@ -0,0 +1,3 @@ +namespace ErsatzTV.Application.Playouts; + +public record ResetAllPlayouts : IRequest; diff --git a/ErsatzTV.Application/Playouts/Commands/ResetAllPlayoutsHandler.cs b/ErsatzTV.Application/Playouts/Commands/ResetAllPlayoutsHandler.cs new file mode 100644 index 00000000..8ccca54e --- /dev/null +++ b/ErsatzTV.Application/Playouts/Commands/ResetAllPlayoutsHandler.cs @@ -0,0 +1,40 @@ +using System.Threading.Channels; +using ErsatzTV.Core.Domain; +using ErsatzTV.Core.Interfaces.Locking; +using ErsatzTV.Core.Scheduling; +using ErsatzTV.Infrastructure.Data; +using Microsoft.EntityFrameworkCore; + +namespace ErsatzTV.Application.Playouts; + +public class ResetAllPlayoutsHandler( + IEntityLocker locker, + ChannelWriter channel, + IDbContextFactory dbContextFactory) + : IRequestHandler +{ + public async Task Handle(ResetAllPlayouts request, CancellationToken cancellationToken) + { + await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); + + foreach (Playout playout in await dbContext.Playouts.ToListAsync(cancellationToken)) + { + switch (playout.ProgramSchedulePlayoutType) + { + case ProgramSchedulePlayoutType.Flood: + case ProgramSchedulePlayoutType.Block: + case ProgramSchedulePlayoutType.Yaml: + if (!locker.IsPlayoutLocked(playout.Id)) + { + await channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Reset), cancellationToken); + } + break; + case ProgramSchedulePlayoutType.ExternalJson: + case ProgramSchedulePlayoutType.None: + default: + // external json cannot be reset + continue; + } + } + } +} diff --git a/ErsatzTV/Pages/Playouts.razor b/ErsatzTV/Pages/Playouts.razor index 3601ee92..7c0527d8 100644 --- a/ErsatzTV/Pages/Playouts.razor +++ b/ErsatzTV/Pages/Playouts.razor @@ -28,6 +28,9 @@ Add External Json Playout + + Reset All Playouts + ("Edit External Json File", parameters, options); DialogResult result = await dialog.Result; - if (!result.Canceled) + if (result is { Canceled: false }) { await Mediator.Send(new UpdateExternalJsonPlayout(playout.PlayoutId, result.Data as string ?? playout.ExternalJsonFile), _cts.Token); if (_table != null) @@ -293,7 +296,7 @@ IDialogReference dialog = await Dialog.ShowAsync("Delete Playout", parameters, options); DialogResult result = await dialog.Result; - if (!result.Canceled) + if (result is { Canceled: false }) { await Mediator.Send(new DeletePlayout(playout.PlayoutId), _cts.Token); if (_table != null) @@ -308,6 +311,12 @@ } } + private async Task ResetAllPlayouts() + { + _selectedPlayoutId = null; + await Mediator.Send(new ResetAllPlayouts(), _cts.Token); + } + private async Task ResetPlayout(PlayoutNameViewModel playout) { await WorkerChannel.WriteAsync(new BuildPlayout(playout.PlayoutId, PlayoutBuildMode.Reset), _cts.Token);