Browse Source

Improve parsers

Bond_009 5 years ago
parent
commit
cd0592ea8f

+ 1 - 2
Emby.Naming/Common/NamingOptions.cs

@@ -182,8 +182,7 @@ namespace Emby.Naming.Common
 
             CleanStrings = new[]
             {
-                @"[ _\,\.\(\)\[\]\-](HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
-                @"[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
+                @"[ _\,\.\(\)\[\]\-](3d|sbs|tab|hsbs|htab|mvc|HDR|HDC|UHD|UltraHD|4k|ac3|dts|custom|dc|divx|divx5|dsr|dsrip|dutch|dvd|dvdrip|dvdscr|dvdscreener|screener|dvdivx|cam|fragment|fs|hdtv|hdrip|hdtvrip|internal|limited|multisubs|ntsc|ogg|ogm|pal|pdtv|proper|repack|rerip|retail|cd[1-9]|r3|r5|bd5|se|svcd|swedish|german|read.nfo|nfofix|unrated|ws|telesync|ts|telecine|tc|brrip|bdrip|480p|480i|576p|576i|720p|720i|1080p|1080i|2160p|hrhd|hrhdtv|hddvd|bluray|x264|h264|xvid|xvidvd|xxx|www.www|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
                 @"(\[.*\])"
             };
 

+ 24 - 12
Emby.Naming/Video/CleanDateTimeParser.cs

@@ -1,8 +1,8 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 using System.Globalization;
-using System.Linq;
 using System.Text.RegularExpressions;
 using Emby.Naming.Common;
 
@@ -21,14 +21,28 @@ namespace Emby.Naming.Video
         }
 
         public CleanDateTimeResult Clean(string name)
-            => _options.CleanDateTimeRegexes.Select(i => Clean(name, i))
-                .FirstOrDefault(i => i.HasChanged) ??
-                new CleanDateTimeResult { Name = name };
-
-        private static CleanDateTimeResult Clean(string name, Regex expression)
         {
-            var result = new CleanDateTimeResult();
+            var regexes = _options.CleanDateTimeRegexes;
+            var len = regexes.Length;
+            CleanDateTimeResult result = new CleanDateTimeResult(name);
+            if (len == 0)
+            {
+                return result;
+            }
+
+            for (int i = 0; i < len; i++)
+            {
+                if (TryClean(name, regexes[i], ref result))
+                {
+                    return result;
+                }
+            }
 
+            return result;
+        }
+
+        private static bool TryClean(string name, Regex expression, ref CleanDateTimeResult result)
+        {
             var match = expression.Match(name);
 
             if (match.Success
@@ -37,13 +51,11 @@ namespace Emby.Naming.Video
                 && match.Groups[2].Success
                 && int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
             {
-                name = match.Groups[1].Value.TrimEnd();
-                result.Year = year;
-                result.HasChanged = true;
+                result = new CleanDateTimeResult(match.Groups[1].Value.TrimEnd(), year);
+                return true;
             }
 
-            result.Name = name;
-            return result;
+            return false;
         }
     }
 }

+ 18 - 11
Emby.Naming/Video/CleanDateTimeResult.cs

