diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 49a3948688..da3c1530c5 100644 --- a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs +++ b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs @@ -13,6 +13,7 @@ using Jellyfin.Api.Models.StreamingDtos; using Jellyfin.Data.Enums; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; @@ -529,7 +530,16 @@ namespace Jellyfin.Api.Helpers if (state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode) { var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); - await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, CancellationToken.None).ConfigureAwait(false); + await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + + if (state.SubtitleStream.IsExternal && string.Equals(Path.GetExtension(state.SubtitleStream.Path), ".mks", StringComparison.OrdinalIgnoreCase)) + { + string subtitlePath = state.SubtitleStream.Path; + string subtitlePathArgument = string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", subtitlePath.Replace("\"", "\\\"", StringComparison.Ordinal)); + string subtitleId = subtitlePath.GetMD5().ToString("N", CultureInfo.InvariantCulture); + + await _attachmentExtractor.ExtractAllAttachmentsExternal(subtitlePathArgument, subtitleId, attachmentPath, cancellationTokenSource.Token).ConfigureAwait(false); + } } var process = new Process diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index a2b6be1e6d..09840d2eea 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -18,10 +18,17 @@ namespace MediaBrowser.Controller.MediaEncoding string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken); + Task ExtractAllAttachments( string inputFile, MediaSourceInfo mediaSource, string outputPath, CancellationToken cancellationToken); + + Task ExtractAllAttachmentsExternal( + string inputArgument, + string id, + string outputPath, + CancellationToken cancellationToken); } } diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 06d20d90e1..142571e8f6 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -100,6 +100,7 @@ namespace MediaBrowser.MediaEncoding.Attachments await ExtractAllAttachmentsInternal( _mediaEncoder.GetInputArgument(inputFile, mediaSource), outputPath, + false, cancellationToken).ConfigureAwait(false); } } @@ -109,9 +110,42 @@ namespace MediaBrowser.MediaEncoding.Attachments } } + public async Task ExtractAllAttachmentsExternal( + string inputArgument, + string id, + string outputPath, + CancellationToken cancellationToken) + { + var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1)); + + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + if (!File.Exists(Path.Join(outputPath, id))) + { + await ExtractAllAttachmentsInternal( + inputArgument, + outputPath, + true, + cancellationToken).ConfigureAwait(false); + + if (Directory.Exists(outputPath)) + { + File.Create(Path.Join(outputPath, id)); + } + } + } + finally + { + semaphore.Release(); + } + } + private async Task ExtractAllAttachmentsInternal( string inputPath, string outputPath, + bool isExternal, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) @@ -128,7 +162,7 @@ namespace MediaBrowser.MediaEncoding.Attachments var processArgs = string.Format( CultureInfo.InvariantCulture, - "-dump_attachment:t \"\" -i {0} -t 0 -f null null", + "-dump_attachment:t \"\" -y -i {0} -t 0 -f null null", inputPath); int exitCode; @@ -174,19 +208,24 @@ namespace MediaBrowser.MediaEncoding.Attachments if (exitCode != 0) { - failed = true; - - _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputPath, exitCode); - try + if (isExternal && exitCode == 1) { - if (Directory.Exists(outputPath)) + // ffmpeg returns exitCode 1 because there is no video or audio stream + // this can be ignored + } + else + { + failed = true; + + _logger.LogWarning("Deleting extracted attachments {Path} due to failure: {ExitCode}", outputPath, exitCode); + try { Directory.Delete(outputPath); } - } - catch (IOException ex) - { - _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputPath); + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting extracted attachments {Path}", outputPath); + } } } else if (!Directory.Exists(outputPath))