diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs index e040286ab9..4a54b677dd 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Linq; using BDInfo.IO; @@ -5,7 +7,7 @@ using MediaBrowser.Model.IO; namespace MediaBrowser.MediaEncoding.BdInfo { - class BdInfoDirectoryInfo : IDirectoryInfo + public class BdInfoDirectoryInfo : IDirectoryInfo { private readonly IFileSystem _fileSystem = null; @@ -43,25 +45,32 @@ namespace MediaBrowser.MediaEncoding.BdInfo public IDirectoryInfo[] GetDirectories() { - return Array.ConvertAll(_fileSystem.GetDirectories(_impl.FullName).ToArray(), + return Array.ConvertAll( + _fileSystem.GetDirectories(_impl.FullName).ToArray(), x => new BdInfoDirectoryInfo(_fileSystem, x)); } public IFileInfo[] GetFiles() { - return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName).ToArray(), + return Array.ConvertAll( + _fileSystem.GetFiles(_impl.FullName).ToArray(), x => new BdInfoFileInfo(x)); } public IFileInfo[] GetFiles(string searchPattern) { - return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(), + return Array.ConvertAll( + _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(), x => new BdInfoFileInfo(x)); } public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption) { - return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, + return Array.ConvertAll( + _fileSystem.GetFiles( + _impl.FullName, + new[] { searchPattern }, + false, searchOption.HasFlag(System.IO.SearchOption.AllDirectories)).ToArray(), x => new BdInfoFileInfo(x)); } diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs index a6ff4f7678..0a8af8e9c8 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs @@ -1,11 +1,18 @@ +#pragma warning disable CS1591 + using System.IO; using MediaBrowser.Model.IO; namespace MediaBrowser.MediaEncoding.BdInfo { - class BdInfoFileInfo : BDInfo.IO.IFileInfo + public class BdInfoFileInfo : BDInfo.IO.IFileInfo { - FileSystemMetadata _impl = null; + private FileSystemMetadata _impl = null; + + public BdInfoFileInfo(FileSystemMetadata impl) + { + _impl = impl; + } public string Name => _impl.Name; @@ -17,14 +24,10 @@ namespace MediaBrowser.MediaEncoding.BdInfo public bool IsDir => _impl.IsDirectory; - public BdInfoFileInfo(FileSystemMetadata impl) - { - _impl = impl; - } - public System.IO.Stream OpenRead() { - return new FileStream(FullName, + return new FileStream( + FullName, FileMode.Open, FileAccess.Read, FileShare.Read); diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs index fea7ee6fed..f81a337dbb 100644 --- a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs @@ -1,11 +1,7 @@ #pragma warning disable CS1591 -using System; using System.Collections.Generic; -using System.Globalization; -using System.IO; using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Configuration; namespace MediaBrowser.MediaEncoding.Configuration { @@ -19,32 +15,4 @@ namespace MediaBrowser.MediaEncoding.Configuration }; } } - - public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration - { - public EncodingConfigurationStore() - { - ConfigurationType = typeof(EncodingOptions); - Key = "encoding"; - } - - public void Validate(object oldConfig, object newConfig) - { - var newPath = ((EncodingOptions)newConfig).TranscodingTempPath; - - if (!string.IsNullOrWhiteSpace(newPath) - && !string.Equals(((EncodingOptions)oldConfig).TranscodingTempPath, newPath, StringComparison.Ordinal)) - { - // Validate - if (!Directory.Exists(newPath)) - { - throw new DirectoryNotFoundException( - string.Format( - CultureInfo.InvariantCulture, - "{0} does not exist.", - newPath)); - } - } - } - } } diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationStore.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationStore.cs new file mode 100644 index 0000000000..2f158157e8 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationStore.cs @@ -0,0 +1,38 @@ +#pragma warning disable CS1591 + +using System; +using System.Globalization; +using System.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; + +namespace MediaBrowser.MediaEncoding.Configuration +{ + public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration + { + public EncodingConfigurationStore() + { + ConfigurationType = typeof(EncodingOptions); + Key = "encoding"; + } + + public void Validate(object oldConfig, object newConfig) + { + var newPath = ((EncodingOptions)newConfig).TranscodingTempPath; + + if (!string.IsNullOrWhiteSpace(newPath) + && !string.Equals(((EncodingOptions)oldConfig).TranscodingTempPath, newPath, StringComparison.Ordinal)) + { + // Validate + if (!Directory.Exists(newPath)) + { + throw new DirectoryNotFoundException( + string.Format( + CultureInfo.InvariantCulture, + "{0} does not exist.", + newPath)); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs index 1ac56f845f..75123a843e 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { private const string DefaultEncoderPath = "ffmpeg"; - private static readonly string[] requiredDecoders = new[] + private static readonly string[] _requiredDecoders = new[] { "h264", "hevc", @@ -57,7 +57,7 @@ namespace MediaBrowser.MediaEncoding.Encoder "vc1_opencl" }; - private static readonly string[] requiredEncoders = new[] + private static readonly string[] _requiredEncoders = new[] { "libx264", "libx265", @@ -112,6 +112,12 @@ namespace MediaBrowser.MediaEncoding.Encoder _encoderPath = encoderPath; } + private enum Codec + { + Encoder, + Decoder + } + public static Version MinVersion { get; } = new Version(4, 0); public static Version MaxVersion { get; } = null; @@ -195,8 +201,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// If that fails then we use one of the main libraries to determine if it's new/older than the latest /// we have stored. /// - /// - /// + /// The output from "ffmpeg -version". + /// The FFmpeg version. internal static Version GetFFmpegVersion(string output) { // For pre-built binaries the FFmpeg version should be mentioned at the very start of the output @@ -218,10 +224,10 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Grabs the library names and major.minor version numbers from the 'ffmpeg -version' output - /// and condenses them on to one line. Output format is "name1=major.minor,name2=major.minor,etc." + /// and condenses them on to one line. Output format is "name1=major.minor,name2=major.minor,etc.". /// - /// - /// + /// The 'ffmpeg -version' output. + /// The library names and major.minor version numbers. private static string GetLibrariesVersionString(string output) { var rc = new StringBuilder(144); @@ -241,12 +247,6 @@ namespace MediaBrowser.MediaEncoding.Encoder return rc.Length == 0 ? null : rc.ToString(); } - private enum Codec - { - Encoder, - Decoder - } - private IEnumerable GetHwaccelTypes() { string output = null; @@ -264,7 +264,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return Enumerable.Empty(); } - var found = output.Split(new char[] {'\r','\n'}, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); + var found = output.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Skip(1).Distinct().ToList(); _logger.LogInformation("Available hwaccel types: {Types}", found); return found; @@ -288,7 +288,7 @@ namespace MediaBrowser.MediaEncoding.Encoder return Enumerable.Empty(); } - var required = codec == Codec.Encoder ? requiredEncoders : requiredDecoders; + var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders; var found = Regex .Matches(output, @"^\s\S{6}\s(?[\w|-]+)\s+.+$", RegexOptions.Multiline) diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 0f0ae877fb..62e6e8e3c9 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -21,9 +22,8 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.System; -using Microsoft.Extensions.Logging; -using System.Diagnostics; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; namespace MediaBrowser.MediaEncoding.Encoder { @@ -37,6 +37,11 @@ namespace MediaBrowser.MediaEncoding.Encoder /// internal const int DefaultImageExtractionTimeout = 5000; + /// + /// The us culture. + /// + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly ILogger _logger; private readonly IServerConfigurationManager _configurationManager; private readonly IFileSystem _fileSystem; @@ -49,6 +54,10 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly object _runningProcessesLock = new object(); private readonly List _runningProcesses = new List(); + private List _encoders = new List(); + private List _decoders = new List(); + private List _hwaccels = new List(); + private string _ffmpegPath = string.Empty; private string _ffprobePath; @@ -79,7 +88,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Run at startup or if the user removes a Custom path from transcode page. /// Sets global variables FFmpegPath. - /// Precedence is: Config > CLI > $PATH + /// Precedence is: Config > CLI > $PATH. /// public void SetFFmpegPath() { @@ -124,8 +133,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// Triggered from the Settings > Transcoding UI page when users submits Custom FFmpeg path to use. /// Only write the new path to xml if it exists. Do not perform validation checks on ffmpeg here. /// - /// - /// + /// The path. + /// The path type. public void UpdateEncoderPath(string path, string pathType) { string newPath; @@ -170,8 +179,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// If checks pass, global variable FFmpegPath and EncoderLocation are updated. /// /// FQPN to test. - /// Location (External, Custom, System) of tool - /// + /// Location (External, Custom, System) of tool. + /// true if the version validation succeeded; otherwise, false. private bool ValidatePath(string path, FFmpegLocation location) { bool rc = false; @@ -223,8 +232,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// Search the system $PATH environment variable looking for given filename. /// - /// - /// + /// The filename. + /// The full path to the file. private string ExistsOnSystemPath(string fileName) { var inJellyfinPath = GetEncoderPathFromDirectory(AppContext.BaseDirectory, fileName, recursive: true); @@ -248,25 +257,19 @@ namespace MediaBrowser.MediaEncoding.Encoder return null; } - private List _encoders = new List(); public void SetAvailableEncoders(IEnumerable list) { _encoders = list.ToList(); - // _logger.Info("Supported encoders: {0}", string.Join(",", list.ToArray())); } - private List _decoders = new List(); public void SetAvailableDecoders(IEnumerable list) { _decoders = list.ToList(); - // _logger.Info("Supported decoders: {0}", string.Join(",", list.ToArray())); } - private List _hwaccels = new List(); public void SetAvailableHwaccels(IEnumerable list) { _hwaccels = list.ToList(); - //_logger.Info("Supported hwaccels: {0}", string.Join(",", list.ToArray())); } public bool SupportsEncoder(string encoder) @@ -334,8 +337,16 @@ namespace MediaBrowser.MediaEncoding.Encoder var forceEnableLogging = request.MediaSource.Protocol != MediaProtocol.File; - return GetMediaInfoInternal(GetInputArgument(inputFiles, request.MediaSource.Protocol), request.MediaSource.Path, request.MediaSource.Protocol, extractChapters, - probeSize, request.MediaType == DlnaProfileType.Audio, request.MediaSource.VideoType, forceEnableLogging, cancellationToken); + return GetMediaInfoInternal( + GetInputArgument(inputFiles, request.MediaSource.Protocol), + request.MediaSource.Path, + request.MediaSource.Protocol, + extractChapters, + probeSize, + request.MediaType == DlnaProfileType.Audio, + request.MediaSource.VideoType, + forceEnableLogging, + cancellationToken); } /// @@ -344,7 +355,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// The input files. /// The protocol. /// System.String. - /// Unrecognized InputType + /// Unrecognized InputType. public string GetInputArgument(IReadOnlyList inputFiles, MediaProtocol protocol) => EncodingUtils.GetInputArgument(inputFiles, protocol); @@ -352,7 +363,8 @@ namespace MediaBrowser.MediaEncoding.Encoder /// Gets the media info internal. /// /// Task{MediaInfoResult}. - private async Task GetMediaInfoInternal(string inputPath, + private async Task GetMediaInfoInternal( + string inputPath, string primaryPath, MediaProtocol protocol, bool extractChapters, @@ -380,7 +392,6 @@ namespace MediaBrowser.MediaEncoding.Encoder FileName = _ffprobePath, Arguments = args, - WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false, }, @@ -441,11 +452,6 @@ namespace MediaBrowser.MediaEncoding.Encoder } } - /// - /// The us culture. - /// - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public Task ExtractAudioImage(string path, int? imageStreamIndex, CancellationToken cancellationToken) { return ExtractImage(new[] { path }, null, null, imageStreamIndex, MediaProtocol.File, true, null, null, cancellationToken); @@ -461,8 +467,16 @@ namespace MediaBrowser.MediaEncoding.Encoder return ExtractImage(inputFiles, container, imageStream, imageStreamIndex, protocol, false, null, null, cancellationToken); } - private async Task ExtractImage(string[] inputFiles, string container, MediaStream videoStream, int? imageStreamIndex, MediaProtocol protocol, bool isAudio, - Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken) + private async Task ExtractImage( + string[] inputFiles, + string container, + MediaStream videoStream, + int? imageStreamIndex, + MediaProtocol protocol, + bool isAudio, + Video3DFormat? threedFormat, + TimeSpan? offset, + CancellationToken cancellationToken) { var inputArgument = GetInputArgument(inputFiles, protocol); @@ -647,7 +661,7 @@ namespace MediaBrowser.MediaEncoding.Encoder public string GetTimeParameter(TimeSpan time) { - return time.ToString(@"hh\:mm\:ss\.fff", UsCulture); + return time.ToString(@"hh\:mm\:ss\.fff", _usCulture); } public async Task ExtractVideoImagesOnInterval( @@ -664,11 +678,11 @@ namespace MediaBrowser.MediaEncoding.Encoder { var inputArgument = GetInputArgument(inputFiles, protocol); - var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(UsCulture); + var vf = "fps=fps=1/" + interval.TotalSeconds.ToString(_usCulture); if (maxWidth.HasValue) { - var maxWidthParam = maxWidth.Value.ToString(UsCulture); + var maxWidthParam = maxWidth.Value.ToString(_usCulture); vf += string.Format(",scale=min(iw\\,{0}):trunc(ow/dar/2)*2", maxWidthParam); } diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index dab5f866cf..017f917e27 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -28,4 +28,16 @@ + + ../jellyfin.ruleset + + + + + + + + + + diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 8aaaf4a09b..19e3bd8e60 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -18,10 +18,19 @@ namespace MediaBrowser.MediaEncoding.Probing { public class ProbeResultNormalizer { + // When extracting subtitles, the maximum length to consider (to avoid invalid filenames) + private const int MaxSubtitleDescriptionExtractionLength = 100; + + private const string ArtistReplaceValue = " | "; + + private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' }; + private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly ILogger _logger; private readonly ILocalizationManager _localization; + private List _splitWhiteList = null; + public ProbeResultNormalizer(ILogger logger, ILocalizationManager localization) { _logger = logger; @@ -370,7 +379,6 @@ namespace MediaBrowser.MediaEncoding.Probing private List ReadValueArray(XmlReader reader) { - var pairs = new List(); reader.MoveToContent(); @@ -951,50 +959,46 @@ namespace MediaBrowser.MediaEncoding.Probing private void SetAudioInfoFromTags(MediaInfo audio, Dictionary tags) { + var peoples = new List(); var composer = FFProbeHelpers.GetDictionaryValue(tags, "composer"); if (!string.IsNullOrWhiteSpace(composer)) { - var peoples = new List(); foreach (var person in Split(composer, false)) { peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Composer }); } - - audio.People = peoples.ToArray(); } - // var conductor = FFProbeHelpers.GetDictionaryValue(tags, "conductor"); - // if (!string.IsNullOrWhiteSpace(conductor)) - //{ - // foreach (var person in Split(conductor, false)) - // { - // audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Conductor }); - // } - //} + var conductor = FFProbeHelpers.GetDictionaryValue(tags, "conductor"); + if (!string.IsNullOrWhiteSpace(conductor)) + { + foreach (var person in Split(conductor, false)) + { + peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Conductor }); + } + } - // var lyricist = FFProbeHelpers.GetDictionaryValue(tags, "lyricist"); - // if (!string.IsNullOrWhiteSpace(lyricist)) - //{ - // foreach (var person in Split(lyricist, false)) - // { - // audio.People.Add(new BaseItemPerson { Name = person, Type = PersonType.Lyricist }); - // } - //} + var lyricist = FFProbeHelpers.GetDictionaryValue(tags, "lyricist"); + if (!string.IsNullOrWhiteSpace(lyricist)) + { + foreach (var person in Split(lyricist, false)) + { + peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Lyricist }); + } + } // Check for writer some music is tagged that way as alternative to composer/lyricist var writer = FFProbeHelpers.GetDictionaryValue(tags, "writer"); if (!string.IsNullOrWhiteSpace(writer)) { - var peoples = new List(); foreach (var person in Split(writer, false)) { peoples.Add(new BaseItemPerson { Name = person, Type = PersonType.Writer }); } - - audio.People = peoples.ToArray(); } + audio.People = peoples.ToArray(); audio.Album = FFProbeHelpers.GetDictionaryValue(tags, "album"); var artists = FFProbeHelpers.GetDictionaryValue(tags, "artists"); @@ -1119,8 +1123,6 @@ namespace MediaBrowser.MediaEncoding.Probing .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } - private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' }; - /// /// Splits the specified val. /// @@ -1140,8 +1142,6 @@ namespace MediaBrowser.MediaEncoding.Probing .Select(i => i.Trim()); } - private const string ArtistReplaceValue = " | "; - private IEnumerable SplitArtists(string val, char[] delimiters, bool splitFeaturing) { if (splitFeaturing) @@ -1171,9 +1171,6 @@ namespace MediaBrowser.MediaEncoding.Probing return artistsFound; } - - private List _splitWhiteList = null; - private IEnumerable GetSplitWhitelist() { if (_splitWhiteList == null) @@ -1250,7 +1247,7 @@ namespace MediaBrowser.MediaEncoding.Probing } /// - /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3' + /// Gets the disc number, which is sometimes can be in the form of '1', or '1/3'. /// /// The tags. /// Name of the tag. @@ -1296,8 +1293,6 @@ namespace MediaBrowser.MediaEncoding.Probing return info; } - private const int MaxSubtitleDescriptionExtractionLength = 100; // When extracting subtitles, the maximum length to consider (to avoid invalid filenames) - private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data) { if (data.Format == null || data.Format.Tags == null) @@ -1382,8 +1377,8 @@ namespace MediaBrowser.MediaEncoding.Probing if (subtitle.Contains('/', StringComparison.Ordinal)) // It contains a episode number and season number { string[] numbers = subtitle.Split(' '); - video.IndexNumber = int.Parse(numbers[0].Replace(".", "").Split('/')[0]); - int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", "").Split('/')[1]); + video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0]); + int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1]); description = string.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it } diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index e6e21756ad..308b62886c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -25,7 +25,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string line; while (reader.ReadLine() != "[Events]") - { } + { + } var headers = ParseFieldHeaders(reader.ReadLine()); @@ -75,17 +76,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles { var fields = line.Substring(8).Split(',').Select(x => x.Trim()).ToList(); - var result = new Dictionary { - {"Start", fields.IndexOf("Start")}, - {"End", fields.IndexOf("End")}, - {"Text", fields.IndexOf("Text")} - }; - return result; + return new Dictionary + { + { "Start", fields.IndexOf("Start") }, + { "End", fields.IndexOf("End") }, + { "Text", fields.IndexOf("Text") } + }; } - /// - /// Credit: https://github.com/SubtitleEdit/subtitleedit/blob/master/src/Logic/SubtitleFormats/AdvancedSubStationAlpha.cs - /// private void RemoteNativeFormatting(SubtitleTrackEvent p) { int indexOfBegin = p.Text.IndexOf('{'); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index bd330f568b..6b7a81e6eb 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -8,7 +8,7 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { /// - /// Credit to https://github.com/SubtitleEdit/subtitleedit/blob/a299dc4407a31796364cc6ad83f0d3786194ba22/src/Logic/SubtitleFormats/SubStationAlpha.cs + /// Credit. /// public class SsaParser : ISubtitleParser { @@ -179,10 +179,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { // h:mm:ss.cc string[] timeCode = time.Split(':', '.'); - return new TimeSpan(0, int.Parse(timeCode[0]), - int.Parse(timeCode[1]), - int.Parse(timeCode[2]), - int.Parse(timeCode[3]) * 10).Ticks; + return new TimeSpan( + 0, + int.Parse(timeCode[0]), + int.Parse(timeCode[1]), + int.Parse(timeCode[2]), + int.Parse(timeCode[3]) * 10).Ticks; } private static string GetFormattedText(string text) @@ -282,6 +284,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { text = text.Insert(start, ""); } + int indexOfEndTag = text.IndexOf("{\\c}", start); if (indexOfEndTag > 0) { @@ -320,6 +323,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { text = text.Insert(start, ""); } + text += ""; } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7c0697279c..374e35b969 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -34,6 +34,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IHttpClient _httpClient; private readonly IMediaSourceManager _mediaSourceManager; + /// + /// The _semaphoreLocks. + /// + private readonly ConcurrentDictionary _semaphoreLocks = + new ConcurrentDictionary(); + public SubtitleEncoder( ILibraryManager libraryManager, ILogger logger, @@ -269,25 +275,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles 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) { if (string.IsNullOrEmpty(format)) @@ -360,12 +347,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentException("Unsupported format: " + format); } - /// - /// The _semaphoreLocks. - /// - private readonly ConcurrentDictionary _semaphoreLocks = - new ConcurrentDictionary(); - /// /// Gets the lock. /// @@ -414,7 +395,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The cancellation token. /// Task. /// - /// The inputPath or outputPath is null + /// The inputPath or outputPath is null. /// private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) { @@ -438,7 +419,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles (encodingParam.Equals("UTF-16BE", StringComparison.OrdinalIgnoreCase) || encodingParam.Equals("UTF-16LE", StringComparison.OrdinalIgnoreCase))) { - encodingParam = ""; + encodingParam = string.Empty; } else if (!string.IsNullOrEmpty(encodingParam)) { @@ -540,7 +521,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The output path. /// The cancellation token. /// Task. - /// Must use inputPath list overload + /// Must use inputPath list overload. private async Task ExtractTextSubtitle( string[] inputFiles, MediaProtocol protocol, @@ -759,7 +740,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles && (string.Equals(charset, "utf-16le", StringComparison.OrdinalIgnoreCase) || string.Equals(charset, "utf-16be", StringComparison.OrdinalIgnoreCase))) { - charset = ""; + charset = string.Empty; } _logger.LogDebug("charset {0} detected for {Path}", charset ?? "null", path); @@ -790,5 +771,24 @@ namespace MediaBrowser.MediaEncoding.Subtitles throw new ArgumentOutOfRangeException(nameof(protocol)); } } + + 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; } + } } }