|
|
|
@ -1,8 +1,10 @@ |
|
|
|
using System.Security.Cryptography; |
|
|
|
using System.Security.Cryptography; |
|
|
|
using System.Text; |
|
|
|
using System.Text; |
|
|
|
|
|
|
|
using System.Threading.Channels; |
|
|
|
using CliWrap; |
|
|
|
using CliWrap; |
|
|
|
using CliWrap.Buffered; |
|
|
|
using CliWrap.Buffered; |
|
|
|
using CliWrap.Builders; |
|
|
|
using CliWrap.Builders; |
|
|
|
|
|
|
|
using ErsatzTV.Application.Maintenance; |
|
|
|
using ErsatzTV.Core; |
|
|
|
using ErsatzTV.Core; |
|
|
|
using ErsatzTV.Core.Domain; |
|
|
|
using ErsatzTV.Core.Domain; |
|
|
|
using ErsatzTV.Core.Extensions; |
|
|
|
using ErsatzTV.Core.Extensions; |
|
|
|
@ -21,6 +23,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
{ |
|
|
|
{ |
|
|
|
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
|
|
|
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
|
|
|
private readonly IEmbyPathReplacementService _embyPathReplacementService; |
|
|
|
private readonly IEmbyPathReplacementService _embyPathReplacementService; |
|
|
|
|
|
|
|
private readonly ChannelWriter<IBackgroundServiceRequest> _workerChannel; |
|
|
|
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService; |
|
|
|
private readonly IJellyfinPathReplacementService _jellyfinPathReplacementService; |
|
|
|
private readonly ILocalFileSystem _localFileSystem; |
|
|
|
private readonly ILocalFileSystem _localFileSystem; |
|
|
|
private readonly ILogger<ExtractEmbeddedSubtitlesHandler> _logger; |
|
|
|
private readonly ILogger<ExtractEmbeddedSubtitlesHandler> _logger; |
|
|
|
@ -32,6 +35,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
IPlexPathReplacementService plexPathReplacementService, |
|
|
|
IPlexPathReplacementService plexPathReplacementService, |
|
|
|
IJellyfinPathReplacementService jellyfinPathReplacementService, |
|
|
|
IJellyfinPathReplacementService jellyfinPathReplacementService, |
|
|
|
IEmbyPathReplacementService embyPathReplacementService, |
|
|
|
IEmbyPathReplacementService embyPathReplacementService, |
|
|
|
|
|
|
|
ChannelWriter<IBackgroundServiceRequest> workerChannel, |
|
|
|
ILogger<ExtractEmbeddedSubtitlesHandler> logger) |
|
|
|
ILogger<ExtractEmbeddedSubtitlesHandler> logger) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_dbContextFactory = dbContextFactory; |
|
|
|
_dbContextFactory = dbContextFactory; |
|
|
|
@ -39,6 +43,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
_plexPathReplacementService = plexPathReplacementService; |
|
|
|
_plexPathReplacementService = plexPathReplacementService; |
|
|
|
_jellyfinPathReplacementService = jellyfinPathReplacementService; |
|
|
|
_jellyfinPathReplacementService = jellyfinPathReplacementService; |
|
|
|
_embyPathReplacementService = embyPathReplacementService; |
|
|
|
_embyPathReplacementService = embyPathReplacementService; |
|
|
|
|
|
|
|
_workerChannel = workerChannel; |
|
|
|
_logger = logger; |
|
|
|
_logger = logger; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -49,7 +54,12 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); |
|
|
|
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); |
|
|
|
Validation<BaseError, string> validation = await FFmpegPathMustExist(dbContext); |
|
|
|
Validation<BaseError, string> validation = await FFmpegPathMustExist(dbContext); |
|
|
|
return await validation.Match( |
|
|
|
return await validation.Match( |
|
|
|
ffmpegPath => ExtractAll(dbContext, request, ffmpegPath, cancellationToken), |
|
|
|
async ffmpegPath => |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
Either<BaseError, Unit> result = await ExtractAll(dbContext, request, ffmpegPath, cancellationToken); |
|
|
|
|
|
|
|
await _workerChannel.WriteAsync(new ReleaseMemory(false), cancellationToken); |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
}, |
|
|
|
error => Task.FromResult<Either<BaseError, Unit>>(error.Join())); |
|
|
|
error => Task.FromResult<Either<BaseError, Unit>>(error.Join())); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -68,6 +78,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
|
|
|
|
|
|
|
|
// only check the requested playout if subtitles are enabled
|
|
|
|
// only check the requested playout if subtitles are enabled
|
|
|
|
Option<Playout> requestedPlayout = await dbContext.Playouts |
|
|
|
Option<Playout> requestedPlayout = await dbContext.Playouts |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
p => p.Channel.SubtitleMode != ChannelSubtitleMode.None || |
|
|
|
p => p.Channel.SubtitleMode != ChannelSubtitleMode.None || |
|
|
|
p.ProgramSchedule.Items.Any(psi => psi.SubtitleMode != ChannelSubtitleMode.None)) |
|
|
|
p.ProgramSchedule.Items.Any(psi => psi.SubtitleMode != ChannelSubtitleMode.None)) |
|
|
|
@ -79,6 +90,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
if (request.PlayoutId.IsNone) |
|
|
|
if (request.PlayoutId.IsNone) |
|
|
|
{ |
|
|
|
{ |
|
|
|
playoutIdsToCheck = dbContext.Playouts |
|
|
|
playoutIdsToCheck = dbContext.Playouts |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
p => p.Channel.SubtitleMode != ChannelSubtitleMode.None || |
|
|
|
p => p.Channel.SubtitleMode != ChannelSubtitleMode.None || |
|
|
|
p.ProgramSchedule.Items.Any(psi => psi.SubtitleMode != ChannelSubtitleMode.None)) |
|
|
|
p.ProgramSchedule.Items.Any(psi => psi.SubtitleMode != ChannelSubtitleMode.None)) |
|
|
|
@ -104,6 +116,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
|
|
|
|
|
|
|
|
// find all playout items in the next hour
|
|
|
|
// find all playout items in the next hour
|
|
|
|
List<PlayoutItem> playoutItems = await dbContext.PlayoutItems |
|
|
|
List<PlayoutItem> playoutItems = await dbContext.PlayoutItems |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter(pi => playoutIdsToCheck.Contains(pi.PlayoutId)) |
|
|
|
.Filter(pi => playoutIdsToCheck.Contains(pi.PlayoutId)) |
|
|
|
.Filter(pi => pi.Finish >= DateTime.UtcNow) |
|
|
|
.Filter(pi => pi.Finish >= DateTime.UtcNow) |
|
|
|
.Filter(pi => pi.Start <= until) |
|
|
|
.Filter(pi => pi.Start <= until) |
|
|
|
@ -170,6 +183,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
try |
|
|
|
try |
|
|
|
{ |
|
|
|
{ |
|
|
|
List<int> episodeIds = await dbContext.EpisodeMetadata |
|
|
|
List<int> episodeIds = await dbContext.EpisodeMetadata |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter(em => mediaItemIds.Contains(em.EpisodeId)) |
|
|
|
.Filter(em => mediaItemIds.Contains(em.EpisodeId)) |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
em => em.Subtitles.Any( |
|
|
|
em => em.Subtitles.Any( |
|
|
|
@ -180,6 +194,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
result.AddRange(episodeIds); |
|
|
|
result.AddRange(episodeIds); |
|
|
|
|
|
|
|
|
|
|
|
List<int> movieIds = await dbContext.MovieMetadata |
|
|
|
List<int> movieIds = await dbContext.MovieMetadata |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter(mm => mediaItemIds.Contains(mm.MovieId)) |
|
|
|
.Filter(mm => mediaItemIds.Contains(mm.MovieId)) |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
mm => mm.Subtitles.Any( |
|
|
|
mm => mm.Subtitles.Any( |
|
|
|
@ -190,6 +205,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
result.AddRange(movieIds); |
|
|
|
result.AddRange(movieIds); |
|
|
|
|
|
|
|
|
|
|
|
List<int> musicVideoIds = await dbContext.MusicVideoMetadata |
|
|
|
List<int> musicVideoIds = await dbContext.MusicVideoMetadata |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter(mm => mediaItemIds.Contains(mm.MusicVideoId)) |
|
|
|
.Filter(mm => mediaItemIds.Contains(mm.MusicVideoId)) |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
mm => mm.Subtitles.Any( |
|
|
|
mm => mm.Subtitles.Any( |
|
|
|
@ -200,6 +216,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu |
|
|
|
result.AddRange(musicVideoIds); |
|
|
|
result.AddRange(musicVideoIds); |
|
|
|
|
|
|
|
|
|
|
|
List<int> otherVideoIds = await dbContext.OtherVideoMetadata |
|
|
|
List<int> otherVideoIds = await dbContext.OtherVideoMetadata |
|
|
|
|
|
|
|
.AsNoTracking() |
|
|
|
.Filter(ovm => mediaItemIds.Contains(ovm.OtherVideoId)) |
|
|
|
.Filter(ovm => mediaItemIds.Contains(ovm.OtherVideoId)) |
|
|
|
.Filter( |
|
|
|
.Filter( |
|
|
|
ovm => ovm.Subtitles.Any( |
|
|
|
ovm => ovm.Subtitles.Any( |
|
|
|
|