Browse Source

fix xmltv grouping with post-roll filler (#2046)

pull/2048/head
Jason Dove 4 days ago committed by GitHub
parent
commit
7cfa298c72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 15
      ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs
  3. 24
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs
  4. 2
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  5. 19
      ErsatzTV/Pages/ScheduleItemsEditor.razor
  6. 32
      ErsatzTV/Services/WorkerService.cs

2
CHANGELOG.md

@ -49,6 +49,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -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/). @@ -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

15
ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs

@ -287,24 +287,11 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -287,24 +287,11 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
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;

24
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerBase.cs

@ -308,7 +308,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe @@ -308,7 +308,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -320,7 +320,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -331,7 +331,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -361,7 +361,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -381,7 +381,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -400,7 +400,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -423,7 +423,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -435,7 +435,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -446,7 +446,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -506,7 +506,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -532,7 +532,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> 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<T> : IPlayoutModeScheduler<T> whe @@ -596,7 +596,7 @@ public abstract class PlayoutModeSchedulerBase<T> : IPlayoutModeScheduler<T> whe
playoutBuilderState,
post1,
remainingToFill,
FillerKind.PostRoll,
scheduleItem.GuideMode == GuideMode.Filler ? FillerKind.GuideMode : FillerKind.PostRoll,
padFiller.AllowWatermarks,
log,
cancellationToken));

2
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -69,7 +69,7 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul @@ -69,7 +69,7 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
SubtitleMode = scheduleItem.SubtitleMode
};
// never block scheduling when there is only one schedule item (with fixed start and flood)
// never block scheduling when there is only one schedule item (with fixed start and flood)
DateTimeOffset peekScheduleItemStart =
scheduleItem.Id != peekScheduleItem.Id && peekScheduleItem.StartType == StartType.Fixed
? GetStartTimeAfter(nextState with { InFlood = false }, peekScheduleItem)

19
ErsatzTV/Pages/ScheduleItemsEditor.razor

@ -13,12 +13,19 @@ @@ -13,12 +13,19 @@
@inject ISnackbar Snackbar
@inject IMediator Mediator
<style>
.selected {
background-color: #009000 !important;
}
</style>
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
<MudTable T="ProgramScheduleItemEditViewModel"
Hover="true"
Items="_schedule?.Items?.OrderBy(i => i.Index)"
Dense="true"
SelectedItemChanged="@(vm => SelectedItemChanged(vm))">
SelectedItemChanged="@(vm => SelectedItemChanged(vm))"
RowClassFunc="@SelectedRowClassFunc">
<ToolBarContent>
<MudText Typo="Typo.h6">@_schedule.Name Items</MudText>
</ToolBarContent>
@ -40,17 +47,17 @@ @@ -40,17 +47,17 @@
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Start Time">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
<MudText Typo="@Typo.body2">
@(context.StartType == StartType.Fixed ? context.StartTime == null ? string.Empty : DateTime.Today.Add(context.StartTime.Value).ToShortTimeString() : "Dynamic")
</MudText>
</MudTd>
<MudTd DataLabel="Collection">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
<MudText Typo="@Typo.body2">
@context.CollectionName
</MudText>
</MudTd>
<MudTd DataLabel="Playout Mode">
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
<MudText Typo="@Typo.body2">
@context.PlayoutMode
@if (context.PlayoutMode == PlayoutMode.Multiple && context.MultipleCount.HasValue)
{
@ -675,4 +682,8 @@ @@ -675,4 +682,8 @@
}
}
private string SelectedRowClassFunc(ProgramScheduleItemEditViewModel element, int rowNumber)
{
return _selectedItem != null && _selectedItem == element ? "selected" : string.Empty;
}
}

32
ErsatzTV/Services/WorkerService.cs

@ -1,4 +1,5 @@ @@ -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 @@ -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<BaseError, Unit> 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<BaseError, Unit> 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);

Loading…
Cancel
Save