From b2e19c0306fb42616736b18777641e94edfc9d85 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Wed, 25 Sep 2024 18:51:28 +0200 Subject: [PATCH 1/7] Also extract subtitles of MKS aux files if they're extractable. --- .../Subtitles/SubtitleEncoder.cs | 85 ++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 777e335874..a9b41898b5 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -489,10 +489,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { var subtitleStreams = mediaSource.MediaStreams - .Where(stream => stream is { IsExtractableSubtitleStream: true, SupportsExternalStream: true, IsExternal: false }); + .Where(stream => stream is { IsExtractableSubtitleStream: true, SupportsExternalStream: true }); foreach (var subtitleStream in subtitleStreams) { + if (subtitleStream.IsExternal && !subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); var releaser = await _semaphoreLocks.LockAsync(outputPath, cancellationToken).ConfigureAwait(false); @@ -510,6 +515,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (extractableStreams.Count > 0) { await ExtractAllExtractableSubtitlesInternal(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false); + await ExtractAllExtractableSubtitlesMKS(mediaSource, extractableStreams, cancellationToken).ConfigureAwait(false); } } catch (Exception ex) @@ -522,6 +528,72 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } + private async Task ExtractAllExtractableSubtitlesMKS( + MediaSourceInfo mediaSource, + List subtitleStreams, + CancellationToken cancellationToken) + { + var mksFiles = new List(); + + foreach (var subtitleStream in subtitleStreams) + { + if (!subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + if (!mksFiles.Contains(subtitleStream.Path)) + { + mksFiles.Add(subtitleStream.Path); + } + } + + if (mksFiles.Count == 0) + { + return; + } + + foreach (string mksFile in mksFiles) + { + var inputPath = _mediaEncoder.GetInputArgument(mksFile, mediaSource); + var outputPaths = new List(); + var args = string.Format( + CultureInfo.InvariantCulture, + "-i {0} -copyts", + inputPath); + + foreach (var subtitleStream in subtitleStreams) + { + if (!subtitleStream.Path.Equals(mksFile, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); + var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; + var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); + + if (streamIndex == -1) + { + _logger.LogError("Cannot find subtitle stream index for {InputPath} ({Index}), skipping this stream", inputPath, subtitleStream.Index); + continue; + } + + Directory.CreateDirectory(Path.GetDirectoryName(outputPath) ?? throw new FileNotFoundException($"Calculated path ({outputPath}) is not valid.")); + + outputPaths.Add(outputPath); + args += string.Format( + CultureInfo.InvariantCulture, + " -map 0:{0} -an -vn -c:s {1} \"{2}\"", + streamIndex, + outputCodec, + outputPath); + } + + await ExtractSubtitlesForFile(inputPath, args, outputPaths, cancellationToken).ConfigureAwait(false); + } + } + private async Task ExtractAllExtractableSubtitlesInternal( MediaSourceInfo mediaSource, List subtitleStreams, @@ -540,7 +612,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); - if (streamIndex == -1) + if (streamIndex == -1 || subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { _logger.LogError("Cannot find subtitle stream index for {InputPath} ({Index}), skipping this stream", inputPath, subtitleStream.Index); continue; @@ -557,6 +629,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles outputPath); } + await ExtractSubtitlesForFile(inputPath, args, outputPaths, cancellationToken).ConfigureAwait(false); + } + + private async Task ExtractSubtitlesForFile( + string inputPath, + string args, + List outputPaths, + CancellationToken cancellationToken) + { int exitCode; using (var process = new Process From 411ba03bf0f1533ba0fd1bd1aae763dbb39e9763 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Wed, 25 Sep 2024 19:07:53 +0200 Subject: [PATCH 2/7] Fixed formatting --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index a9b41898b5..8b11b9da94 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -558,9 +558,9 @@ namespace MediaBrowser.MediaEncoding.Subtitles var inputPath = _mediaEncoder.GetInputArgument(mksFile, mediaSource); var outputPaths = new List(); var args = string.Format( - CultureInfo.InvariantCulture, - "-i {0} -copyts", - inputPath); + CultureInfo.InvariantCulture, + "-i {0} -copyts", + inputPath); foreach (var subtitleStream in subtitleStreams) { From c0e287581822ee67ef696491c0128b8e747207e7 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Fri, 27 Sep 2024 13:22:49 +0200 Subject: [PATCH 3/7] If subtitles are part of an MKS, it is not an error. Just log for debug purpose and continue. --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 8b11b9da94..13c18e3223 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -612,7 +612,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); - if (streamIndex == -1 || subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + if (subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + { + _logger.LogDebug("Subtitle {Index} for file {InputPath} is part in an MKS file. Skipping", inputPath, subtitleStream.Index); + continue; + } + + if (streamIndex == -1) { _logger.LogError("Cannot find subtitle stream index for {InputPath} ({Index}), skipping this stream", inputPath, subtitleStream.Index); continue; From 84cebeae64ec7b291f4ae0f8cd68e6b1e011da01 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Fri, 27 Sep 2024 13:53:36 +0200 Subject: [PATCH 4/7] Skip early if subtitle is in MKS to avoid unnecessary function calls. --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 13c18e3223..dea65708fd 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -608,16 +608,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); - var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; - var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); - if (subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { _logger.LogDebug("Subtitle {Index} for file {InputPath} is part in an MKS file. Skipping", inputPath, subtitleStream.Index); continue; } + var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, "." + GetExtractableSubtitleFileExtension(subtitleStream)); + var outputCodec = IsCodecCopyable(subtitleStream.Codec) ? "copy" : "srt"; + var streamIndex = EncodingHelper.FindIndex(mediaSource.MediaStreams, subtitleStream); + if (streamIndex == -1) { _logger.LogError("Cannot find subtitle stream index for {InputPath} ({Index}), skipping this stream", inputPath, subtitleStream.Index); From e8239a7ee27ede387ab4b32f97cf588a8b3f1b25 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Fri, 27 Sep 2024 14:07:55 +0200 Subject: [PATCH 5/7] Do not attempt to extract internal subtitles if there are only MKS subtitles. --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index dea65708fd..0b09da591a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -635,6 +635,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles outputPath); } + if (outputPaths.Count == 0) + { + return; + } + await ExtractSubtitlesForFile(inputPath, args, outputPaths, cancellationToken).ConfigureAwait(false); } From fcf56b73cb03b9fba5e30484737f410a7cd95deb Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Thu, 2 Jan 2025 22:23:25 +0100 Subject: [PATCH 6/7] When subtitle is embedded in the main video file, the path will be null. --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 0b09da591a..c30bf15a95 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -537,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - if (!subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + if (subtitleStream.Path is null || !subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { continue; } @@ -608,7 +608,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - if (subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + if (subtitleStream.Path is not null && subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { _logger.LogDebug("Subtitle {Index} for file {InputPath} is part in an MKS file. Skipping", inputPath, subtitleStream.Index); continue; From 98daf4aedb464f66cbb6eeb0ad54de338f9eb691 Mon Sep 17 00:00:00 2001 From: Carsten Braun Date: Fri, 3 Jan 2025 08:19:22 +0100 Subject: [PATCH 7/7] Use string.IsNullOrEmpty instead of regular null check. --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index c30bf15a95..508d5be32a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -537,7 +537,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - if (subtitleStream.Path is null || !subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(subtitleStream.Path) || !subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { continue; } @@ -608,7 +608,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var subtitleStream in subtitleStreams) { - if (subtitleStream.Path is not null && subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrEmpty(subtitleStream.Path) && subtitleStream.Path.EndsWith(".mks", StringComparison.OrdinalIgnoreCase)) { _logger.LogDebug("Subtitle {Index} for file {InputPath} is part in an MKS file. Skipping", inputPath, subtitleStream.Index); continue;