Przeglądaj źródła

Review usage of string.Substring (part 1)

Reduced allocations by replacing string.Substring with ReadOnlySpan<char>.Slice
Bond_009 4 lat temu
rodzic
commit
febb6bced6
25 zmienionych plików z 124 dodań i 99 usunięć
  1. 2 1
      Emby.Dlna/Didl/DidlBuilder.cs
  2. 3 3
      Emby.Dlna/DlnaManager.cs
  3. 7 7
      Emby.Drawing/ImageProcessor.cs
  4. 1 1
      Emby.Naming/TV/SeasonPathParser.cs
  5. 2 2
      Emby.Server.Implementations/Library/LibraryManager.cs
  6. 2 1
      Emby.Server.Implementations/Library/MediaSourceManager.cs
  7. 2 2
      Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
  8. 7 2
      Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
  9. 12 13
      Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
  10. 4 4
      Emby.Server.Implementations/Localization/LocalizationManager.cs
  11. 1 1
      Emby.Server.Implementations/Networking/NetworkManager.cs
  12. 7 1
      Emby.Server.Implementations/Services/ServiceExec.cs
  13. 10 7
      Emby.Server.Implementations/Services/ServiceHandler.cs
  14. 1 1
      Emby.Server.Implementations/Services/ServicePath.cs
  15. 1 1
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  16. 9 7
      MediaBrowser.Controller/Entities/BaseItem.cs
  17. 11 12
      MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
  18. 2 2
      MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
  19. 4 1
      MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs
  20. 7 4
      MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
  21. 4 0
      MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs
  22. 14 22
      MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
  23. 3 1
      MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
  24. 7 2
      MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
  25. 1 1
      MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs

+ 2 - 1
Emby.Dlna/Didl/DidlBuilder.cs

@@ -364,7 +364,8 @@ namespace Emby.Dlna.Didl
                 writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture));
                 writer.WriteAttributeString("bitrate", totalBitrate.Value.ToString(_usCulture));
             }
             }
 
 
-            var mediaProfile = _profile.GetVideoMediaProfile(streamInfo.Container,
+            var mediaProfile = _profile.GetVideoMediaProfile(
+                streamInfo.Container,
                 streamInfo.TargetAudioCodec.FirstOrDefault(),
                 streamInfo.TargetAudioCodec.FirstOrDefault(),
                 streamInfo.TargetVideoCodec.FirstOrDefault(),
                 streamInfo.TargetVideoCodec.FirstOrDefault(),
                 streamInfo.TargetAudioBitrate,
                 streamInfo.TargetAudioBitrate,

+ 3 - 3
Emby.Dlna/DlnaManager.cs

@@ -387,7 +387,7 @@ namespace Emby.Dlna
 
 
             foreach (var name in _assembly.GetManifestResourceNames())
             foreach (var name in _assembly.GetManifestResourceNames())
             {
             {
-                if (!name.StartsWith(namespaceName))
+                if (!name.StartsWith(namespaceName, StringComparison.Ordinal))
                 {
                 {
                     continue;
                     continue;
                 }
                 }
@@ -406,7 +406,7 @@ namespace Emby.Dlna
 
 
                         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                         using (var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
                         {
                         {
-                            await stream.CopyToAsync(fileStream);
+                            await stream.CopyToAsync(fileStream).ConfigureAwait(false);
                         }
                         }
                     }
                     }
                 }
                 }
@@ -509,7 +509,7 @@ namespace Emby.Dlna
             return _jsonSerializer.DeserializeFromString<DeviceProfile>(json);
             return _jsonSerializer.DeserializeFromString<DeviceProfile>(json);
         }
         }
 
 
