Review usage of string.Substring (part 1)

Reduced allocations by replacing string.Substring with ReadOnlySpan<char>.Slice
pull/3657/head
Bond_009 4 years ago
parent 0750357916
commit febb6bced6

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

@ -387,7 +387,7 @@ namespace Emby.Dlna
foreach (var name in _assembly.GetManifestResourceNames())
{
if (!name.StartsWith(namespaceName))
if (!name.StartsWith(namespaceName, StringComparison.Ordinal))
{
continue;
}
@ -406,7 +406,7 @@ namespace Emby.Dlna
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);
}
class InternalProfileInfo
private class InternalProfileInfo
{
internal DeviceProfileInfo Info { get; set; }

@ -448,21 +448,21 @@ namespace Emby.Drawing
/// or
/// filename.
/// </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 />

@ -77,7 +77,7 @@ namespace Emby.Naming.TV
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))
{

@ -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
key = key.Substring(_configurationManager.ApplicationPaths.ProgramDataPath.Length)
.TrimStart(new[] { '/', '\\' })
.Replace("/", "\\");
.TrimStart('/', '\\')
.Replace('/', '\\');
}
if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)

@ -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 splitIndex = key.IndexOf(LiveStreamIdDelimeter);
var splitIndex = key.IndexOf(LiveStreamIdDelimeter, StringComparison.Ordinal);
var keyId = key.Substring(splitIndex + 1);
return new Tuple<IMediaSourceProvider, string>(provider, keyId);
@ -881,6 +881,7 @@ namespace Emby.Server.Implementations.Library
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private readonly object _disposeLock = new object();

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

@ -195,7 +195,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
while (!sr.EndOfStream)
{
string line = StripXML(sr.ReadLine());
if (line.Contains("Channel"))
if (line.Contains("Channel", StringComparison.Ordinal))
{
LiveTvTunerStatus status;
var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
@ -226,6 +226,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private static string StripXML(string source)
{
if (string.IsNullOrEmpty(source))
{
return string.Empty;
}
char[] buffer = new char[source.Length];
int bufferIndex = 0;
bool inside = false;
@ -270,7 +275,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
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 isAvailable = await manager.CheckTunerAvailability(ipInfo, i, cancellationToken).ConfigureAwait(false);
var status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;

@ -158,15 +158,14 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
private string GetChannelNumber(string extInf, Dictionary<string, string> attributes, string mediaUrl)
{
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 attributeValue;
double doubleValue;
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;
}
@ -176,36 +175,36 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
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;
}
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;
}
}
}
if (String.IsNullOrWhiteSpace(numberString))
if (string.IsNullOrWhiteSpace(numberString))
{
// 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
// Check for channel number with the format from SatIp
// #EXTINF:0,84. VOX Schweiz
// #EXTINF:0,84.0 - VOX Schweiz
if (!string.IsNullOrWhiteSpace(nameInExtInf))
if (!nameInExtInf.IsEmpty && !nameInExtInf.IsWhiteSpace())
{
var numberIndex = nameInExtInf.IndexOf(' ');
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
{
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/').Last());
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]);
if (!IsValidChannelNumber(numberString))
{
@ -258,7 +257,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
return false;
}
if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
if (!double.TryParse(numberString, NumberStyles.Any, CultureInfo.InvariantCulture, out _))
{
return false;
}
@ -281,7 +280,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
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();
nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });

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

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

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@ -105,7 +106,12 @@ namespace Emby.Server.Implementations.Services
}
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)

@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.Services
var pos = pathInfo.LastIndexOf('.');
if (pos != -1)
{
var format = pathInfo.Substring(pos + 1);
var format = pathInfo.AsSpan().Slice(pos + 1);
contentType = GetFormatContentType(format);
if (contentType != null)
{
@ -55,15 +55,18 @@ namespace Emby.Server.Implementations.Services
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)

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

@ -369,7 +369,7 @@ namespace MediaBrowser.Api.Playback.Hls
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);
}

@ -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));
}
var idString = Id.ToString("N", CultureInfo.InvariantCulture);
ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
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>
@ -702,26 +702,27 @@ namespace MediaBrowser.Controller.Entities
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)
{
sortable = sortable.Replace(replaceChar, " ");
sortable = sortable.Replace(replaceChar, " ", StringComparison.Ordinal);
}
foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
{
// Remove from beginning if a space follows
if (sortable.StartsWith(search + " "))
if (sortable.StartsWith(search + " ", StringComparison.Ordinal))
{
sortable = sortable.Remove(0, search.Length + 1);
}
// 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
if (sortable.EndsWith(" " + search))
if (sortable.EndsWith(" " + search, StringComparison.Ordinal))
{
sortable = sortable.Remove(sortable.Length - (search.Length + 1));
}
@ -751,6 +752,7 @@ namespace MediaBrowser.Controller.Entities
builder.Append(chunkBuilder);
}
// logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
return builder.ToString().RemoveDiacritics();
}

@ -1588,7 +1588,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
outputVideoCodec ??= string.Empty;
var outputSizeParam = string.Empty;
var outputSizeParam = ReadOnlySpan<char>.Empty;
var request = state.BaseRequest;
// Add resolution params, if specified
@ -1602,28 +1602,28 @@ namespace MediaBrowser.Controller.MediaEncoding
var index = outputSizeParam.IndexOf("hwdownload", StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
outputSizeParam = outputSizeParam.Substring(index);
outputSizeParam = outputSizeParam.Slice(index);
}
else
{
index = outputSizeParam.IndexOf("format", StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
outputSizeParam = outputSizeParam.Substring(index);
outputSizeParam = outputSizeParam.Slice(index);
}
else
{
index = outputSizeParam.IndexOf("yadif", StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
outputSizeParam = outputSizeParam.Substring(index);
outputSizeParam = outputSizeParam.Slice(index);
}
else
{
index = outputSizeParam.IndexOf("scale", StringComparison.OrdinalIgnoreCase);
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)
// 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
if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase))
@ -1705,7 +1705,7 @@ namespace MediaBrowser.Controller.MediaEncoding
*/
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}][sub]overlay_qsv\"";
}
@ -1717,7 +1717,7 @@ namespace MediaBrowser.Controller.MediaEncoding
mapPrefix,
subtitleStreamIndex,
state.VideoStream.Index,
outputSizeParam,
outputSizeParam.ToString(),
videoSizeParam);
}
@ -2090,7 +2090,7 @@ namespace MediaBrowser.Controller.MediaEncoding
// Add software deinterlace filter before scaling filter
if (state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true))
{
var deintParam = string.Empty;
string deintParam;
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
@ -2159,7 +2159,6 @@ namespace MediaBrowser.Controller.MediaEncoding
return output;
}
/// <summary>
/// Gets the number of threads.
/// </summary>

@ -35,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
continue;
}
if (line.StartsWith("["))
if (line[0] == '[')
{
break;
}
@ -62,7 +62,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;

@ -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";
}

@ -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

@ -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))

@ -12,6 +12,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// </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;
}
@ -184,12 +185,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles
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 +199,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 +230,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 +264,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');
@ -303,7 +302,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');
@ -354,14 +353,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)
{

@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
@ -365,7 +367,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
/// <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>

@ -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);
}

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

Loading…
Cancel
Save