@@ -1,26 +1,33 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 namespace Emby.Naming.Video
 {
-    public class CleanDateTimeResult
+    public readonly struct CleanDateTimeResult
     {
+        public CleanDateTimeResult(string name, int? year)
+        {
+            Name = name;
+            Year = year;
+        }
+
+        public CleanDateTimeResult(string name)
+        {
+            Name = name;
+            Year = null;
+        }
+
         /// <summary>
-        /// Gets or sets the name.
+        /// Gets the name.
         /// </summary>
         /// <value>The name.</value>
-        public string Name { get; set; }
+        public string Name { get; }
 
         /// <summary>
-        /// Gets or sets the year.
+        /// Gets the year.
         /// </summary>
         /// <value>The year.</value>
-        public int? Year { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance has changed.
-        /// </summary>
-        /// <value><c>true</c> if this instance has changed; otherwise, <c>false</c>.</value>
-        public bool HasChanged { get; set; }
+        public int? Year { get; }
     }
 }

+ 16 - 23
Emby.Naming/Video/CleanStringParser.cs

@@ -1,6 +1,8 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
+using System;
 using System.Collections.Generic;
 using System.Text.RegularExpressions;
 
@@ -11,42 +13,33 @@ namespace Emby.Naming.Video
     /// </summary>
     public static class CleanStringParser
     {
-        public static CleanStringResult Clean(string name, IEnumerable<Regex> expressions)
+        public static bool TryClean(string name, IReadOnlyList<Regex> expressions, out ReadOnlySpan<char> newName)
         {
-            var hasChanged = false;
-
-            foreach (var exp in expressions)
+            var len = expressions.Count;
+            for (int i = 0; i < len; i++)
             {
-                var result = Clean(name, exp);
-
-                if (!string.IsNullOrEmpty(result.Name))
+                if (TryClean(name, expressions[i], out newName))
                 {
-                    name = result.Name;
-                    hasChanged = hasChanged || result.HasChanged;
+                    return true;
                 }
             }
 
-            return new CleanStringResult
-            {
-                Name = name,
-                HasChanged = hasChanged
-            };
+            newName = ReadOnlySpan<char>.Empty;
+            return false;
         }
 
-        private static CleanStringResult Clean(string name, Regex expression)
+        private static bool TryClean(string name, Regex expression, out ReadOnlySpan<char> newName)
         {
-            var result = new CleanStringResult();
-
             var match = expression.Match(name);
-
-            if (match.Success)
+            int index = match.Index;
+            if (match.Success && index != 0)
             {
-                result.HasChanged = true;
-                name = name.Substring(0, match.Index);
+                newName = name.AsSpan().Slice(0, match.Index);
+                return true;
             }
 
-            result.Name = name;
-            return result;
+            newName = string.Empty;
+            return false;
         }
     }
 }

+ 0 - 20
Emby.Naming/Video/CleanStringResult.cs

@@ -1,20 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
-namespace Emby.Naming.Video
-{
-    public class CleanStringResult
-    {
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance has changed.
-        /// </summary>
-        /// <value><c>true</c> if this instance has changed; otherwise, <c>false</c>.</value>
-        public bool HasChanged { get; set; }
-    }
-}

+ 5 - 4
Emby.Naming/Video/VideoResolver.cs

@@ -94,9 +94,10 @@ namespace Emby.Naming.Video
             {
                 var cleanDateTimeResult = CleanDateTime(name);
 
-                if (extraResult.ExtraType == null)
+                if (extraResult.ExtraType == null
+                    && TryCleanString(cleanDateTimeResult.Name, out ReadOnlySpan<char> newName))
                 {
-                    name = CleanString(cleanDateTimeResult.Name).Name;
+                    name = newName.ToString();
                 }
 
                 year = cleanDateTimeResult.Year;
@@ -130,9 +131,9 @@ namespace Emby.Naming.Video
             return _options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
         }
 
-        public CleanStringResult CleanString(string name)
+        public bool TryCleanString(string name, out ReadOnlySpan<char> newName)
         {
-            return CleanStringParser.Clean(name, _options.CleanStringRegexes);
+            return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
         }
 
         public CleanDateTimeResult CleanDateTime(string name)

+ 11 - 3
tests/Jellyfin.Naming.Tests/Video/CleanStringTests.cs

@@ -1,4 +1,5 @@
-using Emby.Naming.Common;
+using System;
+using Emby.Naming.Common;
 using Emby.Naming.Video;
 using Xunit;
 
@@ -30,8 +31,15 @@ namespace Jellyfin.Naming.Tests.Video
         // FIXME: [InlineData("After The Sunset - [0004].mkv", "After The Sunset")]
         public void CleanStringTest(string input, string expectedName)
         {
-            var result = new VideoResolver(_namingOptions).CleanString(input);
-            Assert.Equal(expectedName, result.Name);
+            if (new VideoResolver(_namingOptions).TryCleanString(input, out ReadOnlySpan<char> newName))
+            {
+                // TODO: compare spans when XUnit supports it
+                Assert.Equal(expectedName, newName.ToString());
+            }
+            else
+            {
+                Assert.Equal(expectedName, input);
+            }
         }
     }
 }