Reduce allocations
This commit is contained in:
parent
a3a8e058bc
commit
a6d1e542e6
|
@ -11,6 +11,7 @@ using System.Net.Http;
|
|||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -82,9 +83,7 @@ namespace Emby.Dlna.Eventing
|
|||
if (!string.IsNullOrEmpty(header))
|
||||
{
|
||||
// Starts with SECOND-
|
||||
header = header.Split('-')[^1];
|
||||
|
||||
if (int.TryParse(header, NumberStyles.Integer, _usCulture, out var val))
|
||||
if (int.TryParse(header.AsSpan().RightPart('-'), NumberStyles.Integer, _usCulture, out var val))
|
||||
{
|
||||
return val;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using System.Linq;
|
|||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions;
|
||||
using Jellyfin.XmlTv;
|
||||
using Jellyfin.XmlTv.Entities;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
|
@ -89,11 +90,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
|
|||
return UnzipIfNeeded(path, cacheFile);
|
||||
}
|
||||
|
||||
private string UnzipIfNeeded(string originalUrl, string file)
|
||||
private string UnzipIfNeeded(ReadOnlySpan<char> originalUrl, string file)
|
||||
{
|
||||
string ext = Path.GetExtension(originalUrl.Split('?')[0]);
|
||||
ReadOnlySpan<char> ext = Path.GetExtension(originalUrl.LeftPart('?'));
|
||||
|
||||
if (string.Equals(ext, ".gz", StringComparison.OrdinalIgnoreCase))
|
||||
if (ext.Equals(".gz", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -36,7 +36,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
private readonly IHttpClientFactory _httpClientFactory;
|
||||
private readonly IServerApplicationHost _appHost;
|
||||
private readonly ISocketFactory _socketFactory;
|
||||
private readonly INetworkManager _networkManager;
|
||||
private readonly IStreamHelper _streamHelper;
|
||||
|
||||
private readonly JsonSerializerOptions _jsonOptions;
|
||||
|
@ -50,7 +49,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
IHttpClientFactory httpClientFactory,
|
||||
IServerApplicationHost appHost,
|
||||
ISocketFactory socketFactory,
|
||||
INetworkManager networkManager,
|
||||
IStreamHelper streamHelper,
|
||||
IMemoryCache memoryCache)
|
||||
: base(config, logger, fileSystem, memoryCache)
|
||||
|
@ -58,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
_httpClientFactory = httpClientFactory;
|
||||
_appHost = appHost;
|
||||
_socketFactory = socketFactory;
|
||||
_networkManager = networkManager;
|
||||
_streamHelper = streamHelper;
|
||||
|
||||
_jsonOptions = JsonDefaults.Options;
|
||||
|
@ -70,7 +67,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
|
||||
protected override string ChannelIdPrefix => "hdhr_";
|
||||
|
||||
private string GetChannelId(TunerHostInfo info, Channels i)
|
||||
private string GetChannelId(Channels i)
|
||||
=> ChannelIdPrefix + i.GuideNumber;
|
||||
|
||||
internal async Task<List<Channels>> GetLineup(TunerHostInfo info, CancellationToken cancellationToken)
|
||||
|
@ -103,7 +100,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
{
|
||||
Name = i.GuideName,
|
||||
Number = i.GuideNumber,
|
||||
Id = GetChannelId(tuner, i),
|
||||
Id = GetChannelId(i),
|
||||
IsFavorite = i.Favorite,
|
||||
TunerHostId = tuner.Id,
|
||||
IsHD = i.HD,
|
||||
|
@ -255,7 +252,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
{
|
||||
var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
var tuners = new List<LiveTvTunerInfo>();
|
||||
var tuners = new List<LiveTvTunerInfo>(model.TunerCount);
|
||||
|
||||
var uri = new Uri(GetApiUrl(info));
|
||||
|
||||
|
@ -264,10 +261,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
// Legacy HdHomeruns are IPv4 only
|
||||
var ipInfo = IPAddress.Parse(uri.Host);
|
||||
|
||||
for (int i = 0; i < model.TunerCount; ++i)
|
||||
for (int i = 0; i < model.TunerCount; i++)
|
||||
{
|
||||
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 status = isAvailable ? LiveTvTunerStatus.Available : LiveTvTunerStatus.LiveTv;
|
||||
tuners.Add(new LiveTvTunerInfo
|
||||
|
@ -455,28 +452,28 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
Path = url,
|
||||
Protocol = MediaProtocol.Udp,
|
||||
MediaStreams = new List<MediaStream>
|
||||
{
|
||||
new MediaStream
|
||||
{
|
||||
Type = MediaStreamType.Video,
|
||||
// Set the index to -1 because we don't know the exact index of the video stream within the container
|
||||
Index = -1,
|
||||
IsInterlaced = isInterlaced,
|
||||
Codec = videoCodec,
|
||||
Width = width,
|
||||
Height = height,
|
||||
BitRate = videoBitrate,
|
||||
NalLengthSize = nal
|
||||
},
|
||||
new MediaStream
|
||||
{
|
||||
Type = MediaStreamType.Audio,
|
||||
// Set the index to -1 because we don't know the exact index of the audio stream within the container
|
||||
Index = -1,
|
||||
Codec = audioCodec,
|
||||
BitRate = audioBitrate
|
||||
}
|
||||
},
|
||||
{
|
||||
new MediaStream
|
||||
{
|
||||
Type = MediaStreamType.Video,
|
||||
// Set the index to -1 because we don't know the exact index of the video stream within the container
|
||||
Index = -1,
|
||||
IsInterlaced = isInterlaced,
|
||||
Codec = videoCodec,
|
||||
Width = width,
|
||||
Height = height,
|
||||
BitRate = videoBitrate,
|
||||
NalLengthSize = nal
|
||||
},
|
||||
new MediaStream
|
||||
{
|
||||
Type = MediaStreamType.Audio,
|
||||
// Set the index to -1 because we don't know the exact index of the audio stream within the container
|
||||
Index = -1,
|
||||
Codec = audioCodec,
|
||||
BitRate = audioBitrate
|
||||
}
|
||||
},
|
||||
RequiresOpening = true,
|
||||
RequiresClosing = true,
|
||||
BufferMs = 0,
|
||||
|
@ -551,7 +548,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
|
|||
}
|
||||
}
|
||||
|
||||
var profile = streamId.Split('_')[0];
|
||||
var profile = streamId.AsSpan().LeftPart('_').ToString();
|
||||
|
||||
Logger.LogInformation("GetChannelStream: channel id: {0}. stream id: {1} profile: {2}", channel.Id, streamId, profile);
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||
{
|
||||
try
|
||||
{
|
||||
numberString = Path.GetFileNameWithoutExtension(mediaUrl.Split('/')[^1]);
|
||||
numberString = Path.GetFileNameWithoutExtension(mediaUrl.AsSpan().RightPart('/')).ToString();
|
||||
|
||||
if (!IsValidChannelNumber(numberString))
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Net.Http;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Constants;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller;
|
||||
|
@ -199,7 +200,7 @@ namespace Jellyfin.Api.Controllers
|
|||
throw new ResourceNotFoundException(nameof(response.Content.Headers.ContentType));
|
||||
}
|
||||
|
||||
var ext = response.Content.Headers.ContentType.MediaType.Split('/')[^1];
|
||||
var ext = response.Content.Headers.ContentType.MediaType.AsSpan().RightPart('/').ToString();
|
||||
var fullCachePath = GetFullCachePath(urlHash + "." + ext);
|
||||
|
||||
var fullCacheDirectory = Path.GetDirectoryName(fullCachePath) ?? throw new ResourceNotFoundException($"Provided path ({fullCachePath}) is not valid.");
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Api.Models.StreamingDtos;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -81,7 +82,7 @@ namespace Jellyfin.Api.Helpers
|
|||
throw new ResourceNotFoundException(nameof(httpRequest.Path));
|
||||
}
|
||||
|
||||
var url = httpRequest.Path.Value.Split('.')[^1];
|
||||
var url = httpRequest.Path.Value.AsSpan().RightPart('.').ToString();
|
||||
|
||||
if (string.IsNullOrEmpty(streamingRequest.AudioCodec))
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
var size = part.Split('=', 2)[^1];
|
||||
|
||||
int? scale = null;
|
||||
if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (size.Contains("kb", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
scale = 1024;
|
||||
size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
@ -139,7 +139,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||
var rate = part.Split('=', 2)[^1];
|
||||
|
||||
int? scale = null;
|
||||
if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (rate.Contains("kbits/s", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
scale = 1024;
|
||||
rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -331,7 +332,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out var runtime))
|
||||
if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, _usCulture, out var runtime))
|
||||
{
|
||||
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
|
||||
}
|
||||
|
|
|
@ -1378,7 +1378,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||
{
|
||||
var disc = tags.GetValueOrDefault(tagName);
|
||||
|
||||
if (!string.IsNullOrEmpty(disc) && int.TryParse(disc.Split('/')[0], out var discNum))
|
||||
if (!string.IsNullOrEmpty(disc) && int.TryParse(disc.AsSpan().LeftPart('/'), out var discNum))
|
||||
{
|
||||
return discNum;
|
||||
}
|
||||
|
|
|
@ -18,14 +18,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||
using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||
{
|
||||
writer.WriteLine("WEBVTT");
|
||||
writer.WriteLine(string.Empty);
|
||||
writer.WriteLine();
|
||||
writer.WriteLine("REGION");
|
||||
writer.WriteLine("id:subtitle");
|
||||
writer.WriteLine("width:80%");
|
||||
writer.WriteLine("lines:3");
|
||||
writer.WriteLine("regionanchor:50%,100%");
|
||||
writer.WriteLine("viewportanchor:50%,90%");
|
||||
writer.WriteLine(string.Empty);
|
||||
writer.WriteLine();
|
||||
foreach (var trackEvent in info.TrackEvents)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
|
|
@ -4,6 +4,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Jellyfin.Extensions;
|
||||
|
||||
namespace MediaBrowser.Model.Net
|
||||
{
|
||||
|
@ -221,7 +222,7 @@ namespace MediaBrowser.Model.Net
|
|||
}
|
||||
|
||||
// handle text/html; charset=UTF-8
|
||||
mimeType = mimeType.Split(';')[0];
|
||||
mimeType = mimeType.AsSpan().LeftPart(';').ToString();
|
||||
|
||||
if (_extensionLookup.TryGetValue(mimeType, out string? result))
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Providers;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
@ -474,7 +475,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|||
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, UsCulture, out var runtime))
|
||||
if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, UsCulture, out var runtime))
|
||||
{
|
||||
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
|
||||
}
|
||||
|
|
|
@ -27,5 +27,39 @@ namespace Jellyfin.Extensions
|
|||
|
||||
return count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the part on the left of the <c>needle</c>.
|
||||
/// </summary>
|
||||
/// <param name="haystack">The string to seek.</param>
|
||||
/// <param name="needle">The needle to find.</param>
|
||||
/// <returns>The part left of the <paramref name="needle" />.</returns>
|
||||
public static ReadOnlySpan<char> LeftPart(this ReadOnlySpan<char> haystack, char needle)
|
||||
{
|
||||
var pos = haystack.IndexOf(needle);
|
||||
return pos == -1 ? haystack : haystack[..pos];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the part on the right of the <c>needle</c>.
|
||||
/// </summary>
|
||||
/// <param name="haystack">The string to seek.</param>
|
||||
/// <param name="needle">The needle to find.</param>
|
||||
/// <returns>The part right of the <paramref name="needle" />.</returns>
|
||||
public static ReadOnlySpan<char> RightPart(this ReadOnlySpan<char> haystack, char needle)
|
||||
{
|
||||
var pos = haystack.LastIndexOf(needle);
|
||||
if (pos == -1)
|
||||
{
|
||||
return haystack;
|
||||
}
|
||||
|
||||
if (pos == haystack.Length - 1)
|
||||
{
|
||||
return ReadOnlySpan<char>.Empty;
|
||||
}
|
||||
|
||||
return haystack[(pos + 1)..];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,5 +14,26 @@ namespace Jellyfin.Extensions.Tests
|
|||
{
|
||||
Assert.Equal(count, str.AsSpan().Count(needle));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", 'q', "")]
|
||||
[InlineData("Banana split", ' ', "Banana")]
|
||||
[InlineData("Banana split", 'q', "Banana split")]
|
||||
public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
|
||||
{
|
||||
var result = str.AsSpan().LeftPart(needle).ToString();
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", 'q', "")]
|
||||
[InlineData("Banana split", ' ', "split")]
|
||||
[InlineData("Banana split", 'q', "Banana split")]
|
||||
[InlineData("Banana split.", '.', "")]
|
||||
public void RightPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
|
||||
{
|
||||
var result = str.AsSpan().RightPart(needle).ToString();
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user