-        class InternalProfileInfo
+        private class InternalProfileInfo
         {
         {
             internal DeviceProfileInfo Info { get; set; }
             internal DeviceProfileInfo Info { get; set; }
 
 

+ 7 - 7
Emby.Drawing/ImageProcessor.cs

@@ -448,21 +448,21 @@ namespace Emby.Drawing
         /// or
         /// or
         /// filename.
         /// filename.
         /// </exception>
         /// </exception>
-        public string GetCachePath(string path, string filename)
+        public string GetCachePath(ReadOnlySpan<char> path, ReadOnlySpan<char> filename)
         {
         {
-            if (string.IsNullOrEmpty(path))
+            if (path.IsEmpty)
             {
             {
-                throw new ArgumentNullException(nameof(path));
+                throw new ArgumentException("Path can't be empty.", nameof(path));
             }
             }
 
 
-            if (string.IsNullOrEmpty(filename))
+            if (path.IsEmpty)
             {
             {
-                throw new ArgumentNullException(nameof(filename));
+                throw new ArgumentException("Filename can't be empty.", nameof(filename));
             }
             }
 
 
-            var prefix = filename.Substring(0, 1);
+            var prefix = filename.Slice(0, 1);
 
 
-            return Path.Combine(path, prefix, filename);
+            return Path.Join(path, prefix, filename);
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />

+ 1 - 1
Emby.Naming/TV/SeasonPathParser.cs

@@ -77,7 +77,7 @@ namespace Emby.Naming.TV
 
 
             if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase))
             if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase))
             {
             {
-                var testFilename = filename.Substring(1);
+                var testFilename = filename.AsSpan().Slice(1);
 
 
                 if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 {
                 {

+ 2 - 2
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -511,8 +511,8 @@ namespace Emby.Server.Implementations.Library
             {
             {
                 // Try to normalize paths located underneath program-data in an attempt to make them more portable
                 // Try to normalize paths located underneath program-data in an attempt to make them more portable
                 key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
                 key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
-                    .TrimStart(new[] { '/', '\\' })
-                    .Replace("/", "\\");
+                    .TrimStart('/', '\\')
+                    .Replace('/', '\\');
             }
             }
 
 
             if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)
             if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)

+ 2 - 1
Emby.Server.Implementations/Library/MediaSourceManager.cs

@@ -869,7 +869,7 @@ namespace Emby.Server.Implementations.Library
 
 
             var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase));
             var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N", CultureInfo.InvariantCulture), keys[0], StringComparison.OrdinalIgnoreCase));
 
 
-            var splitIndex = key.IndexOf(LiveStreamIdDelimeter);
+            var splitIndex = key.IndexOf(LiveStreamIdDelimeter, StringComparison.Ordinal);
             var keyId = key.Substring(splitIndex + 1);
             var keyId = key.Substring(splitIndex + 1);
 
 
             return new Tuple<IMediaSourceProvider, string>(provider, keyId);
             return new Tuple<IMediaSourceProvider, string>(provider, keyId);
@@ -881,6 +881,7 @@ namespace Emby.Server.Implementations.Library
         public void Dispose()
         public void Dispose()
         {
         {
             Dispose(true);
             Dispose(true);
+            GC.SuppressFinalize(this);
         }
         }
 
 
         private readonly object _disposeLock = new object();
         private readonly object _disposeLock = new object();

+ 2 - 2
Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs

