diff options
Diffstat (limited to 'MediaBrowser.MediaEncoding/Subtitles')
9 files changed, 111 insertions, 87 deletions
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs index 0e2d70017..308b62886 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -13,6 +15,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { private readonly CultureInfo _usCulture = new CultureInfo("en-US"); + /// <inheritdoc /> public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -22,7 +25,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string line; while (reader.ReadLine() != "[Events]") - { } + { + } var headers = ParseFieldHeaders(reader.ReadLine()); @@ -35,7 +39,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles continue; } - if (line.StartsWith("[")) + if (line[0] == '[') { break; } @@ -62,7 +66,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return trackInfo; } - long GetTicks(string time) + private long GetTicks(ReadOnlySpan<char> time) { return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out var span) ? span.Ticks : 0; @@ -72,17 +76,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles { var fields = line.Substring(8).Split(',').Select(x => x.Trim()).ToList(); - var result = new Dictionary<string, int> { - {"Start", fields.IndexOf("Start")}, - {"End", fields.IndexOf("End")}, - {"Text", fields.IndexOf("Text")} - }; - return result; + return new Dictionary<string, int> + { + { "Start", fields.IndexOf("Start") }, + { "End", fields.IndexOf("End") }, + { "Text", fields.IndexOf("Text") } + }; } - /// <summary> - /// Credit: https://github.com/SubtitleEdit/subtitleedit/blob/master/src/Logic/SubtitleFormats/AdvancedSubStationAlpha.cs - /// </summary> private void RemoteNativeFormatting(SubtitleTrackEvent p) { int indexOfBegin = p.Text.IndexOf('{'); diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs index f0d107196..c0023ebf2 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System.IO; using System.Threading; using MediaBrowser.Model.MediaInfo; diff --git a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs index bf8808eb8..dca5c1e8a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs @@ -1,6 +1,9 @@ +#nullable enable +#pragma warning disable CS1591 + namespace MediaBrowser.MediaEncoding.Subtitles { - public class ParserValues + public static class ParserValues { public const string NewLine = "\r\n"; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs index 728efa788..cc35efb3f 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Generic; using System.Globalization; @@ -20,6 +22,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger = logger; } + /// <inheritdoc /> public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -55,11 +58,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles } subEvent.StartPositionTicks = GetTicks(time[0]); - var endTime = time[1]; - var idx = endTime.IndexOf(" ", StringComparison.Ordinal); + var endTime = time[1].AsSpan(); + var idx = endTime.IndexOf(' '); if (idx > 0) { - endTime = endTime.Substring(0, idx); + endTime = endTime.Slice(0, idx); } subEvent.EndPositionTicks = GetTicks(endTime); @@ -88,7 +91,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return trackInfo; } - long GetTicks(string time) + private long GetTicks(ReadOnlySpan<char> time) { return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out var span) ? span.Ticks diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs index 45b317b2e..143c010b7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs @@ -8,8 +8,12 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { + /// <summary> + /// SRT subtitle writer. + /// </summary> public class SrtWriter : ISubtitleWriter { + /// <inheritdoc /> public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) { using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true)) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs index 77033c6b4..6b7a81e6e 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs @@ -8,10 +8,11 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { /// <summary> - /// Credit to https://github.com/SubtitleEdit/subtitleedit/blob/a299dc4407a31796364cc6ad83f0d3786194ba22/src/Logic/SubtitleFormats/SubStationAlpha.cs + /// <see href="https://github.com/SubtitleEdit/subtitleedit/blob/a299dc4407a31796364cc6ad83f0d3786194ba22/src/Logic/SubtitleFormats/SubStationAlpha.cs">Credit</see>. /// </summary> public class SsaParser : ISubtitleParser { + /// <inheritdoc /> public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); @@ -45,7 +46,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles header.AppendLine(line); } - if (line.Trim().ToLowerInvariant() == "[events]") + if (string.Equals(line.Trim(), "[events]", StringComparison.OrdinalIgnoreCase)) { eventsStarted = true; } @@ -63,27 +64,27 @@ namespace MediaBrowser.MediaEncoding.Subtitles format = line.ToLowerInvariant().Substring(8).Split(','); for (int i = 0; i < format.Length; i++) { - if (format[i].Trim().ToLowerInvariant() == "layer") + if (string.Equals(format[i].Trim(), "layer", StringComparison.OrdinalIgnoreCase)) { indexLayer = i; } - else if (format[i].Trim().ToLowerInvariant() == "start") + else if (string.Equals(format[i].Trim(), "start", StringComparison.OrdinalIgnoreCase)) { indexStart = i; } - else if (format[i].Trim().ToLowerInvariant() == "end") + else if (string.Equals(format[i].Trim(), "end", StringComparison.OrdinalIgnoreCase)) { indexEnd = i; } - else if (format[i].Trim().ToLowerInvariant() == "text") + else if (string.Equals(format[i].Trim(), "text", StringComparison.OrdinalIgnoreCase)) { indexText = i; } - else if (format[i].Trim().ToLowerInvariant() == "effect") + else if (string.Equals(format[i].Trim(), "effect", StringComparison.OrdinalIgnoreCase)) { indexEffect = i; } - else if (format[i].Trim().ToLowerInvariant() == "style") + else if (string.Equals(format[i].Trim(), "style", StringComparison.OrdinalIgnoreCase)) { indexStyle = i; } @@ -178,18 +179,18 @@ 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; } - public static string GetFormattedText(string text) + private static string GetFormattedText(string text) { text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); - bool italic = false; - for (int i = 0; i < 10; i++) // just look ten times... { if (text.Contains(@"{\fn")) @@ -200,7 +201,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string fontName = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref fontName, ref extraTags, out italic); + CheckAndAddSubTags(ref fontName, ref extraTags, out bool italic); text = text.Remove(start, end - start + 1); if (italic) { @@ -231,7 +232,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string fontSize = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref fontSize, ref extraTags, out italic); + CheckAndAddSubTags(ref fontSize, ref extraTags, out bool italic); if (IsInteger(fontSize)) { text = text.Remove(start, end - start + 1); @@ -265,7 +266,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string color = text.Substring(start + 4, end - (start + 4)); string extraTags = string.Empty; - CheckAndAddSubTags(ref color, ref extraTags, out italic); + CheckAndAddSubTags(ref color, ref extraTags, out bool italic); color = color.Replace("&", string.Empty).TrimStart('H'); color = color.PadLeft(6, '0'); @@ -283,6 +284,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); } + int indexOfEndTag = text.IndexOf("{\\c}", start); if (indexOfEndTag > 0) { @@ -303,7 +305,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { string color = text.Substring(start + 5, end - (start + 5)); string extraTags = string.Empty; - CheckAndAddSubTags(ref color, ref extraTags, out italic); + CheckAndAddSubTags(ref color, ref extraTags, out bool italic); color = color.Replace("&", string.Empty).TrimStart('H'); color = color.PadLeft(6, '0'); @@ -321,6 +323,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles { text = text.Insert(start, "<font color=\"" + color + "\"" + extraTags + ">"); } + text += "</font>"; } } @@ -354,14 +357,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles } private static bool IsInteger(string s) - { - if (int.TryParse(s, out var i)) - { - return true; - } - - return false; - } + => int.TryParse(s, out _); private static int CountTagInText(string text, string tag) { diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index f1aa8ea5f..374e35b96 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -1,3 +1,5 @@ +#pragma warning disable CS1591 + using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -32,6 +34,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IHttpClient _httpClient; private readonly IMediaSourceManager _mediaSourceManager; + /// <summary> + /// The _semaphoreLocks. + /// </summary> + private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = + new ConcurrentDictionary<string, SemaphoreSlim>(); + public SubtitleEncoder( ILibraryManager libraryManager, ILogger<SubtitleEncoder> logger, @@ -172,7 +180,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles inputFiles = new[] { mediaSource.Path }; } - var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, subtitleStream, cancellationToken).ConfigureAwait(false); + var protocol = mediaSource.Protocol; + if (subtitleStream.IsExternal) + { + protocol = _mediaSourceManager.GetPathProtocol(subtitleStream.Path); + } + + var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, protocol, subtitleStream, cancellationToken).ConfigureAwait(false); var stream = await GetSubtitleStream(fileInfo.Path, fileInfo.Protocol, fileInfo.IsExternal, cancellationToken).ConfigureAwait(false); @@ -261,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)) @@ -353,25 +348,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles } /// <summary> - /// The _semaphoreLocks. - /// </summary> - private readonly ConcurrentDictionary<string, SemaphoreSlim> _semaphoreLocks = - new ConcurrentDictionary<string, SemaphoreSlim>(); - - /// <summary> /// Gets the lock. /// </summary> /// <param name="filename">The filename.</param> /// <returns>System.Object.</returns> private SemaphoreSlim GetLock(string filename) { - return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); + return _semaphoreLocks.GetOrAdd(filename, _ => new SemaphoreSlim(1, 1)); } /// <summary> /// Converts the text subtitle to SRT. /// </summary> /// <param name="inputPath">The input path.</param> + /// <param name="language">The language.</param> /// <param name="inputProtocol">The input protocol.</param> /// <param name="outputPath">The output path.</param> /// <param name="cancellationToken">The cancellation token.</param> @@ -399,14 +389,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Converts the text subtitle to SRT internal. /// </summary> /// <param name="inputPath">The input path.</param> + /// <param name="language">The language.</param> /// <param name="inputProtocol">The input protocol.</param> /// <param name="outputPath">The output path.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="ArgumentNullException"> - /// inputPath - /// or - /// outputPath + /// The <c>inputPath</c> or <c>outputPath</c> is <c>null</c>. /// </exception> private async Task ConvertTextSubtitleToSrtInternal(string inputPath, string language, MediaProtocol inputProtocol, string outputPath, CancellationToken cancellationToken) { @@ -426,9 +415,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles // FFmpeg automatically convert character encoding when it is UTF-16 // If we specify character encoding, it rejects with "do not specify a character encoding" and "Unable to recode subtitle event" - if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && (encodingParam == "UTF-16BE" || encodingParam == "UTF-16LE")) + if ((inputPath.EndsWith(".smi") || inputPath.EndsWith(".sami")) && + (encodingParam.Equals("UTF-16BE", StringComparison.OrdinalIgnoreCase) || + encodingParam.Equals("UTF-16LE", StringComparison.OrdinalIgnoreCase))) { - encodingParam = ""; + encodingParam = string.Empty; } else if (!string.IsNullOrEmpty(encodingParam)) { @@ -530,7 +521,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// <param name="outputPath">The output path.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> - /// <exception cref="ArgumentException">Must use inputPath list overload</exception> + /// <exception cref="ArgumentException">Must use inputPath list overload.</exception> private async Task ExtractTextSubtitle( string[] inputFiles, MediaProtocol protocol, @@ -721,19 +712,19 @@ namespace MediaBrowser.MediaEncoding.Subtitles var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - var filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam).GetMD5() + outputSubtitleExtension; + ReadOnlySpan<char> filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture) + ticksParam).GetMD5() + outputSubtitleExtension; - var prefix = filename.Substring(0, 1); + var prefix = filename.Slice(0, 1); - return Path.Combine(SubtitleCachePath, prefix, filename); + return Path.Join(SubtitleCachePath, prefix, filename); } else { - var filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension; + ReadOnlySpan<char> filename = (mediaPath + "_" + subtitleStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5() + outputSubtitleExtension; - var prefix = filename.Substring(0, 1); + var prefix = filename.Slice(0, 1); - return Path.Combine(SubtitleCachePath, prefix, filename); + return Path.Join(SubtitleCachePath, prefix, filename); } } @@ -749,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); @@ -780,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; } + } } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs index 7d3e18578..e5c785bc5 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs @@ -6,8 +6,12 @@ using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles { + /// <summary> + /// TTML subtitle writer. + /// </summary> public class TtmlWriter : ISubtitleWriter { + /// <inheritdoc /> public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken) { // Example: https://github.com/zmalltalker/ttml2vtt/blob/master/data/sample.xml @@ -36,9 +40,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = Regex.Replace(text, @"\\n", "<br/>", RegexOptions.IgnoreCase); - writer.WriteLine("<p begin=\"{0}\" dur=\"{1}\">{2}</p>", + writer.WriteLine( + "<p begin=\"{0}\" dur=\"{1}\">{2}</p>", trackEvent.StartPositionTicks, - (trackEvent.EndPositionTicks - trackEvent.StartPositionTicks), + trackEvent.EndPositionTicks - trackEvent.StartPositionTicks, text); } diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs index de35acbba..ad32cb794 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs @@ -47,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase); writer.WriteLine(text); - writer.WriteLine(string.Empty); + writer.WriteLine(); } } } |
