From 585b56a668f044ae231458aff32d64f40a6b150a Mon Sep 17 00:00:00 2001 From: Jason Dove Date: Tue, 10 Jan 2023 14:45:04 -0600 Subject: [PATCH] bug fixes (#1107) * don't search an empty search index * fix bug with flood filler prediction check * extract subtitles on primary worker thread --- .../Channels/Commands/UpdateChannelHandler.cs | 8 +-- .../ISubtitleWorkerRequest.cs | 5 -- .../Playouts/Commands/BuildPlayoutHandler.cs | 8 +-- .../Commands/ExtractEmbeddedSubtitles.cs | 2 +- ErsatzTV.Core/Scheduling/PlayoutBuilder.cs | 15 +++-- .../Scheduling/PlayoutModeSchedulerFlood.cs | 19 +++--- ErsatzTV.Infrastructure/Search/SearchIndex.cs | 5 +- ErsatzTV/Services/SubtitleWorkerService.cs | 66 ------------------- ErsatzTV/Services/WorkerService.cs | 4 ++ ErsatzTV/Startup.cs | 2 - 10 files changed, 35 insertions(+), 99 deletions(-) delete mode 100644 ErsatzTV.Application/ISubtitleWorkerRequest.cs delete mode 100644 ErsatzTV/Services/SubtitleWorkerService.cs diff --git a/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs b/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs index 08e43172c..e92dcf19c 100644 --- a/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs @@ -15,13 +15,13 @@ namespace ErsatzTV.Application.Channels; public class UpdateChannelHandler : IRequestHandler> { private readonly IDbContextFactory _dbContextFactory; - private readonly ChannelWriter _ffmpegWorkerChannel; + private readonly ChannelWriter _workerChannel; public UpdateChannelHandler( - ChannelWriter ffmpegWorkerChannel, + ChannelWriter workerChannel, IDbContextFactory dbContextFactory) { - _ffmpegWorkerChannel = ffmpegWorkerChannel; + _workerChannel = workerChannel; _dbContextFactory = dbContextFactory; } @@ -85,7 +85,7 @@ public class UpdateChannelHandler : IRequestHandler _dbContextFactory; private readonly IFFmpegSegmenterService _ffmpegSegmenterService; - private readonly ChannelWriter _ffmpegWorkerChannel; + private readonly ChannelWriter _workerChannel; private readonly IPlayoutBuilder _playoutBuilder; public BuildPlayoutHandler( @@ -25,13 +25,13 @@ public class BuildPlayoutHandler : IRequestHandler dbContextFactory, IPlayoutBuilder playoutBuilder, IFFmpegSegmenterService ffmpegSegmenterService, - ChannelWriter ffmpegWorkerChannel) + ChannelWriter workerChannel) { _client = client; _dbContextFactory = dbContextFactory; _playoutBuilder = playoutBuilder; _ffmpegSegmenterService = ffmpegSegmenterService; - _ffmpegWorkerChannel = ffmpegWorkerChannel; + _workerChannel = workerChannel; } public async Task> Handle(BuildPlayout request, CancellationToken cancellationToken) @@ -56,7 +56,7 @@ public class BuildPlayoutHandler : IRequestHandler PlayoutId) : IRequest>, - ISubtitleWorkerRequest; + IBackgroundServiceRequest; diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index 66b8a812a..8d88c54be 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -737,17 +737,18 @@ public class PlayoutBuilder : IPlayoutBuilder (anchor.EnumeratorState = new CollectionEnumeratorState { Seed = Random.Next(), Index = 0 }), () => new CollectionEnumeratorState { Seed = Random.Next(), Index = 0 }); - if (await _mediaCollectionRepository.IsCustomPlaybackOrder(collectionKey.CollectionId ?? 0)) + int collectionId = collectionKey.CollectionId ?? 0; + + if (collectionKey.CollectionType == ProgramScheduleItemCollectionType.Collection && + await _mediaCollectionRepository.IsCustomPlaybackOrder(collectionId)) { - Option collectionWithItems = - await _mediaCollectionRepository.GetCollectionWithCollectionItemsUntracked( - collectionKey.CollectionId ?? 0); + Option maybeCollectionWithItems = + await _mediaCollectionRepository.GetCollectionWithCollectionItemsUntracked(collectionId); - if (collectionKey.CollectionType == ProgramScheduleItemCollectionType.Collection && - collectionWithItems.IsSome) + foreach (Collection collectionWithItems in maybeCollectionWithItems) { return new CustomOrderCollectionEnumerator( - collectionWithItems.ValueUnsafe(), + collectionWithItems, mediaItems, state); } diff --git a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs index e52ee1ea7..4fe56f902 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs @@ -91,15 +91,18 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase p.FinishOffset); - if (Math.Abs((itemEndTimeWithFiller - actualEndTime).TotalSeconds) > 1) + if (playoutItems.Count > 0) { - _logger.LogWarning( - "Filler prediction failure: predicted {PredictedDuration} doesn't match actual {ActualDuration}", - itemEndTimeWithFiller, - actualEndTime); - - // _logger.LogWarning("Playout items: {@PlayoutItems}", playoutItems); + DateTimeOffset actualEndTime = playoutItems.Max(p => p.FinishOffset); + if (Math.Abs((itemEndTimeWithFiller - actualEndTime).TotalSeconds) > 1) + { + _logger.LogWarning( + "Filler prediction failure: predicted {PredictedDuration} doesn't match actual {ActualDuration}", + itemEndTimeWithFiller, + actualEndTime); + + // _logger.LogWarning("Playout items: {@PlayoutItems}", playoutItems); + } } nextState = nextState with diff --git a/ErsatzTV.Infrastructure/Search/SearchIndex.cs b/ErsatzTV.Infrastructure/Search/SearchIndex.cs index 07cf12adb..11723dcb1 100644 --- a/ErsatzTV.Infrastructure/Search/SearchIndex.cs +++ b/ErsatzTV.Infrastructure/Search/SearchIndex.cs @@ -185,8 +185,9 @@ public sealed class SearchIndex : ISearchIndex }; client.Breadcrumbs.Leave("SearchIndex.Search", BreadcrumbType.State, metadata); - - if (string.IsNullOrWhiteSpace(searchQuery.Replace("*", string.Empty).Replace("?", string.Empty))) + + if (string.IsNullOrWhiteSpace(searchQuery.Replace("*", string.Empty).Replace("?", string.Empty)) || + _writer.MaxDoc == 0) { return new SearchResult(new List(), 0); } diff --git a/ErsatzTV/Services/SubtitleWorkerService.cs b/ErsatzTV/Services/SubtitleWorkerService.cs deleted file mode 100644 index 6eeec5a86..000000000 --- a/ErsatzTV/Services/SubtitleWorkerService.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Threading.Channels; -using Bugsnag; -using ErsatzTV.Application; -using ErsatzTV.Application.Subtitles; -using MediatR; - -namespace ErsatzTV.Services; - -public class SubtitleWorkerService : BackgroundService -{ - private readonly ChannelReader _channel; - private readonly ILogger _logger; - private readonly IServiceScopeFactory _serviceScopeFactory; - - public SubtitleWorkerService( - ChannelReader channel, - IServiceScopeFactory serviceScopeFactory, - ILogger logger) - { - _channel = channel; - _serviceScopeFactory = serviceScopeFactory; - _logger = logger; - } - - protected override async Task ExecuteAsync(CancellationToken cancellationToken) - { - try - { - _logger.LogInformation("Subtitle worker service started"); - - await foreach (ISubtitleWorkerRequest request in _channel.ReadAllAsync(cancellationToken)) - { - using IServiceScope scope = _serviceScopeFactory.CreateScope(); - - try - { - switch (request) - { - case ExtractEmbeddedSubtitles extractEmbeddedSubtitles: - IMediator mediator = scope.ServiceProvider.GetRequiredService(); - await mediator.Send(extractEmbeddedSubtitles, cancellationToken); - break; - } - } - catch (Exception ex) - { - _logger.LogWarning(ex, "Failed to handle subtitle worker request"); - - try - { - IClient client = scope.ServiceProvider.GetRequiredService(); - client.Notify(ex); - } - catch (Exception) - { - // do nothing - } - } - } - } - catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException) - { - _logger.LogInformation("Subtitle worker service shutting down"); - } - } -} diff --git a/ErsatzTV/Services/WorkerService.cs b/ErsatzTV/Services/WorkerService.cs index 3bf846cde..213d5a0bd 100644 --- a/ErsatzTV/Services/WorkerService.cs +++ b/ErsatzTV/Services/WorkerService.cs @@ -6,6 +6,7 @@ using ErsatzTV.Application.MediaCollections; using ErsatzTV.Application.MediaSources; using ErsatzTV.Application.Playouts; using ErsatzTV.Application.Search; +using ErsatzTV.Application.Subtitles; using ErsatzTV.Core; using ErsatzTV.Core.Interfaces.Locking; using MediatR; @@ -96,6 +97,9 @@ public class WorkerService : BackgroundService case MatchTraktListItems matchTraktListItems: await mediator.Send(matchTraktListItems, cancellationToken); break; + case ExtractEmbeddedSubtitles extractEmbeddedSubtitles: + await mediator.Send(extractEmbeddedSubtitles, cancellationToken); + break; } } catch (ObjectDisposedException) when (cancellationToken.IsCancellationRequested) diff --git a/ErsatzTV/Startup.cs b/ErsatzTV/Startup.cs index 067d5a5ad..021c00e59 100644 --- a/ErsatzTV/Startup.cs +++ b/ErsatzTV/Startup.cs @@ -375,7 +375,6 @@ public class Startup AddChannel(services); AddChannel(services); AddChannel(services); - AddChannel(services); AddChannel(services); services.AddScoped(); @@ -470,7 +469,6 @@ public class Startup services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); - services.AddHostedService(); #endif services.AddHostedService(); services.AddHostedService();