diff --git a/Jellyfin.Api/Helpers/TranscodingJobHelper.cs b/Jellyfin.Api/Helpers/TranscodingJobHelper.cs index 49a3948688..3235da2920 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; @@ -530,6 +531,15 @@ namespace Jellyfin.Api.Helpers { var attachmentPath = Path.Combine(_appPaths.CachePath, "attachments", state.MediaSource.Id); await _attachmentExtractor.ExtractAllAttachments(state.MediaPath, state.MediaSource, attachmentPath, CancellationToken.None).ConfigureAwait(false); + + if (state.SubtitleStream.IsExternal) + { + 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, CancellationToken.None).ConfigureAwait(false); + } } var process = new Process diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index a2b6be1e6d..cffc60ba37 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -23,5 +23,10 @@ namespace MediaBrowser.Controller.MediaEncoding 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..eb58dd9e24 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -89,29 +89,63 @@ namespace MediaBrowser.MediaEncoding.Attachments string outputPath, CancellationToken cancellationToken) { - var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1)); + if (!Directory.Exists(outputPath)) + { + var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1)); - await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - if (!Directory.Exists(outputPath)) + try { await ExtractAllAttachmentsInternal( _mediaEncoder.GetInputArgument(inputFile, mediaSource), outputPath, + false, cancellationToken).ConfigureAwait(false); } + finally + { + semaphore.Release(); + } } - finally + } + + public async Task ExtractAllAttachmentsExternal( + string inputArgument, + string id, + string outputPath, + CancellationToken cancellationToken) + { + if (!File.Exists(Path.Join(outputPath, id))) { - semaphore.Release(); + var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1)); + + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + await ExtractAllAttachmentsInternal( + inputArgument, + outputPath, + true, + cancellationToken).ConfigureAwait(false); + } + finally + { + if (Directory.Exists(outputPath)) + { + File.Create(Path.Join(outputPath, id)); + } + + semaphore.Release(); + } } } private async Task ExtractAllAttachmentsInternal( string inputPath, string outputPath, + bool isExternal, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) @@ -124,11 +158,14 @@ namespace MediaBrowser.MediaEncoding.Attachments throw new ArgumentNullException(nameof(outputPath)); } - Directory.CreateDirectory(outputPath); + if (!Directory.Exists(outputPath)) + { + Directory.CreateDirectory(outputPath); + } 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 +211,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))