Browse Source

bug fixes (#1107)

* don't search an empty search index

* fix bug with flood filler prediction check

* extract subtitles on primary worker thread
pull/1108/head
Jason Dove 3 years ago committed by GitHub
parent
commit
585b56a668
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs
  2. 5
      ErsatzTV.Application/ISubtitleWorkerRequest.cs
  3. 8
      ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs
  4. 2
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitles.cs
  5. 15
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  6. 19
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  7. 5
      ErsatzTV.Infrastructure/Search/SearchIndex.cs
  8. 66
      ErsatzTV/Services/SubtitleWorkerService.cs
  9. 4
      ErsatzTV/Services/WorkerService.cs
  10. 2
      ErsatzTV/Startup.cs

8
ErsatzTV.Application/Channels/Commands/UpdateChannelHandler.cs

@ -15,13 +15,13 @@ namespace ErsatzTV.Application.Channels; @@ -15,13 +15,13 @@ namespace ErsatzTV.Application.Channels;
public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseError, ChannelViewModel>>
{
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly ChannelWriter<ISubtitleWorkerRequest> _ffmpegWorkerChannel;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
public UpdateChannelHandler(
ChannelWriter<ISubtitleWorkerRequest> ffmpegWorkerChannel,
ChannelWriter<IBackgroundServiceRequest> workerChannel,
IDbContextFactory<TvContext> dbContextFactory)
{
_ffmpegWorkerChannel = ffmpegWorkerChannel;
_workerChannel = workerChannel;
_dbContextFactory = dbContextFactory;
}
@ -85,7 +85,7 @@ public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseEr @@ -85,7 +85,7 @@ public class UpdateChannelHandler : IRequestHandler<UpdateChannel, Either<BaseEr
foreach (Playout playout in maybePlayout)
{
await _ffmpegWorkerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id));
await _workerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id));
}
}

5
ErsatzTV.Application/ISubtitleWorkerRequest.cs

@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
namespace ErsatzTV.Application;
public interface ISubtitleWorkerRequest
{
}

8
ErsatzTV.Application/Playouts/Commands/BuildPlayoutHandler.cs

@ -17,7 +17,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -17,7 +17,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
private readonly IClient _client;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
private readonly IFFmpegSegmenterService _ffmpegSegmenterService;
private readonly ChannelWriter<ISubtitleWorkerRequest> _ffmpegWorkerChannel;
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel;
private readonly IPlayoutBuilder _playoutBuilder;
public BuildPlayoutHandler(
@ -25,13 +25,13 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -25,13 +25,13 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
IDbContextFactory<TvContext> dbContextFactory,
IPlayoutBuilder playoutBuilder,
IFFmpegSegmenterService ffmpegSegmenterService,
ChannelWriter<ISubtitleWorkerRequest> ffmpegWorkerChannel)
ChannelWriter<IBackgroundServiceRequest> workerChannel)
{
_client = client;
_dbContextFactory = dbContextFactory;
_playoutBuilder = playoutBuilder;
_ffmpegSegmenterService = ffmpegSegmenterService;
_ffmpegWorkerChannel = ffmpegWorkerChannel;
_workerChannel = workerChannel;
}
public async Task<Either<BaseError, Unit>> Handle(BuildPlayout request, CancellationToken cancellationToken)
@ -56,7 +56,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro @@ -56,7 +56,7 @@ public class BuildPlayoutHandler : IRequestHandler<BuildPlayout, Either<BaseErro
_ffmpegSegmenterService.PlayoutUpdated(playout.Channel.Number);
}
await _ffmpegWorkerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id));
await _workerChannel.WriteAsync(new ExtractEmbeddedSubtitles(playout.Id));
}
catch (Exception ex)
{

2
ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitles.cs

@ -3,4 +3,4 @@ @@ -3,4 +3,4 @@
namespace ErsatzTV.Application.Subtitles;
public record ExtractEmbeddedSubtitles(Option<int> PlayoutId) : IRequest<Either<BaseError, Unit>>,
ISubtitleWorkerRequest;
IBackgroundServiceRequest;

15
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -737,17 +737,18 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -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<Collection> collectionWithItems =
await _mediaCollectionRepository.GetCollectionWithCollectionItemsUntracked(
collectionKey.CollectionId ?? 0);
Option<Collection> 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);
}

19
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -91,15 +91,18 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul @@ -91,15 +91,18 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
AddFiller(nextState, collectionEnumerators, scheduleItem, playoutItem, itemChapters));
// LogScheduledItem(scheduleItem, mediaItem, itemStartTime);
DateTimeOffset actualEndTime = playoutItems.Max(p => 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

5
ErsatzTV.Infrastructure/Search/SearchIndex.cs

@ -185,8 +185,9 @@ public sealed class SearchIndex : ISearchIndex @@ -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<SearchItem>(), 0);
}

66
ErsatzTV/Services/SubtitleWorkerService.cs

@ -1,66 +0,0 @@ @@ -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<ISubtitleWorkerRequest> _channel;
private readonly ILogger<SubtitleWorkerService> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public SubtitleWorkerService(
ChannelReader<ISubtitleWorkerRequest> channel,
IServiceScopeFactory serviceScopeFactory,
ILogger<SubtitleWorkerService> 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<IMediator>();
await mediator.Send(extractEmbeddedSubtitles, cancellationToken);
break;
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to handle subtitle worker request");
try
{
IClient client = scope.ServiceProvider.GetRequiredService<IClient>();
client.Notify(ex);
}
catch (Exception)
{
// do nothing
}
}
}
}
catch (Exception ex) when (ex is TaskCanceledException or OperationCanceledException)
{
_logger.LogInformation("Subtitle worker service shutting down");
}
}
}

4
ErsatzTV/Services/WorkerService.cs

@ -6,6 +6,7 @@ using ErsatzTV.Application.MediaCollections; @@ -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 @@ -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)

2
ErsatzTV/Startup.cs

@ -375,7 +375,6 @@ public class Startup @@ -375,7 +375,6 @@ public class Startup
AddChannel<IJellyfinBackgroundServiceRequest>(services);
AddChannel<IEmbyBackgroundServiceRequest>(services);
AddChannel<IFFmpegWorkerRequest>(services);
AddChannel<ISubtitleWorkerRequest>(services);
AddChannel<ISearchIndexBackgroundServiceRequest>(services);
services.AddScoped<IFFmpegVersionHealthCheck, FFmpegVersionHealthCheck>();
@ -470,7 +469,6 @@ public class Startup @@ -470,7 +469,6 @@ public class Startup
services.AddHostedService<EmbyService>();
services.AddHostedService<JellyfinService>();
services.AddHostedService<PlexService>();
services.AddHostedService<SubtitleWorkerService>();
#endif
services.AddHostedService<FFmpegLocatorService>();
services.AddHostedService<WorkerService>();

Loading…
Cancel
Save