mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-15 09:59:06 -07:00
Review usage of string.Substring (part 1)
Reduced allocations by replacing string.Substring with ReadOnlySpan<char>.Slice
This commit is contained in:
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…
Reference in New Issue
Block a user