diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4b8548..39f5d984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - VAAPI, QSV and NVIDIA are now all supported in the base docker image - Other docker image tags are deprecated and will receive no new updates after the next release - A health check has been added to notify users (on `-vaapi` or `-nvidia` tags) of this change +- Schedule items editor: show currently selected row using background color instead of font weight ### Fixed - Fix error message about synchronizing Plex collections from a Plex server that has zero collections @@ -61,6 +62,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix detecting NVIDIA capabilities on Blackwell GPUs - Fix decoder selection in NVIDIA pipeline - Prevent playback order `Shuffle In Order` from being used with `Fill With Group Mode` as they are incompatible +- Fix XMLTV items not grouping properly (guide mode: `Filler`) due to post-roll filler ## [25.1.0] - 2025-01-10 ### Added diff --git a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs index 0b8cc698..15e4f9d4 100644 --- a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs @@ -287,24 +287,11 @@ public class RefreshChannelDataHandler : IRequestHandler int finishIndex = j; while (finishIndex + 1 < sorted.Count && (sorted[finishIndex + 1].GuideGroup == startItem.GuideGroup || sorted[finishIndex + 1].FillerKind is FillerKind.GuideMode - or FillerKind.Tail or FillerKind.Fallback or FillerKind.DecoDefault)) + or FillerKind.PostRoll or FillerKind.Tail or FillerKind.Fallback or FillerKind.DecoDefault)) { finishIndex++; } - int customShowId = -1; - if (displayItem.MediaItem is Episode ep) - { - customShowId = ep.Season.ShowId; - } - - bool isSameCustomShow = hasCustomTitle; - for (int x = j; x <= finishIndex; x++) - { - isSameCustomShow = isSameCustomShow && sorted[x].MediaItem is Episode e && - customShowId == e.Season.ShowId; - } - PlayoutItem finishItem = sorted[finishIndex]; i = finishIndex; diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs index 5905cbd1..bce72729 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs @@ -308,7 +308,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e1, filler.Duration.Value, - FillerKind.PreRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PreRoll, filler.AllowWatermarks, log, cancellationToken)); @@ -320,7 +320,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e2, filler.Count.Value, - FillerKind.PreRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PreRoll, filler.AllowWatermarks, cancellationToken)); break; @@ -331,7 +331,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e3, filler.Count.Value, - FillerKind.PreRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PreRoll, filler.AllowWatermarks, cancellationToken)); break; @@ -361,7 +361,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e1, filler.Duration.Value, - FillerKind.MidRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.MidRoll, filler.AllowWatermarks, log, cancellationToken)); @@ -381,7 +381,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e2, filler.Count.Value, - FillerKind.MidRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.MidRoll, filler.AllowWatermarks, cancellationToken)); } @@ -400,7 +400,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e3, filler.Count.Value, - FillerKind.MidRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.MidRoll, filler.AllowWatermarks, cancellationToken)); } @@ -423,7 +423,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e1, filler.Duration.Value, - FillerKind.PostRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PostRoll, filler.AllowWatermarks, log, cancellationToken)); @@ -435,7 +435,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e2, filler.Count.Value, - FillerKind.PostRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PostRoll, filler.AllowWatermarks, cancellationToken)); break; @@ -446,7 +446,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, e3, filler.Count.Value, - FillerKind.PostRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PostRoll, filler.AllowWatermarks, cancellationToken)); break; @@ -506,7 +506,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, pre1, remainingToFill, - FillerKind.PreRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PreRoll, padFiller.AllowWatermarks, log, cancellationToken)); @@ -532,7 +532,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, mid1, remainingToFill, - FillerKind.MidRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.MidRoll, padFiller.AllowWatermarks, log, cancellationToken)); @@ -596,7 +596,7 @@ public abstract class PlayoutModeSchedulerBase : IPlayoutModeScheduler whe playoutBuilderState, post1, remainingToFill, - FillerKind.PostRoll, + scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PostRoll, padFiller.AllowWatermarks, log, cancellationToken)); diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs index f5565a03..6a72a774 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs @@ -69,7 +69,7 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase + .selected { + background-color: #009000 !important; + } + + + SelectedItemChanged="@(vm => SelectedItemChanged(vm))" + RowClassFunc="@SelectedRowClassFunc"> @_schedule.Name Items @@ -40,17 +47,17 @@ - + @(context.StartType == StartType.Fixed ? context.StartTime == null ? string.Empty : DateTime.Today.Add(context.StartTime.Value).ToShortTimeString() : "Dynamic") - + @context.CollectionName - + @context.PlayoutMode @if (context.PlayoutMode == PlayoutMode.Multiple && context.MultipleCount.HasValue) { @@ -675,4 +682,8 @@ } } + private string SelectedRowClassFunc(ProgramScheduleItemEditViewModel element, int rowNumber) + { + return _selectedItem != null && _selectedItem == element ? "selected" : string.Empty; + } } \ No newline at end of file diff --git a/ErsatzTV/Services/WorkerService.cs b/ErsatzTV/Services/WorkerService.cs index 5be04630..bfaccd06 100644 --- a/ErsatzTV/Services/WorkerService.cs +++ b/ErsatzTV/Services/WorkerService.cs @@ -1,4 +1,5 @@ -using System.Threading.Channels; +using System.Diagnostics; +using System.Threading.Channels; using Bugsnag; using ErsatzTV.Application; using ErsatzTV.Application.Channels; @@ -57,19 +58,24 @@ public class WorkerService : BackgroundService await mediator.Send(refreshChannelData, stoppingToken); break; case BuildPlayout buildPlayout: - var cts = new CancellationTokenSource(TimeSpan.FromMinutes(2)); - var linkedTokenSource = - CancellationTokenSource.CreateLinkedTokenSource(cts.Token, stoppingToken); + { + CancellationTokenSource cts = Debugger.IsAttached + ? new CancellationTokenSource(TimeSpan.FromMinutes(10)) + : new CancellationTokenSource(TimeSpan.FromMinutes(2)); + + var linkedTokenSource = + CancellationTokenSource.CreateLinkedTokenSource(cts.Token, stoppingToken); - Either buildPlayoutResult = await mediator.Send( - buildPlayout, - linkedTokenSource.Token); - buildPlayoutResult.BiIter( - _ => _logger.LogDebug("Built playout {PlayoutId}", buildPlayout.PlayoutId), - error => _logger.LogWarning( - "Unable to build playout {PlayoutId}: {Error}", - buildPlayout.PlayoutId, - error.Value)); + Either buildPlayoutResult = await mediator.Send( + buildPlayout, + linkedTokenSource.Token); + buildPlayoutResult.BiIter( + _ => _logger.LogDebug("Built playout {PlayoutId}", buildPlayout.PlayoutId), + error => _logger.LogWarning( + "Unable to build playout {PlayoutId}: {Error}", + buildPlayout.PlayoutId, + error.Value)); + } break; case TimeShiftOnDemandPlayout timeShiftOnDemandPlayout: await mediator.Send(timeShiftOnDemandPlayout, stoppingToken);