@@ -461,7 +461,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
         private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
         private async Task<List<ScheduleDirect.ShowImages>> GetImageForPrograms(
             ListingsProviderInfo info,
             ListingsProviderInfo info,
             List<string> programIds,
             List<string> programIds,
-           CancellationToken cancellationToken)
+            CancellationToken cancellationToken)
         {
         {
             if (programIds.Count == 0)
             if (programIds.Count == 0)
             {
             {
@@ -474,7 +474,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
             {
             {
                 var imageId = i.Substring(0, 10);
                 var imageId = i.Substring(0, 10);
 
 
-                if (!imageIdString.Contains(imageId))
+                if (!imageIdString.Contains(imageId, StringComparison.Ordinal))
                 {
                 {
                     imageIdString += "\"" + imageId + "\",";
                     imageIdString += "\"" + imageId + "\",";
                 }
                 }

+ 7 - 2
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

@@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
                 while (!sr.EndOfStream)
                 while (!sr.EndOfStream)
                 {
                 {
                     string line = StripXML(sr.ReadLine());
                     string line = StripXML(sr.ReadLine());
-                    if (line.Contains("Channel"))
+                    if (line.Contains("Channel", StringComparison.Ordinal))
                     {
                     {
                         LiveTvTunerStatus status;
                         LiveTvTunerStatus status;
                         var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
                         var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
@@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
 
         private static string StripXML(string source)
         private static string StripXML(string source)
         {
         {
+            if (string.IsNullOrEmpty(source))
+            {
+                return string.Empty;
+            }
+
             char[] buffer = new char[source.Length];
             char[] buffer = new char[source.Length];
             int bufferIndex = 0;
             int bufferIndex = 0;
             bool inside = false;
             bool inside = false;
@@ -270,7 +275,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
 
 
                 for (int i = 0; i < model.TunerCount; ++i)
                 for (int i = 0; i < model.TunerCount; ++i)
                 {
                 {
-                    var name = string.Format("Tuner {0}", i + 1);
+                    var name = string.Format(CultureInfo.InvariantCulture, "Tuner {0}", i + 1);
                     var currentChannel = "none"; // @todo Get current channel and map back to Station Id
                     var currentChannel = "none"; // @todo Get current channel and map back to Station Id
                     var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false);
                     var isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false);
                     var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;
                     var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;

+ 12 - 13
Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

@@ -158,15 +158,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
         private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
         private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
         {
         {
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
             var nameParts = extInf.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
-            var nameInExtInf = nameParts.Length > 1 ? nameParts[nameParts.Length - 1].Trim() : null;
+            var nameInExtInf = nameParts.Length > 1 ? nameParts[^1].AsSpan().Trim() : ReadOnlySpan<char>.Empty;
 
 
             string numberString = null;
             string numberString = null;
             string attributeValue;
             string attributeValue;
-            double doubleValue;
 
 
             if (attributes.TryGetValue("tvg-chno", out attributeValue))
             if (attributes.TryGetValue("tvg-chno", out attributeValue))
             {
             {
-                if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+                if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
                 {
                 {
                     numberString = attributeValue;
                     numberString = attributeValue;
                 }
                 }
@@ -176,36 +175,36 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
             {
             {
                 if (attributes.TryGetValue("tvg-id", out attributeValue))
                 if (attributes.TryGetValue("tvg-id", out attributeValue))
                 {
                 {
-                    if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+                    if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
                     {
                     {
                         numberString = attributeValue;
                         numberString = attributeValue;
                     }
                     }
                     else if (attributes.TryGetValue("channel-id", out attributeValue))
                     else if (attributes.TryGetValue("channel-id", out attributeValue))
                     {
                     {
-                        if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out doubleValue))
+                        if (double.TryParse(attributeValue, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
                         {
                         {
                             numberString = attributeValue;
                             numberString = attributeValue;
                         }
                         }
                     }
                     }
                 }
                 }
 
 
-                if (String.IsNullOrWhiteSpace(numberString))
+                if (string.IsNullOrWhiteSpace(numberString))
                 {
                 {
                     // Using this as a fallback now as this leads to Problems with channels like "5 USA"
                     // Using this as a fallback now as this leads to Problems with channels like "5 USA"
                     // where 5 isnt ment to be the channel number
                     // where 5 isnt ment to be the channel number
                     // Check for channel number with the format from SatIp
                     // Check for channel number with the format from SatIp
                     // #EXTINF:0,84. VOX Schweiz
                     // #EXTINF:0,84. VOX Schweiz
                     // #EXTINF:0,84.0 - VOX Schweiz
                     // #EXTINF:0,84.0 - VOX Schweiz
-                    if (!string.IsNullOrWhiteSpace(nameInExtInf))
+                    if (!nameInExtInf.IsEmpty && !nameInExtInf.IsWhiteSpace())
                     {
                     {
                         var numberIndex = nameInExtInf.IndexOf(' ');
                         var numberIndex = nameInExtInf.IndexOf(' ');
                         if (numberIndex > 0)
                         if (numberIndex > 0)
                         {
                         {
-                            var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' });
+                            var numberPart = nameInExtInf.Slice(0, numberIndex).Trim(new[] { ' ', '.' });
 
 
-                            if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
+                            if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
                             {
                             {
-                                numberString = numberPart;
+                                numberString = numberPart.ToString();
                             }
                             }
                         }
                         }
                     }
                     }
@@ -231,7 +230,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 {
                 {
                     try
                     try
                     {
                     {
-                        numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
+                        numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]);
 
 
                         if (!IsValidChannelNumber(numberString))
                         if (!IsValidChannelNumber(numberString))
                         {
                         {
@@ -258,7 +257,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 return false;
                 return false;
             }
             }
 
 
-            if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
+            if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
             {
             {
                 return false;
                 return false;
             }
             }
@@ -281,7 +280,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
                 {
                 {
                     var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' });
                     var numberPart = nameInExtInf.Substring(0, numberIndex).Trim(new[] { ' ', '.' });
 
 
-                    if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
+                    if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
                     {
                     {
                         // channel.Number = number.ToString();
                         // channel.Number = number.ToString();
                         nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });
                         nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });

+ 4 - 4
Emby.Server.Implementations/Localization/LocalizationManager.cs

@@ -247,7 +247,7 @@ namespace Emby.Server.Implementations.Localization
             }
             }
 
 
             // Try splitting by : to handle "Germany: FSK 18"
             // Try splitting by : to handle "Germany: FSK 18"
-            var index = rating.IndexOf(':');
+            var index = rating.IndexOf(':', StringComparison.Ordinal);
             if (index != -1)
             if (index != -1)
             {
             {
                 rating = rating.Substring(index).TrimStart(':').Trim();
                 rating = rating.Substring(index).TrimStart(':').Trim();
@@ -312,12 +312,12 @@ namespace Emby.Server.Implementations.Localization
                 throw new ArgumentNullException(nameof(culture));
                 throw new ArgumentNullException(nameof(culture));
             }
             }
 
 
-            const string prefix = "Core";
-            var key = prefix + culture;
+            const string Prefix = "Core";
+            var key = Prefix + culture;
 
 
             return _dictionaries.GetOrAdd(
             return _dictionaries.GetOrAdd(
                 key,
                 key,
-                f => GetDictionary(prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult());
+                f => GetDictionary(Prefix, culture, DefaultCulture + ".json").GetAwaiter().GetResult());
         }
         }
 
 
         private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename)
         private async Task<Dictionary<string, string>> GetDictionary(string prefix, string culture, string baseFilename)

+ 1 - 1
Emby.Server.Implementations/Networking/NetworkManager.cs

@@ -390,7 +390,7 @@ namespace Emby.Server.Implementations.Networking
                         var host = uri.DnsSafeHost;
                         var host = uri.DnsSafeHost;
                         _logger.LogDebug("Resolving host {0}", host);
                         _logger.LogDebug("Resolving host {0}", host);
 
 
-                        address = GetIpAddresses(host).Result.FirstOrDefault();
+                        address = GetIpAddresses(host).GetAwaiter().GetResult().FirstOrDefault();
 
 
                         if (address != null)
                         if (address != null)
                         {
                         {

+ 7 - 1
Emby.Server.Implementations/Services/ServiceExec.cs

@@ -2,6 +2,7 @@
 
 
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Globalization;
 using System.Linq;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Linq.Expressions;
 using System.Reflection;
 using System.Reflection;
@@ -105,7 +106,12 @@ namespace Emby.Server.Implementations.Services
             }
             }
 
 
             var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant();
             var expectedMethodName = actionName.Substring(0, 1) + actionName.Substring(1).ToLowerInvariant();
-            throw new NotImplementedException(string.Format("Could not find method named {1}({0}) or Any({0}) on Service {2}", requestDto.GetType().GetMethodName(), expectedMethodName, serviceType.GetMethodName()));
+            throw new NotImplementedException(
+                string.Format(
+                    CultureInfo.InvariantCulture,
+                    "Could not find method named {1}({0}) or Any({0}) on Service {2}",
+                    requestDto.GetType().GetMethodName(),
+                    expectedMethodName, serviceType.GetMethodName()));
         }
         }
 
 
         private static async Task<object> GetTaskResult(Task task)
         private static async Task<object> GetTaskResult(Task task)

+ 10 - 7
Emby.Server.Implementations/Services/ServiceHandler.cs

@@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Services
             var pos = pathInfo.LastIndexOf('.');
             var pos = pathInfo.LastIndexOf('.');
             if (pos != -1)
             if (pos != -1)
             {
             {
-                var format = pathInfo.Substring(pos + 1);
+                var format = pathInfo.AsSpan().Slice(pos + 1);
                 contentType = GetFormatContentType(format);
                 contentType = GetFormatContentType(format);
                 if (contentType != null)
                 if (contentType != null)
                 {
                 {
@@ -55,15 +55,18 @@ namespace Emby.Server.Implementations.Services
             return pathInfo;
             return pathInfo;
         }
         }
 
 
-        private static string GetFormatContentType(string format)
+        private static string GetFormatContentType(ReadOnlySpan<char> format)
         {
         {
-            // built-in formats
-            switch (format)
+            if (format.Equals("json", StringComparison.Ordinal))
             {
             {
-                case "json": return "application/json";
-                case "xml": return "application/xml";
-                default: return null;
+                return "application/json";
             }
             }
+            else if (format.Equals("xml", StringComparison.Ordinal))
+            {
+                return "application/xml";
+            }
+
+            return null;
         }
         }
 
 
         public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, ILogger logger, CancellationToken cancellationToken)
         public async Task ProcessRequestAsync(HttpListenerHost httpHost, IRequest httpReq, HttpResponse httpRes, ILogger logger, CancellationToken cancellationToken)

+ 1 - 1
Emby.Server.Implementations/Services/ServicePath.cs

@@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.Services
             {
             {
                 var component = components[i];
                 var component = components[i];
 
 
-                if (component.StartsWith(VariablePrefix))
+                if (component.StartsWith(VariablePrefix, StringComparison.Ordinal))
                 {
                 {
                     var variableName = component.Substring(1, component.Length - 2);
                     var variableName = component.Substring(1, component.Length - 2);
                     if (variableName[variableName.Length - 1] == WildCardChar)
                     if (variableName[variableName.Length - 1] == WildCardChar)

+ 1 - 1
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
 
             var playlistFilename = Path.GetFileNameWithoutExtension(playlist);
             var playlistFilename = Path.GetFileNameWithoutExtension(playlist);
 
 
-            var indexString = Path.GetFileNameWithoutExtension(file.Name).Substring(playlistFilename.Length);
+            var indexString = Path.GetFileNameWithoutExtension(file.Name).AsSpan().Slice(playlistFilename.Length);
 
 
             return int.Parse(indexString, NumberStyles.Integer, CultureInfo.InvariantCulture);
             return int.Parse(indexString, NumberStyles.Integer, CultureInfo.InvariantCulture);
         }
         }

+ 9 - 7
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -675,11 +675,11 @@ namespace MediaBrowser.Controller.Entities
                 return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
                 return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
             }
             }
 
 
-            var idString = Id.ToString("N", CultureInfo.InvariantCulture);
+            ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
 
 
             basePath = System.IO.Path.Combine(basePath, "library");
             basePath = System.IO.Path.Combine(basePath, "library");
 
 
-            return System.IO.Path.Combine(basePath, idString.Substring(0, 2), idString);
+            return System.IO.Path.Join(basePath, idString.Slice(0, 2), idString);
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -702,26 +702,27 @@ namespace MediaBrowser.Controller.Entities
 
 
             foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
             foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
             {
             {
-                sortable = sortable.Replace(removeChar, string.Empty);
+                sortable = sortable.Replace(removeChar, string.Empty, StringComparison.Ordinal);
             }
             }
 
 
             foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters)
             foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters)
             {
             {
-                sortable = sortable.Replace(replaceChar, " ");
+                sortable = sortable.Replace(replaceChar, " ", StringComparison.Ordinal);
             }
             }
 
 
             foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
             foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
             {
             {
                 // Remove from beginning if a space follows
                 // Remove from beginning if a space follows
-                if (sortable.StartsWith(search + " "))
+                if (sortable.StartsWith(search + " ", StringComparison.Ordinal))
                 {
                 {
                     sortable = sortable.Remove(0, search.Length + 1);
                     sortable = sortable.Remove(0, search.Length + 1);
                 }
                 }
+
                 // Remove from middle if surrounded by spaces
                 // Remove from middle if surrounded by spaces
-                sortable = sortable.Replace(" " + search + " ", " ");
+                sortable = sortable.Replace(" " + search + " ", " ", StringComparison.Ordinal);
 
 
                 // Remove from end if followed by a space
                 // Remove from end if followed by a space
-                if (sortable.EndsWith(" " + search))
+                if (sortable.EndsWith(" " + search, StringComparison.Ordinal))
                 {
                 {
                     sortable = sortable.Remove(sortable.Length - (search.Length + 1));
                     sortable = sortable.Remove(sortable.Length - (search.Length + 1));
                 }
                 }
@@ -751,6 +752,7 @@ namespace MediaBrowser.Controller.Entities
 
 
                 builder.Append(chunkBuilder);
                 builder.Append(chunkBuilder);
             }
             }
+
             // logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
             // logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
             return builder.ToString().RemoveDiacritics();
             return builder.ToString().RemoveDiacritics();
         }
         }

+ 11 - 12
MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs

@@ -1588,7 +1588,7 @@ namespace MediaBrowser.Controller.MediaEncoding
         {
         {
             outputVideoCodec ??= string.Empty;
             outputVideoCodec ??= string.Empty;
 
 
-            var outputSizeParam = string.Empty;
+            var outputSizeParam = ReadOnlySpan<char>.Empty;
             var request = state.BaseRequest;
             var request = state.BaseRequest;
 
 
             // Add resolution params, if specified
             // Add resolution params, if specified
@@ -1602,28 +1602,28 @@ namespace MediaBrowser.Controller.MediaEncoding
                 var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase);
                 var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase);
                 if (index != -1)
                 if (index != -1)
                 {
                 {
-                    outputSizeParam = outputSizeParam.Substring(index);
+                    outputSizeParam = outputSizeParam.Slice(index);
                 }
                 }
                 else
                 else
                 {
                 {
                     index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
                     index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
                     if (index != -1)
                     if (index != -1)
                     {
                     {
-                        outputSizeParam = outputSizeParam.Substring(index);
+                        outputSizeParam = outputSizeParam.Slice(index);
                     }
                     }
                     else
                     else
                     {
                     {
                         index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
                         index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
                         if (index != -1)
                         if (index != -1)
                         {
                         {
-                            outputSizeParam = outputSizeParam.Substring(index);
+                            outputSizeParam = outputSizeParam.Slice(index);
                         }
                         }
                         else
                         else
                         {
                         {
                             index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
                             index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
                             if (index != -1)
                             if (index != -1)
                             {
                             {
-                                outputSizeParam = outputSizeParam.Substring(index);
+                                outputSizeParam = outputSizeParam.Slice(index);
                             }
                             }
                         }
                         }
                     }
                     }
@@ -1669,9 +1669,9 @@ namespace MediaBrowser.Controller.MediaEncoding
 
 
             // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
             // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference)
             // Always put the scaler before the overlay for better performance
             // Always put the scaler before the overlay for better performance
-            var retStr = !string.IsNullOrEmpty(outputSizeParam) ?
-                " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\"" :
-                " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
+            var retStr = !outputSizeParam.IsEmpty
+                ? " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay\""
+                : " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay\"";
 
 
             // When the input may or may not be hardware VAAPI decodable
             // When the input may or may not be hardware VAAPI decodable
             if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
@@ -1705,7 +1705,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 */
                 */
                 if (isLinux)
                 if (isLinux)
                 {
                 {
-                    retStr = !string.IsNullOrEmpty(outputSizeParam) ?
+                    retStr = !outputSizeParam.IsEmpty ?
                         " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" :
                         " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]{3}[base];[base][sub]overlay_qsv\"" :
                         " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
                         " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv\"";
                 }
                 }
@@ -1717,7 +1717,7 @@ namespace MediaBrowser.Controller.MediaEncoding
                 mapPrefix,
                 mapPrefix,
                 subtitleStreamIndex,
                 subtitleStreamIndex,
                 state.VideoStream.Index,
                 state.VideoStream.Index,
-                outputSizeParam,
+                outputSizeParam.ToString(),
                 videoSizeParam);
                 videoSizeParam);
         }
         }
 
 
@@ -2090,7 +2090,7 @@ namespace MediaBrowser.Controller.MediaEncoding
             // Add software deinterlace filter before scaling filter
             // Add software deinterlace filter before scaling filter
             if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
             if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
             {
             {
-                var deintParam = string.Empty;
+                string deintParam;
                 var inputFramerate = videoStream?.RealFrameRate;
                 var inputFramerate = videoStream?.RealFrameRate;
 
 
                 // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
                 // If it is already 60fps then it will create an output framerate that is much too high for roku and others to handle
@@ -2159,7 +2159,6 @@ namespace MediaBrowser.Controller.MediaEncoding
             return output;
             return output;
         }
         }
 
 
-
         /// <summary>
         /// <summary>
         /// Gets the number of threads.
         /// Gets the number of threads.
         /// </summary>
         /// </summary>

+ 2 - 2
MediaBrowser.MediaEncoding/Subtitles/AssParser.cs

@@ -35,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                         continue;
                         continue;
                     }
                     }
 
 
-                    if (line.StartsWith("["))
+                    if (line[0] == '[')
                     {
                     {
                         break;
                         break;
                     }
                     }
@@ -62,7 +62,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             return trackInfo;
             return trackInfo;
         }
         }
 
 
-        long GetTicks(string time)
+        private long GetTicks(ReadOnlySpan<char> time)
         {
         {
             return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out var span)
             return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out var span)
                 ? span.Ticks : 0;
                 ? span.Ticks : 0;

+ 4 - 1
MediaBrowser.MediaEncoding/Subtitles/ParserValues.cs

@@ -1,6 +1,9 @@
+#nullable enable
+#pragma warning disable CS1591
+
 namespace MediaBrowser.MediaEncoding.Subtitles
 namespace MediaBrowser.MediaEncoding.Subtitles
 {
 {
-    public class ParserValues
+    public static class ParserValues
     {
     {
         public const string NewLine = "\r\n";
         public const string NewLine = "\r\n";
     }
     }

+ 7 - 4
MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
@@ -20,6 +22,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             _logger = logger;
             _logger = logger;
         }
         }
 
 
+        /// <inheritdoc />
         public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
         public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
         {
         {
             var trackInfo = new SubtitleTrackInfo();
             var trackInfo = new SubtitleTrackInfo();
@@ -55,11 +58,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     }
                     }
 
 
                     subEvent.StartPositionTicks = GetTicks(time[0]);
                     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)
                     if (idx > 0)
                     {
                     {
-                        endTime = endTime.Substring(0, idx);
+                        endTime = endTime.Slice(0, idx);
                     }
                     }
 
 
                     subEvent.EndPositionTicks = GetTicks(endTime);
                     subEvent.EndPositionTicks = GetTicks(endTime);
@@ -88,7 +91,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
             return trackInfo;
             return trackInfo;
         }
         }
 
 
-        long GetTicks(string time)
+        private long GetTicks(ReadOnlySpan<char> time)
         {
         {
             return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out var span)
             return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out var span)
                 ? span.Ticks
                 ? span.Ticks

+ 4 - 0
MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs

@@ -8,8 +8,12 @@ using MediaBrowser.Model.MediaInfo;
 
 
 namespace MediaBrowser.MediaEncoding.Subtitles
 namespace MediaBrowser.MediaEncoding.Subtitles
 {
 {
+    /// <summary>
+    /// SRT subtitle writer.
+    /// </summary>
     public class SrtWriter : ISubtitleWriter
     public class SrtWriter : ISubtitleWriter
     {
     {
+        /// <inheritdoc />
         public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
         public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
         {
         {
             using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
             using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))

+ 14 - 22
MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs

@@ -12,6 +12,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
     /// </summary>
     /// </summary>
     public class SsaParser : ISubtitleParser
     public class SsaParser : ISubtitleParser
     {
     {
+        /// <inheritdoc />
         public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
         public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
         {
         {
             var trackInfo = new SubtitleTrackInfo();
             var trackInfo = new SubtitleTrackInfo();
@@ -45,7 +46,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                         header.AppendLine(line);
                         header.AppendLine(line);
                     }
                     }
 
 
-                    if (line.Trim().ToLowerInvariant() == "[events]")
+                    if (string.Equals(line.Trim(), "[events]", StringComparison.OrdinalIgnoreCase))
                     {
                     {
                         eventsStarted = true;
                         eventsStarted = true;
                     }
                     }
@@ -63,27 +64,27 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                                 format = line.ToLowerInvariant().Substring(8).Split(',');
                                 format = line.ToLowerInvariant().Substring(8).Split(',');
                                 for (int i = 0; i < format.Length; i++)
                                 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;
                                         indexLayer = i;
                                     }
                                     }
-                                    else if (format[i].Trim().ToLowerInvariant() == "start")
+                                    else if (string.Equals(format[i].Trim(), "start", StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
                                         indexStart = i;
                                         indexStart = i;
                                     }
                                     }
-                                    else if (format[i].Trim().ToLowerInvariant() == "end")
+                                    else if (string.Equals(format[i].Trim(), "end", StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
                                         indexEnd = i;
                                         indexEnd = i;
                                     }
                                     }
-                                    else if (format[i].Trim().ToLowerInvariant() == "text")
+                                    else if (string.Equals(format[i].Trim(), "text", StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
                                         indexText = i;
                                         indexText = i;
                                     }
                                     }
-                                    else if (format[i].Trim().ToLowerInvariant() == "effect")
+                                    else if (string.Equals(format[i].Trim(), "effect", StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
                                         indexEffect = i;
                                         indexEffect = i;
                                     }
                                     }
-                                    else if (format[i].Trim().ToLowerInvariant() == "style")
+                                    else if (string.Equals(format[i].Trim(), "style", StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
                                         indexStyle = i;
                                         indexStyle = i;
                                     }
                                     }
@@ -184,12 +185,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                                 int.Parse(timeCode[3]) * 10).Ticks;
                                 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);
             text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
 
 
-            bool italic = false;
-
             for (int i = 0; i < 10; i++) // just look ten times...
             for (int i = 0; i < 10; i++) // just look ten times...
             {
             {
                 if (text.Contains(@"{\fn"))
                 if (text.Contains(@"{\fn"))
@@ -200,7 +199,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     {
                     {
                         string fontName = text.Substring(start + 4, end - (start + 4));
                         string fontName = text.Substring(start + 4, end - (start + 4));
                         string extraTags = string.Empty;
                         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);
                         text = text.Remove(start, end - start + 1);
                         if (italic)
                         if (italic)
                         {
                         {
@@ -231,7 +230,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     {
                     {
                         string fontSize = text.Substring(start + 4, end - (start + 4));
                         string fontSize = text.Substring(start + 4, end - (start + 4));
                         string extraTags = string.Empty;
                         string extraTags = string.Empty;
-                        CheckAndAddSubTags(ref fontSize, ref extraTags, out italic);
+                        CheckAndAddSubTags(ref fontSize, ref extraTags, out bool italic);
                         if (IsInteger(fontSize))
                         if (IsInteger(fontSize))
                         {
                         {
                             text = text.Remove(start, end - start + 1);
                             text = text.Remove(start, end - start + 1);
@@ -265,7 +264,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     {
                     {
                         string color = text.Substring(start + 4, end - (start + 4));
                         string color = text.Substring(start + 4, end - (start + 4));
                         string extraTags = string.Empty;
                         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.Replace("&", string.Empty).TrimStart('H');
                         color = color.PadLeft(6, '0');
                         color = color.PadLeft(6, '0');
@@ -303,7 +302,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     {
                     {
                         string color = text.Substring(start + 5, end - (start + 5));
                         string color = text.Substring(start + 5, end - (start + 5));
                         string extraTags = string.Empty;
                         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.Replace("&", string.Empty).TrimStart('H');
                         color = color.PadLeft(6, '0');
                         color = color.PadLeft(6, '0');
@@ -354,14 +353,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
         }
         }
 
 
         private static bool IsInteger(string s)
         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)
         private static int CountTagInText(string text, string tag)
         {
         {

+ 3 - 1
MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Diagnostics;
 using System.Diagnostics;
@@ -365,7 +367,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
         /// <returns>System.Object.</returns>
         /// <returns>System.Object.</returns>
         private SemaphoreSlim GetLock(string filename)
         private SemaphoreSlim GetLock(string filename)
         {
         {
-            return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
+            return _semaphoreLocks.GetOrAdd(filename, _ => new SemaphoreSlim(1, 1));
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 7 - 2
MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs

@@ -6,8 +6,12 @@ using MediaBrowser.Model.MediaInfo;
 
 
 namespace MediaBrowser.MediaEncoding.Subtitles
 namespace MediaBrowser.MediaEncoding.Subtitles
 {
 {
+    /// <summary>
+    /// TTML subtitle writer.
+    /// </summary>
     public class TtmlWriter : ISubtitleWriter
     public class TtmlWriter : ISubtitleWriter
     {
     {
+        /// <inheritdoc />
         public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
         public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
         {
         {
             // Example: https://github.com/zmalltalker/ttml2vtt/blob/master/data/sample.xml
             // 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);
                     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.StartPositionTicks,
-                        (trackEvent.EndPositionTicks - trackEvent.StartPositionTicks),
+                        trackEvent.EndPositionTicks - trackEvent.StartPositionTicks,
                         text);
                         text);
                 }
                 }
 
 

+ 1 - 1
MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs

@@ -47,7 +47,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
                     text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
                     text = Regex.Replace(text, @"\\n", " ", RegexOptions.IgnoreCase);
 
 
                     writer.WriteLine(text);
                     writer.WriteLine(text);
-                    writer.WriteLine(string.Empty);
+                    writer.WriteLine();
                 }
                 }
             }
             }
         }
         }