Răsfoiți Sursa

Improve alternate ordering (#9336)

Bond-009 2 ani în urmă
părinte
comite
5b493e14ac

+ 1 - 1
Emby.Naming/AudioBook/AudioBookFilePathParser.cs

@@ -32,7 +32,7 @@ namespace Emby.Naming.AudioBook
             var fileName = Path.GetFileNameWithoutExtension(path);
             foreach (var expression in _options.AudioBookPartsExpressions)
             {
-                var match = new Regex(expression, RegexOptions.IgnoreCase).Match(fileName);
+                var match = Regex.Match(fileName, expression, RegexOptions.IgnoreCase);
                 if (match.Success)
                 {
                     if (!result.ChapterNumber.HasValue)

+ 1 - 1
Emby.Naming/AudioBook/AudioBookNameParser.cs

@@ -30,7 +30,7 @@ namespace Emby.Naming.AudioBook
             AudioBookNameParserResult result = default;
             foreach (var expression in _options.AudioBookNamesExpressions)
             {
-                var match = new Regex(expression, RegexOptions.IgnoreCase).Match(name);
+                var match = Regex.Match(name, expression, RegexOptions.IgnoreCase);
                 if (match.Success)
                 {
                     if (result.Name is null)

+ 1 - 1
Emby.Naming/TV/SeriesResolver.cs

@@ -14,7 +14,7 @@ namespace Emby.Naming.TV
         /// Used for removing separators between words, i.e turns "The_show" into "The show" while
         /// preserving namings like "S.H.O.W".
         /// </summary>
-        private static readonly Regex _seriesNameRegex = new Regex(@"((?<a>[^\._]{2,})[\._]*)|([\._](?<b>[^\._]{2,}))");
+        private static readonly Regex _seriesNameRegex = new Regex(@"((?<a>[^\._]{2,})[\._]*)|([\._](?<b>[^\._]{2,}))", RegexOptions.Compiled);
 
         /// <summary>
         /// Resolve information about series from path.

+ 1 - 1
Emby.Naming/Video/FileStackRule.cs

@@ -17,7 +17,7 @@ public class FileStackRule
     /// <param name="isNumerical">Whether the file stack rule uses numerical or alphabetical numbering.</param>
     public FileStackRule(string token, bool isNumerical)
     {
-        _tokenRegex = new Regex(token, RegexOptions.IgnoreCase);
+        _tokenRegex = new Regex(token, RegexOptions.IgnoreCase | RegexOptions.Compiled);
         IsNumerical = isNumerical;
     }
 

+ 23 - 6
Emby.Naming/Video/VideoListResolver.cs

@@ -4,6 +4,7 @@ using System.IO;
 using System.Linq;
 using System.Text.RegularExpressions;
 using Emby.Naming.Common;
+using Jellyfin.Extensions;
 using MediaBrowser.Model.IO;
 
 namespace Emby.Naming.Video
@@ -13,6 +14,8 @@ namespace Emby.Naming.Video
     /// </summary>
     public static class VideoListResolver
     {
+        private static readonly Regex _resolutionRegex = new Regex("[0-9]{2}[0-9]+[ip]", RegexOptions.IgnoreCase | RegexOptions.Compiled);
+
         /// <summary>
         /// Resolves alternative versions and extras from list of video files.
         /// </summary>
@@ -115,19 +118,34 @@ namespace Emby.Naming.Video
                     continue;
                 }
 
-                if (!IsEligibleForMultiVersion(folderName, video.Files[0].Path, namingOptions))
+                if (!IsEligibleForMultiVersion(folderName, video.Files[0].FileNameWithoutExtension, namingOptions))
                 {
                     return videos;
                 }
 
-                if (folderName.Equals(Path.GetFileNameWithoutExtension(video.Files[0].Path.AsSpan()), StringComparison.Ordinal))
+                if (folderName.Equals(video.Files[0].FileNameWithoutExtension, StringComparison.Ordinal))
                 {
                     primary = video;
                 }
             }
 
-            // The list is created and overwritten in the caller, so we are allowed to do in-place sorting
-            videos.Sort((x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal));
+            if (videos.Count > 1)
+            {
+                var groups = videos.GroupBy(x => _resolutionRegex.IsMatch(x.Files[0].FileNameWithoutExtension)).ToList();
+                videos.Clear();
+                foreach (var group in groups)
+                {
+                    if (group.Key)
+                    {
+                        videos.InsertRange(0, group.OrderByDescending(x => x.Files[0].FileNameWithoutExtension.ToString(), new AlphanumericComparator()));
+                    }
+                    else
+                    {
+                        videos.AddRange(group.OrderBy(x => x.Files[0].FileNameWithoutExtension.ToString(), new AlphanumericComparator()));
+                    }
+                }
+            }
+
             primary ??= videos[0];
             videos.Remove(primary);
 
@@ -161,9 +179,8 @@ namespace Emby.Naming.Video
             return true;
         }
 
-        private static bool IsEligibleForMultiVersion(ReadOnlySpan<char> folderName, string testFilePath, NamingOptions namingOptions)
+        private static bool IsEligibleForMultiVersion(ReadOnlySpan<char> folderName, ReadOnlySpan<char> testFilename, NamingOptions namingOptions)
         {
-            var testFilename = Path.GetFileNameWithoutExtension(testFilePath.AsSpan());
             if (!testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
             {
                 return false;

+ 1 - 2
Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/LegacyHdHomerunChannelCommands.cs

@@ -13,8 +13,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
         public LegacyHdHomerunChannelCommands(string url)
         {
             // parse url for channel and program
-            var regExp = new Regex(@"\/ch([0-9]+)-?([0-9]*)");
-            var match = regExp.Match(url);
+            var match = Regex.Match(url, @"\/ch([0-9]+)-?([0-9]*)");
             if (match.Success)
             {
                 _channel = match.Groups[1].Value;

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

@@ -308,8 +308,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
         {
             var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
-            var reg = new Regex(@"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
-            var matches = reg.Matches(line);
+            var matches = Regex.Matches(line, @"([a-z0-9\-_]+)=\""([^""]+)\""", RegexOptions.IgnoreCase);
 
             remaining = line;
 

+ 1 - 1
src/Jellyfin.Extensions/StringExtensions.cs

@@ -12,7 +12,7 @@ namespace Jellyfin.Extensions
     {
         // Matches non-conforming unicode chars
         // https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
-        private static readonly Regex _nonConformingUnicode = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])|(\ufffd)");
+        private static readonly Regex _nonConformingUnicode = new Regex("([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])|(\ufffd)", RegexOptions.Compiled);
 
         /// <summary>
         /// Removes the diacritics character from the strings.

+ 28 - 14
tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs

@@ -188,8 +188,7 @@ namespace Jellyfin.Naming.Tests.Video
                 @"/movies/Iron Man/Iron Man-bluray.mkv",
                 @"/movies/Iron Man/Iron Man-3d.mkv",
                 @"/movies/Iron Man/Iron Man-3d-hsbs.mkv",
-                @"/movies/Iron Man/Iron Man-3d.hsbs.mkv",
-                @"/movies/Iron Man/Iron Man[test].mkv",
+                @"/movies/Iron Man/Iron Man[test].mkv"
             };
 
             var result = VideoListResolver.Resolve(
@@ -197,10 +196,14 @@ namespace Jellyfin.Naming.Tests.Video
                 _namingOptions).ToList();
 
             Assert.Single(result);
-            Assert.Equal(7, result[0].AlternateVersions.Count);
-            Assert.False(result[0].AlternateVersions[2].Is3D);
-            Assert.True(result[0].AlternateVersions[3].Is3D);
-            Assert.True(result[0].AlternateVersions[4].Is3D);
+            Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
+            Assert.Equal(6, result[0].AlternateVersions.Count);
+            Assert.Equal("/movies/Iron Man/Iron Man-720p.mkv", result[0].AlternateVersions[0].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man-3d.mkv", result[0].AlternateVersions[1].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man-3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man-bluray.mkv", result[0].AlternateVersions[3].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man-test.mkv", result[0].AlternateVersions[4].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man[test].mkv", result[0].AlternateVersions[5].Path);
         }
 
         [Fact]
@@ -214,7 +217,6 @@ namespace Jellyfin.Naming.Tests.Video
                 @"/movies/Iron Man/Iron Man - bluray.mkv",
                 @"/movies/Iron Man/Iron Man - 3d.mkv",
                 @"/movies/Iron Man/Iron Man - 3d-hsbs.mkv",
-                @"/movies/Iron Man/Iron Man - 3d.hsbs.mkv",
                 @"/movies/Iron Man/Iron Man [test].mkv"
             };
 
@@ -223,10 +225,14 @@ namespace Jellyfin.Naming.Tests.Video
                 _namingOptions).ToList();
 
             Assert.Single(result);
-            Assert.Equal(7, result[0].AlternateVersions.Count);
-            Assert.False(result[0].AlternateVersions[3].Is3D);
-            Assert.True(result[0].AlternateVersions[4].Is3D);
-            Assert.True(result[0].AlternateVersions[5].Is3D);
+            Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
+            Assert.Equal(6, result[0].AlternateVersions.Count);
+            Assert.Equal("/movies/Iron Man/Iron Man - 720p.mkv", result[0].AlternateVersions[0].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man - 3d.mkv", result[0].AlternateVersions[1].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man - 3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man - bluray.mkv", result[0].AlternateVersions[3].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man - test.mkv", result[0].AlternateVersions[4].Path);
+            Assert.Equal("/movies/Iron Man/Iron Man [test].mkv", result[0].AlternateVersions[5].Path);
         }
 
         [Fact]
@@ -328,8 +334,12 @@ namespace Jellyfin.Naming.Tests.Video
         {
             var files = new[]
             {
+                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv",
+                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv",
                 @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv",
-                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv"
+                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv",
+                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv",
+                @"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv",
             };
 
             var result = VideoListResolver.Resolve(
@@ -338,8 +348,12 @@ namespace Jellyfin.Naming.Tests.Video
 
             Assert.Single(result);
             Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
-            Assert.Single(result[0].AlternateVersions);
-            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[0].Path);
+            Assert.Equal(5, result[0].AlternateVersions.Count);
+            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Path);
+            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[1].Path);
+            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[2].Path);
+            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[3].Path);
+            Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[4].Path);
         }
 
         [Fact]