diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index a1dc9b7d4..68faffa91 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -1,26 +1,25 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Entities; -using Microsoft.Extensions.Logging; -using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; -using System; +using System; using System.Collections.Concurrent; -using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.IO; using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Text; +using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Subtitles { @@ -110,7 +109,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (endTimeTicks.HasValue) { - var endTime = endTimeTicks.Value; + long endTime = endTimeTicks.Value; track.TrackEvents = track.TrackEvents .TakeWhile(i => i.StartPositionTicks <= endTime) @@ -150,48 +149,51 @@ namespace MediaBrowser.MediaEncoding.Subtitles var subtitle = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken) .ConfigureAwait(false); - var inputFormat = subtitle.Item2; + var inputFormat = subtitle.format; var writer = TryGetWriter(outputFormat); // Return the original if we don't have any way of converting it if (writer == null) { - return subtitle.Item1; + return subtitle.stream; } // Return the original if the same format is being requested // Character encoding was already handled in GetSubtitleStream if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase)) { - return subtitle.Item1; + return subtitle.stream; } - using (var stream = subtitle.Item1) + using (var stream = subtitle.stream) { - return ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken); + return ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken); } } - private async Task> GetSubtitleStream(MediaSourceInfo mediaSource, + private async Task<(Stream stream, string format)> GetSubtitleStream( + MediaSourceInfo mediaSource, MediaStream subtitleStream, CancellationToken cancellationToken) { - var inputFiles = new[] { mediaSource.Path }; + string[] inputFiles; - if (mediaSource.VideoType.HasValue) + if (mediaSource.VideoType.HasValue + && (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd)) { - if (mediaSource.VideoType.Value == VideoType.BluRay || mediaSource.VideoType.Value == VideoType.Dvd) - { - var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id)); - inputFiles = mediaSourceItem.GetPlayableStreamFileNames(_mediaEncoder).ToArray(); - } + var mediaSourceItem = (Video)_libraryManager.GetItemById(new Guid(mediaSource.Id)); + inputFiles = mediaSourceItem.GetPlayableStreamFileNames(_mediaEncoder); + } + else + { + inputFiles = new[] { mediaSource.Path }; } var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false); - var stream = await GetSubtitleStream(fileInfo.Item1, subtitleStream.Language, fileInfo.Item2, fileInfo.Item4, cancellationToken).ConfigureAwait(false); + var stream = await GetSubtitleStream(fileInfo.Path, subtitleStream.Language, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false); - return new Tuple(stream, fileInfo.Item3); + return (stream, fileInfo.Format); } private async Task GetSubtitleStream(string path, string language, MediaProtocol protocol, bool requiresCharset, CancellationToken cancellationToken) @@ -206,15 +208,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (!string.IsNullOrEmpty(charset)) { using (var inputStream = new MemoryStream(bytes)) + using (var reader = new StreamReader(inputStream, _textEncoding.GetEncodingFromCharset(charset))) { - using (var reader = new StreamReader(inputStream, _textEncoding.GetEncodingFromCharset(charset))) - { - var text = await reader.ReadToEndAsync().ConfigureAwait(false); + var text = await reader.ReadToEndAsync().ConfigureAwait(false); - bytes = Encoding.UTF8.GetBytes(text); + bytes = Encoding.UTF8.GetBytes(text); - return new MemoryStream(bytes); - } + return new MemoryStream(bytes); } } } @@ -222,7 +222,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles return _fileSystem.OpenRead(path); } - private async Task> GetReadableFile(string mediaPath, + private async Task GetReadableFile( + string mediaPath, string[] inputFiles, MediaProtocol protocol, MediaStream subtitleStream, @@ -237,30 +238,30 @@ namespace MediaBrowser.MediaEncoding.Subtitles string.Equals(subtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase) || string.Equals(subtitleStream.Codec, "srt", StringComparison.OrdinalIgnoreCase)) { - // Extract + // Extract outputCodec = "copy"; outputFormat = subtitleStream.Codec; } else if (string.Equals(subtitleStream.Codec, "subrip", StringComparison.OrdinalIgnoreCase)) { - // Extract + // Extract outputCodec = "copy"; outputFormat = "srt"; } else { - // Extract + // Extract outputCodec = "srt"; outputFormat = "srt"; } - // Extract + // Extract var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, "." + outputFormat); await ExtractTextSubtitle(inputFiles, protocol, subtitleStream.Index, outputCodec, outputPath, cancellationToken) .ConfigureAwait(false); - return new Tuple(outputPath, MediaProtocol.File, outputFormat, false); + return new SubtitleInfo(outputPath, MediaProtocol.File, outputFormat, false); } var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) @@ -268,15 +269,31 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (GetReader(currentFormat, false) == null) { - // Convert + // Convert var outputPath = GetSubtitleCachePath(mediaPath, protocol, subtitleStream.Index, ".srt"); await ConvertTextSubtitleToSrt(subtitleStream.Path, subtitleStream.Language, protocol, outputPath, cancellationToken).ConfigureAwait(false); - return new Tuple(outputPath, MediaProtocol.File, "srt", true); + return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true); } - return new Tuple(subtitleStream.Path, protocol, currentFormat, true); + return new SubtitleInfo(subtitleStream.Path, protocol, currentFormat, true); + } + + private struct SubtitleInfo + { + public SubtitleInfo(string path, MediaProtocol protocol, string format, bool isExternal) + { + Path = path; + Protocol = protocol; + Format = format; + IsExternal = isExternal; + } + + public string Path { get; set; } + public MediaProtocol Protocol { get; set; } + public string Format { get; set; } + public bool IsExternal { get; set; } } private ISubtitleParser GetReader(string format, bool throwIfMissing) @@ -482,7 +499,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } catch (IOException ex) { - _logger.LogError(ex, "Error deleting converted subtitle {0}", outputPath); + _logger.LogError(ex, "Error deleting converted subtitle {Path}", outputPath); } } } @@ -493,7 +510,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (failed) { - var msg = string.Format("ffmpeg subtitle conversion failed for {0}", inputPath); + var msg = string.Format("ffmpeg subtitle conversion failed for {Path}", inputPath); _logger.LogError(msg); @@ -501,7 +518,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } await SetAssFont(outputPath).ConfigureAwait(false); - _logger.LogInformation("ffmpeg subtitle conversion succeeded for {0}", inputPath); + _logger.LogInformation("ffmpeg subtitle conversion succeeded for {Path}", inputPath); } /// @@ -515,8 +532,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The cancellation token. /// Task. /// Must use inputPath list overload - private async Task ExtractTextSubtitle(string[] inputFiles, MediaProtocol protocol, int subtitleStreamIndex, - string outputCodec, string outputPath, CancellationToken cancellationToken) + private async Task ExtractTextSubtitle( + string[] inputFiles, + MediaProtocol protocol, + int subtitleStreamIndex, + string outputCodec, + string outputPath, + CancellationToken cancellationToken) { var semaphore = GetLock(outputPath); @@ -535,8 +557,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - private async Task ExtractTextSubtitleInternal(string inputPath, int subtitleStreamIndex, - string outputCodec, string outputPath, CancellationToken cancellationToken) + private async Task ExtractTextSubtitleInternal( + string inputPath, + int subtitleStreamIndex, + string outputCodec, + string outputPath, + CancellationToken cancellationToken) { if (string.IsNullOrEmpty(inputPath)) { @@ -564,7 +590,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles ErrorDialog = false }); - _logger.LogInformation("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); + _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); try { @@ -583,7 +609,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { try { - _logger.LogInformation("Killing ffmpeg subtitle extraction process"); + _logger.LogWarning("Killing ffmpeg subtitle extraction process"); process.Kill(); } @@ -605,7 +631,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - _logger.LogInformation("Deleting extracted subtitle due to failure: {0}", outputPath); + _logger.LogWarning("Deleting extracted subtitle due to failure: {Path}", outputPath); _fileSystem.DeleteFile(outputPath); } catch (FileNotFoundException) @@ -614,7 +640,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } catch (IOException ex) { - _logger.LogError(ex, "Error deleting extracted subtitle {0}", outputPath); + _logger.LogError(ex, "Error deleting extracted subtitle {Path}", outputPath); } } else if (!_fileSystem.FileExists(outputPath)) @@ -624,7 +650,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (failed) { - var msg = string.Format("ffmpeg subtitle extraction failed for {0} to {1}", inputPath, outputPath); + var msg = $"ffmpeg subtitle extraction failed for {inputPath} to {outputPath}"; _logger.LogError(msg); @@ -632,7 +658,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } else { - var msg = string.Format("ffmpeg subtitle extraction completed for {0} to {1}", inputPath, outputPath); + var msg = $"ffmpeg subtitle extraction completed for {inputPath} to {outputPath}"; _logger.LogInformation(msg); } @@ -650,19 +676,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Task. private async Task SetAssFont(string file) { - _logger.LogInformation("Setting ass font within {0}", file); + _logger.LogInformation("Setting ass font within {File}", file); string text; Encoding encoding; using (var fileStream = _fileSystem.OpenRead(file)) + using (var reader = new StreamReader(fileStream, true)) { - using (var reader = new StreamReader(fileStream, true)) - { - encoding = reader.CurrentEncoding; + encoding = reader.CurrentEncoding; - text = await reader.ReadToEndAsync().ConfigureAwait(false); - } + text = await reader.ReadToEndAsync().ConfigureAwait(false); } var newText = text.Replace(",Arial,", ",Arial Unicode MS,"); @@ -707,7 +731,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles var charset = _textEncoding.GetDetectedEncodingName(bytes, bytes.Length, language, true); - _logger.LogDebug("charset {0} detected for {1}", charset ?? "null", path); + _logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path); return charset; } @@ -716,18 +740,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles { if (protocol == MediaProtocol.Http) { - HttpRequestOptions opts = new HttpRequestOptions(); - opts.Url = path; - opts.CancellationToken = cancellationToken; - using (var file = await _httpClient.Get(opts).ConfigureAwait(false)) + HttpRequestOptions opts = new HttpRequestOptions() { - using (var memoryStream = new MemoryStream()) - { - await file.CopyToAsync(memoryStream).ConfigureAwait(false); - memoryStream.Position = 0; + Url = path, + CancellationToken = cancellationToken + }; + using (var file = await _httpClient.Get(opts).ConfigureAwait(false)) + using (var memoryStream = new MemoryStream()) + { + await file.CopyToAsync(memoryStream).ConfigureAwait(false); + memoryStream.Position = 0; - return memoryStream.ToArray(); - } + return memoryStream.ToArray(); } } if (protocol == MediaProtocol.File) @@ -737,6 +761,5 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentOutOfRangeException("protocol"); } - } }