mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-11-15 18:08:53 -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));
|
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,
|
||||||
|
@ -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; }
|
||||||
|
|
||||||
|
@ -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 />
|
||||||
|
@ -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))
|
||||||
{
|
{
|
||||||
|
@ -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[] { '/', '\\' })
|
.TrimStart('/', '\\')
|
||||||
.Replace("/", "\\");
|
.Replace('/', '\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceCaseInsensitive || !_configurationManager.Configuration.EnableCaseSensitiveItemIds)
|
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 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();
|
||||||
|
@ -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 + "\",";
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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[] { ' ', '-' });
|
||||||
|
@ -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";
|
const string Prefix = "Core";
|
||||||
var key = prefix + culture;
|
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)
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
if (format.Equals("json", StringComparison.Ordinal))
|
||||||
switch (format)
|
|
||||||
{
|
{
|
||||||
case "json": return "application/json";
|
return "application/json";
|
||||||
case "xml": return "application/xml";
|
|
||||||
default: return null;
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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) ?
|
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}]{3}[base];[base][sub]overlay\""
|
||||||
" -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][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>
|
||||||
|
@ -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;
|
||||||
|
@ -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";
|
||||||
}
|
}
|
||||||
|
@ -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 endTime = time[1].AsSpan();
|
||||||
var idx = endTime.IndexOf(" ", StringComparison.Ordinal);
|
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
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
{
|
=> int.TryParse(s, out _);
|
||||||
if (int.TryParse(s, out var i))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int CountTagInText(string text, string tag)
|
private static int CountTagInText(string text, string tag)
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user