diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs
index 07259e00a1..41060426fa 100644
--- a/Emby.Naming/Common/NamingOptions.cs
+++ b/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|\[.*\])([ _\,\.\(\)\[\]\-]|$)",
@"(\[.*\])"
};
diff --git a/Emby.Naming/Video/CleanDateTimeParser.cs b/Emby.Naming/Video/CleanDateTimeParser.cs
index 9723fb71a3..8638dddd42 100644
--- a/Emby.Naming/Video/CleanDateTimeParser.cs
+++ b/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;
}
}
}
diff --git a/Emby.Naming/Video/CleanDateTimeResult.cs b/Emby.Naming/Video/CleanDateTimeResult.cs
index a7581972e4..73a445612b 100644
--- a/Emby.Naming/Video/CleanDateTimeResult.cs
+++ b/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;
+ }
+
///
- /// Gets or sets the name.
+ /// Gets the name.
///
/// The name.
- public string Name { get; set; }
+ public string Name { get; }
///
- /// Gets or sets the year.
+ /// Gets the year.
///
/// The year.
- public int? Year { get; set; }
-
- ///
- /// Gets or sets a value indicating whether this instance has changed.
- ///
- /// true if this instance has changed; otherwise, false.
- public bool HasChanged { get; set; }
+ public int? Year { get; }
}
}
diff --git a/Emby.Naming/Video/CleanStringParser.cs b/Emby.Naming/Video/CleanStringParser.cs
index fe2a91bdb9..b7b65d8228 100644
--- a/Emby.Naming/Video/CleanStringParser.cs
+++ b/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
///
public static class CleanStringParser
{
- public static CleanStringResult Clean(string name, IEnumerable expressions)
+ public static bool TryClean(string name, IReadOnlyList expressions, out ReadOnlySpan 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.Empty;
+ return false;
}
- private static CleanStringResult Clean(string name, Regex expression)
+ private static bool TryClean(string name, Regex expression, out ReadOnlySpan 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;
}
}
}
diff --git a/Emby.Naming/Video/CleanStringResult.cs b/Emby.Naming/Video/CleanStringResult.cs
deleted file mode 100644
index 786fe9e028..0000000000
--- a/Emby.Naming/Video/CleanStringResult.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
-namespace Emby.Naming.Video
-{
- public class CleanStringResult
- {
- ///
- /// Gets or sets the name.
- ///
- /// The name.
- public string Name { get; set; }
-
- ///
- /// Gets or sets a value indicating whether this instance has changed.
- ///
- /// true if this instance has changed; otherwise, false.
- public bool HasChanged { get; set; }
- }
-}
diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs
index 97f59121b1..76e0a5a0ec 100644
--- a/Emby.Naming/Video/VideoResolver.cs
+++ b/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 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 newName)
{
- return CleanStringParser.Clean(name, _options.CleanStringRegexes);
+ return CleanStringParser.TryClean(name, _options.CleanStringRegexes, out newName);
}
public CleanDateTimeResult CleanDateTime(string name)
diff --git a/tests/Jellyfin.Naming.Tests/Video/CleanStringTests.cs b/tests/Jellyfin.Naming.Tests/Video/CleanStringTests.cs
index 7c3270ebcc..fde06c5a17 100644
--- a/tests/Jellyfin.Naming.Tests/Video/CleanStringTests.cs
+++ b/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 newName))
+ {
+ // TODO: compare spans when XUnit supports it
+ Assert.Equal(expectedName, newName.ToString());
+ }
+ else
+ {
+ Assert.Equal(expectedName, input);
+ }
}
}
}