public async Task <Either <BaseError, Unit> > Handle( ExtractEmbeddedSubtitles request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation <BaseError, string> validation = await FFmpegPathMustExist(dbContext); return(await validation.Match( ffmpegPath => ExtractAll(dbContext, request, ffmpegPath, cancellationToken), error => Task.FromResult <Either <BaseError, Unit> >(error.Join()))); }
private async Task <Either <BaseError, Unit> > ExtractAll( TvContext dbContext, ExtractEmbeddedSubtitles request, string ffmpegPath, CancellationToken cancellationToken) { try { DateTime now = DateTime.UtcNow; DateTime until = now.AddHours(1); var playoutIdsToCheck = new List <int>(); // only check the requested playout if subtitles are enabled Option <Playout> requestedPlayout = await dbContext.Playouts .Filter(p => p.Channel.SubtitleMode != ChannelSubtitleMode.None) .SelectOneAsync(p => p.Id, p => p.Id == request.PlayoutId.IfNone(-1)); playoutIdsToCheck.AddRange(requestedPlayout.Map(p => p.Id)); // check all playouts (that have subtitles enabled) if none were passed if (request.PlayoutId.IsNone) { playoutIdsToCheck = dbContext.Playouts .Filter(p => p.Channel.SubtitleMode != ChannelSubtitleMode.None) .Map(p => p.Id) .ToList(); } if (playoutIdsToCheck.Count == 0) { foreach (int playoutId in request.PlayoutId) { _logger.LogDebug( "Playout {PlayoutId} does not have subtitles enabled; nothing to extract", playoutId); return(Unit.Default); } _logger.LogDebug("No playouts have subtitles enabled; nothing to extract"); return(Unit.Default); } _logger.LogDebug("Checking playouts {PlayoutIds} for text subtitles to extract", playoutIdsToCheck); // find all playout items in the next hour List <PlayoutItem> playoutItems = await dbContext.PlayoutItems .Filter(pi => playoutIdsToCheck.Contains(pi.PlayoutId)) .Filter(pi => pi.Finish >= DateTime.UtcNow) .Filter(pi => pi.Start <= until) .ToListAsync(cancellationToken); // TODO: support other media kinds (movies, other videos, etc) var mediaItemIds = playoutItems.Map(pi => pi.MediaItemId).ToList(); // filter for subtitles that need extraction List <int> unextractedMediaItemIds = await GetUnextractedMediaItemIds(dbContext, mediaItemIds, cancellationToken); if (unextractedMediaItemIds.Any()) { _logger.LogDebug( "Found media items {MediaItemIds} with text subtitles to extract for playouts {PlayoutIds}", unextractedMediaItemIds, playoutIdsToCheck); } else { _logger.LogDebug("Found no text subtitles to extract for playouts {PlayoutIds}", playoutIdsToCheck); } // sort by start time var toUpdate = playoutItems .Filter(pi => pi.Finish >= DateTime.UtcNow) .DistinctBy(pi => pi.MediaItemId) .Filter(pi => unextractedMediaItemIds.Contains(pi.MediaItemId)) .OrderBy(pi => pi.StartOffset) .Map(pi => pi.MediaItemId) .ToList(); foreach (int mediaItemId in toUpdate) { if (cancellationToken.IsCancellationRequested) { return(Unit.Default); } PlayoutItem pi = playoutItems.Find(pi => pi.MediaItemId == mediaItemId); _logger.LogDebug("Extracting subtitles for item with start time {StartTime}", pi?.StartOffset); // extract subtitles and fonts for each item and update db await ExtractSubtitles(dbContext, mediaItemId, ffmpegPath, cancellationToken); // await ExtractFonts(dbContext, episodeId, ffmpegPath, cancellationToken); } return(Unit.Default); } catch (TaskCanceledException) { return(Unit.Default); } }