Bond_009 3 роки тому
батько
коміт
a6d1e542e6

+ 2 - 3
Emby.Dlna/Eventing/DlnaEventManager.cs

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

+ 4 - 3
Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs

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

+ 28 - 31
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs

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

+ 1 - 1
Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs

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

+ 2 - 1
Jellyfin.Api/Controllers/RemoteImageController.cs

@@ -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.");

+ 2 - 1
Jellyfin.Api/Helpers/StreamingHelpers.cs

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

+ 2 - 2
MediaBrowser.Controller/MediaEncoding/JobLogger.cs

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

+ 2 - 1
MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs

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

+ 1 - 1
MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs

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

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

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

+ 2 - 1
MediaBrowser.Model/Net/MimeTypes.cs

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

+ 2 - 1
MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs

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

+ 34 - 0
src/Jellyfin.Extensions/StringExtensions.cs

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

+ 21 - 0
tests/Jellyfin.Extensions.Tests/StringExtensionsTests.cs

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