Browse Source

Merge pull request #1366 from Bond-009/warn3

Fix more warnings
Anthony Lavado 6 years ago
parent
commit
aee3360841
41 changed files with 334 additions and 237 deletions
  1. 14 12
      Emby.Naming/Audio/AlbumParser.cs
  2. 2 0
      Emby.Naming/Audio/MultiPartResult.cs
  3. 25 4
      Emby.Naming/AudioBook/AudioBookFileInfo.cs
  4. 7 6
      Emby.Naming/AudioBook/AudioBookFilePathParser.cs
  5. 2 0
      Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs
  6. 14 7
      Emby.Naming/AudioBook/AudioBookInfo.cs
  7. 1 1
      Emby.Naming/AudioBook/AudioBookListResolver.cs
  8. 6 5
      Emby.Naming/AudioBook/AudioBookResolver.cs
  9. 14 3
      Emby.Naming/Common/EpisodeExpression.cs
  10. 2 0
      Emby.Naming/Common/MediaType.cs
  11. 39 36
      Emby.Naming/Common/NamingOptions.cs
  12. 13 1
      Emby.Naming/Emby.Naming.csproj
  13. 1 0
      Emby.Naming/Extensions/StringExtensions.cs
  14. 0 30
      Emby.Naming/StringExtensions.cs
  15. 3 0
      Emby.Naming/Subtitles/SubtitleInfo.cs
  16. 11 0
      Emby.Naming/TV/EpisodeInfo.cs
  17. 23 28
      Emby.Naming/TV/EpisodePathParser.cs
  18. 7 0
      Emby.Naming/TV/EpisodePathParserResult.cs
  19. 9 3
      Emby.Naming/TV/EpisodeResolver.cs
  20. 20 22
      Emby.Naming/TV/SeasonPathParser.cs
  21. 2 0
      Emby.Naming/TV/SeasonPathParserResult.cs
  22. 10 10
      Emby.Naming/Video/CleanDateTimeParser.cs
  23. 0 2
      Emby.Naming/Video/ExtraResolver.cs
  24. 2 2
      Emby.Naming/Video/FileStack.cs
  25. 7 3
      Emby.Naming/Video/Format3DParser.cs
  26. 7 5
      Emby.Naming/Video/Format3DResult.cs
  27. 13 6
      Emby.Naming/Video/StackResolver.cs
  28. 20 12
      Emby.Naming/Video/StubResolver.cs
  29. 1 0
      Emby.Naming/Video/StubResult.cs
  30. 1 0
      Emby.Naming/Video/StubTypeRule.cs
  31. 11 1
      Emby.Naming/Video/VideoFileInfo.cs
  32. 4 0
      Emby.Naming/Video/VideoInfo.cs
  33. 18 22
      Emby.Naming/Video/VideoListResolver.cs
  34. 7 5
      Emby.Naming/Video/VideoResolver.cs
  35. 2 2
      Emby.Server.Implementations/Emby.Server.Implementations.csproj
  36. 1 1
      Emby.Server.Implementations/Library/LibraryManager.cs
  37. 1 1
      Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
  38. 1 3
      Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
  39. 3 3
      Jellyfin.Server/Jellyfin.Server.csproj
  40. 5 1
      Jellyfin.Server/Program.cs
  41. 5 0
      jellyfin.ruleset

+ 14 - 12
Emby.Naming/Audio/AlbumParser.cs

@@ -33,27 +33,29 @@ namespace Emby.Naming.Audio
 
 
             // Normalize
             // Normalize
             // Remove whitespace
             // Remove whitespace
-            filename = filename.Replace("-", " ");
-            filename = filename.Replace(".", " ");
-            filename = filename.Replace("(", " ");
-            filename = filename.Replace(")", " ");
+            filename = filename.Replace('-', ' ');
+            filename = filename.Replace('.', ' ');
+            filename = filename.Replace('(', ' ');
+            filename = filename.Replace(')', ' ');
             filename = Regex.Replace(filename, @"\s+", " ");
             filename = Regex.Replace(filename, @"\s+", " ");
 
 
             filename = filename.TrimStart();
             filename = filename.TrimStart();
 
 
             foreach (var prefix in _options.AlbumStackingPrefixes)
             foreach (var prefix in _options.AlbumStackingPrefixes)
             {
             {
-                if (filename.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) == 0)
+                if (filename.IndexOf(prefix, StringComparison.OrdinalIgnoreCase) != 0)
                 {
                 {
-                    var tmp = filename.Substring(prefix.Length);
+                    continue;
+                }
+
+                var tmp = filename.Substring(prefix.Length);
 
 
-                    tmp = tmp.Trim().Split(' ').FirstOrDefault() ?? string.Empty;
+                tmp = tmp.Trim().Split(' ').FirstOrDefault() ?? string.Empty;
 
 
-                    if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
-                    {
-                        result.IsMultiPart = true;
-                        break;
-                    }
+                if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
+                {
+                    result.IsMultiPart = true;
+                    break;
                 }
                 }
             }
             }
 
 

+ 2 - 0
Emby.Naming/Audio/MultiPartResult.cs

@@ -7,11 +7,13 @@ namespace Emby.Naming.Audio
         /// </summary>
         /// </summary>
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the part.
         /// Gets or sets the part.
         /// </summary>
         /// </summary>
         /// <value>The part.</value>
         /// <value>The part.</value>
         public string Part { get; set; }
         public string Part { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is multi part.
         /// Gets or sets a value indicating whether this instance is multi part.
         /// </summary>
         /// </summary>

+ 25 - 4
Emby.Naming/AudioBook/AudioBookFileInfo.cs

@@ -12,35 +12,56 @@ namespace Emby.Naming.AudioBook
         /// </summary>
         /// </summary>
         /// <value>The path.</value>
         /// <value>The path.</value>
         public string Path { get; set; }
         public string Path { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the container.
         /// Gets or sets the container.
         /// </summary>
         /// </summary>
         /// <value>The container.</value>
         /// <value>The container.</value>
         public string Container { get; set; }
         public string Container { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the part number.
         /// Gets or sets the part number.
         /// </summary>
         /// </summary>
         /// <value>The part number.</value>
         /// <value>The part number.</value>
         public int? PartNumber { get; set; }
         public int? PartNumber { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the chapter number.
         /// Gets or sets the chapter number.
         /// </summary>
         /// </summary>
         /// <value>The chapter number.</value>
         /// <value>The chapter number.</value>
         public int? ChapterNumber { get; set; }
         public int? ChapterNumber { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type.
         /// Gets or sets the type.
         /// </summary>
         /// </summary>
         /// <value>The type.</value>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }
         public bool IsDirectory { get; set; }
 
 
+        /// <inheritdoc/>
         public int CompareTo(AudioBookFileInfo other)
         public int CompareTo(AudioBookFileInfo other)
         {
         {
-            if (ReferenceEquals(this, other)) return 0;
-            if (ReferenceEquals(null, other)) return 1;
+            if (ReferenceEquals(this, other))
+            {
+                return 0;
+            }
+
+            if (ReferenceEquals(null, other))
+            {
+                return 1;
+            }
+
             var chapterNumberComparison = Nullable.Compare(ChapterNumber, other.ChapterNumber);
             var chapterNumberComparison = Nullable.Compare(ChapterNumber, other.ChapterNumber);
-            if (chapterNumberComparison != 0) return chapterNumberComparison;
+            if (chapterNumberComparison != 0)
+            {
+                return chapterNumberComparison;
+            }
+
             var partNumberComparison = Nullable.Compare(PartNumber, other.PartNumber);
             var partNumberComparison = Nullable.Compare(PartNumber, other.PartNumber);
-            if (partNumberComparison != 0) return partNumberComparison;
+            if (partNumberComparison != 0)
+            {
+                return partNumberComparison;
+            }
+
             return string.Compare(Path, other.Path, StringComparison.Ordinal);
             return string.Compare(Path, other.Path, StringComparison.Ordinal);
         }
         }
     }
     }

+ 7 - 6
Emby.Naming/AudioBook/AudioBookFilePathParser.cs

@@ -1,3 +1,4 @@
+using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
@@ -14,14 +15,13 @@ namespace Emby.Naming.AudioBook
             _options = options;
             _options = options;
         }
         }
 
 
-        public AudioBookFilePathParserResult Parse(string path, bool IsDirectory)
+        public AudioBookFilePathParserResult Parse(string path)
         {
         {
-            var result = Parse(path);
-            return !result.Success ? new AudioBookFilePathParserResult() : result;
-        }
+            if (path == null)
+            {
+                throw new ArgumentNullException(nameof(path));
+            }
 
 
-        private AudioBookFilePathParserResult Parse(string path)
-        {
             var result = new AudioBookFilePathParserResult();
             var result = new AudioBookFilePathParserResult();
             var fileName = Path.GetFileNameWithoutExtension(path);
             var fileName = Path.GetFileNameWithoutExtension(path);
             foreach (var expression in _options.AudioBookPartsExpressions)
             foreach (var expression in _options.AudioBookPartsExpressions)
@@ -40,6 +40,7 @@ namespace Emby.Naming.AudioBook
                             }
                             }
                         }
                         }
                     }
                     }
+
                     if (!result.PartNumber.HasValue)
                     if (!result.PartNumber.HasValue)
                     {
                     {
                         var value = match.Groups["part"];
                         var value = match.Groups["part"];

+ 2 - 0
Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs

@@ -3,7 +3,9 @@ namespace Emby.Naming.AudioBook
     public class AudioBookFilePathParserResult
     public class AudioBookFilePathParserResult
     {
     {
         public int? PartNumber { get; set; }
         public int? PartNumber { get; set; }
+
         public int? ChapterNumber { get; set; }
         public int? ChapterNumber { get; set; }
+
         public bool Success { get; set; }
         public bool Success { get; set; }
     }
     }
 }
 }

+ 14 - 7
Emby.Naming/AudioBook/AudioBookInfo.cs

@@ -7,33 +7,40 @@ namespace Emby.Naming.AudioBook
     /// </summary>
     /// </summary>
     public class AudioBookInfo
     public class AudioBookInfo
     {
     {
+        public AudioBookInfo()
+        {
+            Files = new List<AudioBookFileInfo>();
+            Extras = new List<AudioBookFileInfo>();
+            AlternateVersions = new List<AudioBookFileInfo>();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the name.
         /// Gets or sets the name.
         /// </summary>
         /// </summary>
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the year.
+        /// </summary>
         public int? Year { get; set; }
         public int? Year { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the files.
         /// Gets or sets the files.
         /// </summary>
         /// </summary>
         /// <value>The files.</value>
         /// <value>The files.</value>
         public List<AudioBookFileInfo> Files { get; set; }
         public List<AudioBookFileInfo> Files { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the extras.
         /// Gets or sets the extras.
         /// </summary>
         /// </summary>
         /// <value>The extras.</value>
         /// <value>The extras.</value>
         public List<AudioBookFileInfo> Extras { get; set; }
         public List<AudioBookFileInfo> Extras { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the alternate versions.
         /// Gets or sets the alternate versions.
         /// </summary>
         /// </summary>
         /// <value>The alternate versions.</value>
         /// <value>The alternate versions.</value>
         public List<AudioBookFileInfo> AlternateVersions { get; set; }
         public List<AudioBookFileInfo> AlternateVersions { get; set; }
-
-        public AudioBookInfo()
-        {
-            Files = new List<AudioBookFileInfo>();
-            Extras = new List<AudioBookFileInfo>();
-            AlternateVersions = new List<AudioBookFileInfo>();
-        }
     }
     }
 }
 }

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

@@ -15,7 +15,7 @@ namespace Emby.Naming.AudioBook
             _options = options;
             _options = options;
         }
         }
 
 
-        public IEnumerable<AudioBookInfo> Resolve(List<FileSystemMetadata> files)
+        public IEnumerable<AudioBookInfo> Resolve(IEnumerable<FileSystemMetadata> files)
         {
         {
             var audioBookResolver = new AudioBookResolver(_options);
             var audioBookResolver = new AudioBookResolver(_options);
 
 

+ 6 - 5
Emby.Naming/AudioBook/AudioBookResolver.cs

@@ -24,19 +24,21 @@ namespace Emby.Naming.AudioBook
             return Resolve(path, true);
             return Resolve(path, true);
         }
         }
 
 
-        public AudioBookFileInfo Resolve(string path, bool IsDirectory = false)
+        public AudioBookFileInfo Resolve(string path, bool isDirectory = false)
         {
         {
             if (string.IsNullOrEmpty(path))
             if (string.IsNullOrEmpty(path))
             {
             {
                 throw new ArgumentNullException(nameof(path));
                 throw new ArgumentNullException(nameof(path));
             }
             }
 
 
-            if (IsDirectory) // TODO
+            // TODO
+            if (isDirectory)
             {
             {
                 return null;
                 return null;
             }
             }
 
 
             var extension = Path.GetExtension(path);
             var extension = Path.GetExtension(path);
+
             // Check supported extensions
             // Check supported extensions
             if (!_options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
             if (!_options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
             {
             {
@@ -45,8 +47,7 @@ namespace Emby.Naming.AudioBook
 
 
             var container = extension.TrimStart('.');
             var container = extension.TrimStart('.');
 
 
-            var parsingResult = new AudioBookFilePathParser(_options)
-                .Parse(path, IsDirectory);
+            var parsingResult = new AudioBookFilePathParser(_options).Parse(path);
 
 
             return new AudioBookFileInfo
             return new AudioBookFileInfo
             {
             {
@@ -54,7 +55,7 @@ namespace Emby.Naming.AudioBook
                 Container = container,
                 Container = container,
                 PartNumber = parsingResult.PartNumber,
                 PartNumber = parsingResult.PartNumber,
                 ChapterNumber = parsingResult.ChapterNumber,
                 ChapterNumber = parsingResult.ChapterNumber,
-                IsDirectory = IsDirectory
+                IsDirectory = isDirectory
             };
             };
         }
         }
     }
     }

+ 14 - 3
Emby.Naming/Common/EpisodeExpression.cs

@@ -6,17 +6,28 @@ namespace Emby.Naming.Common
     public class EpisodeExpression
     public class EpisodeExpression
     {
     {
         private string _expression;
         private string _expression;
-        public string Expression { get => _expression;
-            set { _expression = value; _regex = null; } }
+        private Regex _regex;
+
+        public string Expression
+        {
+            get => _expression;
+            set
+            {
+                _expression = value;
+                _regex = null;
+            }
+        }
 
 
         public bool IsByDate { get; set; }
         public bool IsByDate { get; set; }
+
         public bool IsOptimistic { get; set; }
         public bool IsOptimistic { get; set; }
+
         public bool IsNamed { get; set; }
         public bool IsNamed { get; set; }
+
         public bool SupportsAbsoluteEpisodeNumbers { get; set; }
         public bool SupportsAbsoluteEpisodeNumbers { get; set; }
 
 
         public string[] DateTimeFormats { get; set; }
         public string[] DateTimeFormats { get; set; }
 
 
-        private Regex _regex;
         public Regex Regex => _regex ?? (_regex = new Regex(Expression, RegexOptions.IgnoreCase | RegexOptions.Compiled));
         public Regex Regex => _regex ?? (_regex = new Regex(Expression, RegexOptions.IgnoreCase | RegexOptions.Compiled));
 
 
         public EpisodeExpression(string expression, bool byDate)
         public EpisodeExpression(string expression, bool byDate)

+ 2 - 0
Emby.Naming/Common/MediaType.cs

@@ -6,10 +6,12 @@ namespace Emby.Naming.Common
         /// The audio
         /// The audio
         /// </summary>
         /// </summary>
         Audio = 0,
         Audio = 0,
+
         /// <summary>
         /// <summary>
         /// The photo
         /// The photo
         /// </summary>
         /// </summary>
         Photo = 1,
         Photo = 1,
+
         /// <summary>
         /// <summary>
         /// The video
         /// The video
         /// </summary>
         /// </summary>

+ 39 - 36
Emby.Naming/Common/NamingOptions.cs

@@ -8,19 +8,25 @@ namespace Emby.Naming.Common
     public class NamingOptions
     public class NamingOptions
     {
     {
         public string[] AudioFileExtensions { get; set; }
         public string[] AudioFileExtensions { get; set; }
+
         public string[] AlbumStackingPrefixes { get; set; }
         public string[] AlbumStackingPrefixes { get; set; }
 
 
         public string[] SubtitleFileExtensions { get; set; }
         public string[] SubtitleFileExtensions { get; set; }
+
         public char[] SubtitleFlagDelimiters { get; set; }
         public char[] SubtitleFlagDelimiters { get; set; }
 
 
         public string[] SubtitleForcedFlags { get; set; }
         public string[] SubtitleForcedFlags { get; set; }
+
         public string[] SubtitleDefaultFlags { get; set; }
         public string[] SubtitleDefaultFlags { get; set; }
 
 
         public EpisodeExpression[] EpisodeExpressions { get; set; }
         public EpisodeExpression[] EpisodeExpressions { get; set; }
+
         public string[] EpisodeWithoutSeasonExpressions { get; set; }
         public string[] EpisodeWithoutSeasonExpressions { get; set; }
+
         public string[] EpisodeMultiPartExpressions { get; set; }
         public string[] EpisodeMultiPartExpressions { get; set; }
 
 
         public string[] VideoFileExtensions { get; set; }
         public string[] VideoFileExtensions { get; set; }
+
         public string[] StubFileExtensions { get; set; }
         public string[] StubFileExtensions { get; set; }
 
 
         public string[] AudioBookPartsExpressions { get; set; }
         public string[] AudioBookPartsExpressions { get; set; }
@@ -28,12 +34,14 @@ namespace Emby.Naming.Common
         public StubTypeRule[] StubTypes { get; set; }
         public StubTypeRule[] StubTypes { get; set; }
 
 
         public char[] VideoFlagDelimiters { get; set; }
         public char[] VideoFlagDelimiters { get; set; }
+
         public Format3DRule[] Format3DRules { get; set; }
         public Format3DRule[] Format3DRules { get; set; }
 
 
         public string[] VideoFileStackingExpressions { get; set; }
         public string[] VideoFileStackingExpressions { get; set; }
+
         public string[] CleanDateTimes { get; set; }
         public string[] CleanDateTimes { get; set; }
-        public string[] CleanStrings { get; set; }
 
 
+        public string[] CleanStrings { get; set; }
 
 
         public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
         public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
 
 
@@ -41,7 +49,7 @@ namespace Emby.Naming.Common
 
 
         public NamingOptions()
         public NamingOptions()
         {
         {
-            VideoFileExtensions = new string[]
+            VideoFileExtensions = new[]
             {
             {
                 ".m4v",
                 ".m4v",
                 ".3gp",
                 ".3gp",
@@ -106,53 +114,53 @@ namespace Emby.Naming.Common
             {
             {
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "dvd",
-                     Token = "dvd"
+                    StubType = "dvd",
+                    Token = "dvd"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "hddvd",
-                     Token = "hddvd"
+                    StubType = "hddvd",
+                    Token = "hddvd"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "bluray",
-                     Token = "bluray"
+                    StubType = "bluray",
+                    Token = "bluray"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "bluray",
-                     Token = "brrip"
+                    StubType = "bluray",
+                    Token = "brrip"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "bluray",
-                     Token = "bd25"
+                    StubType = "bluray",
+                    Token = "bd25"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "bluray",
-                     Token = "bd50"
+                    StubType = "bluray",
+                    Token = "bd50"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "vhs",
-                     Token = "vhs"
+                    StubType = "vhs",
+                    Token = "vhs"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "tv",
-                     Token = "HDTV"
+                    StubType = "tv",
+                    Token = "HDTV"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "tv",
-                     Token = "PDTV"
+                    StubType = "tv",
+                    Token = "PDTV"
                 },
                 },
                 new StubTypeRule
                 new StubTypeRule
                 {
                 {
-                     StubType = "tv",
-                     Token = "DSR"
+                    StubType = "tv",
+                    Token = "DSR"
                 }
                 }
             };
             };
 
 
@@ -286,7 +294,7 @@ namespace Emby.Naming.Common
                 new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
                 new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
                 new EpisodeExpression("([0-9]{4})[\\.-]([0-9]{2})[\\.-]([0-9]{2})", true)
                 new EpisodeExpression("([0-9]{4})[\\.-]([0-9]{2})[\\.-]([0-9]{2})", true)
                 {
                 {
-                    DateTimeFormats = new []
+                    DateTimeFormats = new[]
                     {
                     {
                         "yyyy.MM.dd",
                         "yyyy.MM.dd",
                         "yyyy-MM-dd",
                         "yyyy-MM-dd",
@@ -295,7 +303,7 @@ namespace Emby.Naming.Common
                 },
                 },
                 new EpisodeExpression("([0-9]{2})[\\.-]([0-9]{2})[\\.-]([0-9]{4})", true)
                 new EpisodeExpression("([0-9]{2})[\\.-]([0-9]{2})[\\.-]([0-9]{4})", true)
                 {
                 {
-                    DateTimeFormats = new []
+                    DateTimeFormats = new[]
                     {
                     {
                         "dd.MM.yyyy",
                         "dd.MM.yyyy",
                         "dd-MM-yyyy",
                         "dd-MM-yyyy",
@@ -348,9 +356,7 @@ namespace Emby.Naming.Common
                 },
                 },
 
 
                 // "1-12 episode title"
                 // "1-12 episode title"
-                new EpisodeExpression(@"([0-9]+)-([0-9]+)")
-                {
-                },
+                new EpisodeExpression(@"([0-9]+)-([0-9]+)"),
 
 
                 // "01 - blah.avi", "01-blah.avi"
                 // "01 - blah.avi", "01-blah.avi"
                 new EpisodeExpression(@".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\s?-\s?[^\\\/]*$")
                 new EpisodeExpression(@".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\s?-\s?[^\\\/]*$")
@@ -427,7 +433,7 @@ namespace Emby.Naming.Common
                     Token = "_trailer",
                     Token = "_trailer",
                     MediaType = MediaType.Video
                     MediaType = MediaType.Video
                 },
                 },
-                 new ExtraRule
+                new ExtraRule
                 {
                 {
                     ExtraType = "trailer",
                     ExtraType = "trailer",
                     RuleType = ExtraRuleType.Suffix,
                     RuleType = ExtraRuleType.Suffix,
@@ -462,7 +468,7 @@ namespace Emby.Naming.Common
                     Token = "_sample",
                     Token = "_sample",
                     MediaType = MediaType.Video
                     MediaType = MediaType.Video
                 },
                 },
-                 new ExtraRule
+                new ExtraRule
                 {
                 {
                     ExtraType = "sample",
                     ExtraType = "sample",
                     RuleType = ExtraRuleType.Suffix,
                     RuleType = ExtraRuleType.Suffix,
@@ -476,7 +482,6 @@ namespace Emby.Naming.Common
                     Token = "theme",
                     Token = "theme",
                     MediaType = MediaType.Audio
                     MediaType = MediaType.Audio
                 },
                 },
-
                 new ExtraRule
                 new ExtraRule
                 {
                 {
                     ExtraType = "scene",
                     ExtraType = "scene",
@@ -526,8 +531,8 @@ namespace Emby.Naming.Common
                     Token = "-short",
                     Token = "-short",
                     MediaType = MediaType.Video
                     MediaType = MediaType.Video
                 }
                 }
-
             };
             };
+
             Format3DRules = new[]
             Format3DRules = new[]
             {
             {
                 // Kodi rules:
                 // Kodi rules:
@@ -648,12 +653,10 @@ namespace Emby.Naming.Common
                 @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
                 @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$",
                 @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
                 @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$",
                 @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$"
                 @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$"
-
             }.Select(i => new EpisodeExpression(i)
             }.Select(i => new EpisodeExpression(i)
-            {
-                IsNamed = true
-
-            }).ToArray();
+                {
+                    IsNamed = true
+                }).ToArray();
 
 
             VideoFileExtensions = extensions
             VideoFileExtensions = extensions
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .Distinct(StringComparer.OrdinalIgnoreCase)

+ 13 - 1
Emby.Naming/Emby.Naming.csproj

@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>netstandard2.0</TargetFramework>
     <TargetFramework>netstandard2.0</TargetFramework>
@@ -18,6 +18,18 @@
     <PackageId>Jellyfin.Naming</PackageId>
     <PackageId>Jellyfin.Naming</PackageId>
     <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl>
     <PackageLicenseUrl>https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt</PackageLicenseUrl>
     <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
     <RepositoryUrl>https://github.com/jellyfin/jellyfin</RepositoryUrl>
+    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+  </PropertyGroup>
+
+  <!-- Code analysers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.2" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
   </PropertyGroup>
   </PropertyGroup>
 
 
 </Project>
 </Project>

+ 1 - 0
Emby.Naming/Extensions/StringExtensions.cs

@@ -5,6 +5,7 @@ namespace Emby.Naming.Extensions
 {
 {
     public static class StringExtensions
     public static class StringExtensions
     {
     {
+        // TODO: @bond remove this when moving to netstandard2.1
         public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
         public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
         {
         {
             var sb = new StringBuilder();
             var sb = new StringBuilder();

+ 0 - 30
Emby.Naming/StringExtensions.cs

@@ -1,30 +0,0 @@
-using System;
-using System.Text;
-
-namespace Emby.Naming
-{
-    internal static class StringExtensions
-    {
-        public static string Replace(this string str, string oldValue, string newValue, StringComparison comparison)
-        {
-            var sb = new StringBuilder();
-
-            var previousIndex = 0;
-            var index = str.IndexOf(oldValue, comparison);
-
-            while (index != -1)
-            {
-                sb.Append(str.Substring(previousIndex, index - previousIndex));
-                sb.Append(newValue);
-                index += oldValue.Length;
-
-                previousIndex = index;
-                index = str.IndexOf(oldValue, index, comparison);
-            }
-
-            sb.Append(str.Substring(previousIndex));
-
-            return sb.ToString();
-        }
-    }
-}

+ 3 - 0
Emby.Naming/Subtitles/SubtitleInfo.cs

@@ -7,16 +7,19 @@ namespace Emby.Naming.Subtitles
         /// </summary>
         /// </summary>
         /// <value>The path.</value>
         /// <value>The path.</value>
         public string Path { get; set; }
         public string Path { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the language.
         /// Gets or sets the language.
         /// </summary>
         /// </summary>
         /// <value>The language.</value>
         /// <value>The language.</value>
         public string Language { get; set; }
         public string Language { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is default.
         /// Gets or sets a value indicating whether this instance is default.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is default; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is default; otherwise, <c>false</c>.</value>
         public bool IsDefault { get; set; }
         public bool IsDefault { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is forced.
         /// Gets or sets a value indicating whether this instance is forced.
         /// </summary>
         /// </summary>

+ 11 - 0
Emby.Naming/TV/EpisodeInfo.cs

@@ -7,31 +7,37 @@ namespace Emby.Naming.TV
         /// </summary>
         /// </summary>
         /// <value>The path.</value>
         /// <value>The path.</value>
         public string Path { get; set; }
         public string Path { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the container.
         /// Gets or sets the container.
         /// </summary>
         /// </summary>
         /// <value>The container.</value>
         /// <value>The container.</value>
         public string Container { get; set; }
         public string Container { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the name of the series.
         /// Gets or sets the name of the series.
         /// </summary>
         /// </summary>
         /// <value>The name of the series.</value>
         /// <value>The name of the series.</value>
         public string SeriesName { get; set; }
         public string SeriesName { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the format3 d.
         /// Gets or sets the format3 d.
         /// </summary>
         /// </summary>
         /// <value>The format3 d.</value>
         /// <value>The format3 d.</value>
         public string Format3D { get; set; }
         public string Format3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [is3 d].
         /// Gets or sets a value indicating whether [is3 d].
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         public bool Is3D { get; set; }
         public bool Is3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is stub.
         /// Gets or sets a value indicating whether this instance is stub.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         public bool IsStub { get; set; }
         public bool IsStub { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type of the stub.
         /// Gets or sets the type of the stub.
         /// </summary>
         /// </summary>
@@ -39,12 +45,17 @@ namespace Emby.Naming.TV
         public string StubType { get; set; }
         public string StubType { get; set; }
 
 
         public int? SeasonNumber { get; set; }
         public int? SeasonNumber { get; set; }
+
         public int? EpisodeNumber { get; set; }
         public int? EpisodeNumber { get; set; }
+
         public int? EndingEpsiodeNumber { get; set; }
         public int? EndingEpsiodeNumber { get; set; }
 
 
         public int? Year { get; set; }
         public int? Year { get; set; }
+
         public int? Month { get; set; }
         public int? Month { get; set; }
+
         public int? Day { get; set; }
         public int? Day { get; set; }
+
         public bool IsByDate { get; set; }
         public bool IsByDate { get; set; }
     }
     }
 }
 }

+ 23 - 28
Emby.Naming/TV/EpisodePathParser.cs

@@ -15,12 +15,12 @@ namespace Emby.Naming.TV
             _options = options;
             _options = options;
         }
         }
 
 
-        public EpisodePathParserResult Parse(string path, bool IsDirectory, bool? isNamed = null, bool? isOptimistic = null, bool? supportsAbsoluteNumbers = null, bool fillExtendedInfo = true)
+        public EpisodePathParserResult Parse(string path, bool isDirectory, bool? isNamed = null, bool? isOptimistic = null, bool? supportsAbsoluteNumbers = null, bool fillExtendedInfo = true)
         {
         {
             // Added to be able to use regex patterns which require a file extension.
             // Added to be able to use regex patterns which require a file extension.
             // There were no failed tests without this block, but to be safe, we can keep it until
             // There were no failed tests without this block, but to be safe, we can keep it until
             // the regex which require file extensions are modified so that they don't need them.
             // the regex which require file extensions are modified so that they don't need them.
-            if (IsDirectory)
+            if (isDirectory)
             {
             {
                 path += ".mp4";
                 path += ".mp4";
             }
             }
@@ -29,28 +29,20 @@ namespace Emby.Naming.TV
 
 
             foreach (var expression in _options.EpisodeExpressions)
             foreach (var expression in _options.EpisodeExpressions)
             {
             {
-                if (supportsAbsoluteNumbers.HasValue)
+                if (supportsAbsoluteNumbers.HasValue
+                    && expression.SupportsAbsoluteEpisodeNumbers != supportsAbsoluteNumbers.Value)
                 {
                 {
-                    if (expression.SupportsAbsoluteEpisodeNumbers != supportsAbsoluteNumbers.Value)
-                    {
-                        continue;
-                    }
+                    continue;
                 }
                 }
 
 
-                if (isNamed.HasValue)
+                if (isNamed.HasValue && expression.IsNamed != isNamed.Value)
                 {
                 {
-                    if (expression.IsNamed != isNamed.Value)
-                    {
-                        continue;
-                    }
+                    continue;
                 }
                 }
 
 
-                if (isOptimistic.HasValue)
+                if (isOptimistic.HasValue && expression.IsOptimistic != isOptimistic.Value)
                 {
                 {
-                    if (expression.IsOptimistic != isOptimistic.Value)
-                    {
-                        continue;
-                    }
+                    continue;
                 }
                 }
 
 
                 var currentResult = Parse(path, expression);
                 var currentResult = Parse(path, expression);
@@ -97,7 +89,8 @@ namespace Emby.Naming.TV
                     DateTime date;
                     DateTime date;
                     if (expression.DateTimeFormats.Length > 0)
                     if (expression.DateTimeFormats.Length > 0)
                     {
                     {
-                        if (DateTime.TryParseExact(match.Groups[0].Value,
+                        if (DateTime.TryParseExact(
+                            match.Groups[0].Value,
                             expression.DateTimeFormats,
                             expression.DateTimeFormats,
                             CultureInfo.InvariantCulture,
                             CultureInfo.InvariantCulture,
                             DateTimeStyles.None,
                             DateTimeStyles.None,
@@ -109,15 +102,12 @@ namespace Emby.Naming.TV
                             result.Success = true;
                             result.Success = true;
                         }
                         }
                     }
                     }
-                    else
+                    else if (DateTime.TryParse(match.Groups[0].Value, out date))
                     {
                     {
-                        if (DateTime.TryParse(match.Groups[0].Value, out date))
-                        {
-                            result.Year = date.Year;
-                            result.Month = date.Month;
-                            result.Day = date.Day;
-                            result.Success = true;
-                        }
+                        result.Year = date.Year;
+                        result.Month = date.Month;
+                        result.Day = date.Day;
+                        result.Success = true;
                     }
                     }
 
 
                     // TODO: Only consider success if date successfully parsed?
                     // TODO: Only consider success if date successfully parsed?
@@ -142,7 +132,8 @@ namespace Emby.Naming.TV
                         // or a 'p' or 'i' as what you would get with a pixel resolution specification.
                         // or a 'p' or 'i' as what you would get with a pixel resolution specification.
                         // It avoids erroneous parsing of something like "series-s09e14-1080p.mkv" as a multi-episode from E14 to E108
                         // It avoids erroneous parsing of something like "series-s09e14-1080p.mkv" as a multi-episode from E14 to E108
                         int nextIndex = endingNumberGroup.Index + endingNumberGroup.Length;
                         int nextIndex = endingNumberGroup.Index + endingNumberGroup.Length;
-                        if (nextIndex >= name.Length || "0123456789iIpP".IndexOf(name[nextIndex]) == -1)
+                        if (nextIndex >= name.Length
+                            || "0123456789iIpP".IndexOf(name[nextIndex]) == -1)
                         {
                         {
                             if (int.TryParse(endingNumberGroup.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                             if (int.TryParse(endingNumberGroup.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                             {
                             {
@@ -160,6 +151,7 @@ namespace Emby.Naming.TV
                     {
                     {
                         result.SeasonNumber = num;
                         result.SeasonNumber = num;
                     }
                     }
+
                     if (int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                     if (int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                     {
                     {
                         result.EpisodeNumber = num;
                         result.EpisodeNumber = num;
@@ -171,8 +163,11 @@ namespace Emby.Naming.TV
                 // Invalidate match when the season is 200 through 1927 or above 2500
                 // Invalidate match when the season is 200 through 1927 or above 2500
                 // because it is an error unless the TV show is intentionally using false season numbers.
                 // because it is an error unless the TV show is intentionally using false season numbers.
                 // It avoids erroneous parsing of something like "Series Special (1920x1080).mkv" as being season 1920 episode 1080.
                 // It avoids erroneous parsing of something like "Series Special (1920x1080).mkv" as being season 1920 episode 1080.
-                if (result.SeasonNumber >= 200 && result.SeasonNumber < 1928 || result.SeasonNumber > 2500)
+                if ((result.SeasonNumber >= 200 && result.SeasonNumber < 1928)
+                    || result.SeasonNumber > 2500)
+                {
                     result.Success = false;
                     result.Success = false;
+                }
 
 
                 result.IsByDate = expression.IsByDate;
                 result.IsByDate = expression.IsByDate;
             }
             }

+ 7 - 0
Emby.Naming/TV/EpisodePathParserResult.cs

@@ -3,14 +3,21 @@ namespace Emby.Naming.TV
     public class EpisodePathParserResult
     public class EpisodePathParserResult
     {
     {
         public int? SeasonNumber { get; set; }
         public int? SeasonNumber { get; set; }
+
         public int? EpisodeNumber { get; set; }
         public int? EpisodeNumber { get; set; }
+
         public int? EndingEpsiodeNumber { get; set; }
         public int? EndingEpsiodeNumber { get; set; }
+
         public string SeriesName { get; set; }
         public string SeriesName { get; set; }
+
         public bool Success { get; set; }
         public bool Success { get; set; }
 
 
         public bool IsByDate { get; set; }
         public bool IsByDate { get; set; }
+
         public int? Year { get; set; }
         public int? Year { get; set; }
+
         public int? Month { get; set; }
         public int? Month { get; set; }
+
         public int? Day { get; set; }
         public int? Day { get; set; }
     }
     }
 }
 }

+ 9 - 3
Emby.Naming/TV/EpisodeResolver.cs

@@ -15,7 +15,13 @@ namespace Emby.Naming.TV
             _options = options;
             _options = options;
         }
         }
 
 
-        public EpisodeInfo Resolve(string path, bool IsDirectory, bool? isNamed = null, bool? isOptimistic = null, bool? supportsAbsoluteNumbers = null, bool fillExtendedInfo = true)
+        public EpisodeInfo Resolve(
+            string path,
+            bool isDirectory,
+            bool? isNamed = null,
+            bool? isOptimistic = null,
+            bool? supportsAbsoluteNumbers = null,
+            bool fillExtendedInfo = true)
         {
         {
             if (string.IsNullOrEmpty(path))
             if (string.IsNullOrEmpty(path))
             {
             {
@@ -26,7 +32,7 @@ namespace Emby.Naming.TV
             string container = null;
             string container = null;
             string stubType = null;
             string stubType = null;
 
 
-            if (!IsDirectory)
+            if (!isDirectory)
             {
             {
                 var extension = Path.GetExtension(path);
                 var extension = Path.GetExtension(path);
                 // Check supported extensions
                 // Check supported extensions
@@ -52,7 +58,7 @@ namespace Emby.Naming.TV
             var format3DResult = new Format3DParser(_options).Parse(flags);
             var format3DResult = new Format3DParser(_options).Parse(flags);
 
 
             var parsingResult = new EpisodePathParser(_options)
             var parsingResult = new EpisodePathParser(_options)
-                .Parse(path, IsDirectory, isNamed, isOptimistic, supportsAbsoluteNumbers, fillExtendedInfo);
+                .Parse(path, isDirectory, isNamed, isOptimistic, supportsAbsoluteNumbers, fillExtendedInfo);
 
 
             return new EpisodeInfo
             return new EpisodeInfo
             {
             {

+ 20 - 22
Emby.Naming/TV/SeasonPathParser.cs

@@ -3,30 +3,24 @@ using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using Emby.Naming.Common;
 using Emby.Naming.Common;
+using Emby.Naming.Extensions;
 
 
 namespace Emby.Naming.TV
 namespace Emby.Naming.TV
 {
 {
     public class SeasonPathParser
     public class SeasonPathParser
     {
     {
-        private readonly NamingOptions _options;
-
-        public SeasonPathParser(NamingOptions options)
-        {
-            _options = options;
-        }
-
         public SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
         public SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
         {
         {
             var result = new SeasonPathParserResult();
             var result = new SeasonPathParserResult();
 
 
             var seasonNumberInfo = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
             var seasonNumberInfo = GetSeasonNumberFromPath(path, supportSpecialAliases, supportNumericSeasonFolders);
 
 
-            result.SeasonNumber = seasonNumberInfo.Item1;
+            result.SeasonNumber = seasonNumberInfo.seasonNumber;
 
 
             if (result.SeasonNumber.HasValue)
             if (result.SeasonNumber.HasValue)
             {
             {
                 result.Success = true;
                 result.Success = true;
-                result.IsSeasonFolder = seasonNumberInfo.Item2;
+                result.IsSeasonFolder = seasonNumberInfo.isSeasonFolder;
             }
             }
 
 
             return result;
             return result;
@@ -35,7 +29,7 @@ namespace Emby.Naming.TV
         /// <summary>
         /// <summary>
         /// A season folder must contain one of these somewhere in the name
         /// A season folder must contain one of these somewhere in the name
         /// </summary>
         /// </summary>
-        private static readonly string[] SeasonFolderNames =
+        private static readonly string[] _seasonFolderNames =
         {
         {
             "season",
             "season",
             "sæson",
             "sæson",
@@ -54,19 +48,23 @@ namespace Emby.Naming.TV
         /// <param name="supportSpecialAliases">if set to <c>true</c> [support special aliases].</param>
         /// <param name="supportSpecialAliases">if set to <c>true</c> [support special aliases].</param>
         /// <param name="supportNumericSeasonFolders">if set to <c>true</c> [support numeric season folders].</param>
         /// <param name="supportNumericSeasonFolders">if set to <c>true</c> [support numeric season folders].</param>
         /// <returns>System.Nullable{System.Int32}.</returns>
         /// <returns>System.Nullable{System.Int32}.</returns>
-        private Tuple<int?, bool> GetSeasonNumberFromPath(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
+        private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPath(
+            string path,
+            bool supportSpecialAliases,
+            bool supportNumericSeasonFolders)
         {
         {
-            var filename = Path.GetFileName(path);
+            var filename = Path.GetFileName(path) ?? string.Empty;
 
 
             if (supportSpecialAliases)
             if (supportSpecialAliases)
             {
             {
                 if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    return new Tuple<int?, bool>(0, true);
+                    return (0, true);
                 }
                 }
+
                 if (string.Equals(filename, "extras", StringComparison.OrdinalIgnoreCase))
                 if (string.Equals(filename, "extras", StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    return new Tuple<int?, bool>(0, true);
+                    return (0, true);
                 }
                 }
             }
             }
 
 
@@ -74,7 +72,7 @@ namespace Emby.Naming.TV
             {
             {
                 if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 {
                 {
-                    return new Tuple<int?, bool>(val, true);
+                    return (val, true);
                 }
                 }
             }
             }
 
 
@@ -84,12 +82,12 @@ namespace Emby.Naming.TV
 
 
                 if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
                 {
                 {
-                    return new Tuple<int?, bool>(val, true);
+                    return (val, true);
                 }
                 }
             }
             }
 
 
             // Look for one of the season folder names
             // Look for one of the season folder names
-            foreach (var name in SeasonFolderNames)
+            foreach (var name in _seasonFolderNames)
             {
             {
                 var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
                 var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase);
 
 
@@ -107,10 +105,10 @@ namespace Emby.Naming.TV
 
 
             var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
             var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
             var resultNumber = parts.Select(GetSeasonNumberFromPart).FirstOrDefault(i => i.HasValue);
             var resultNumber = parts.Select(GetSeasonNumberFromPart).FirstOrDefault(i => i.HasValue);
-            return new Tuple<int?, bool>(resultNumber, true);
+            return (resultNumber, true);
         }
         }
 
 
-        private int? GetSeasonNumberFromPart(string part)
+        private static int? GetSeasonNumberFromPart(string part)
         {
         {
             if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
             if (part.Length < 2 || !part.StartsWith("s", StringComparison.OrdinalIgnoreCase))
             {
             {
@@ -132,7 +130,7 @@ namespace Emby.Naming.TV
         /// </summary>
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
         /// <returns>System.Nullable{System.Int32}.</returns>
         /// <returns>System.Nullable{System.Int32}.</returns>
-        private Tuple<int?, bool> GetSeasonNumberFromPathSubstring(string path)
+        private static (int? seasonNumber, bool isSeasonFolder) GetSeasonNumberFromPathSubstring(string path)
         {
         {
             var numericStart = -1;
             var numericStart = -1;
             var length = 0;
             var length = 0;
@@ -174,10 +172,10 @@ namespace Emby.Naming.TV
 
 
             if (numericStart == -1)
             if (numericStart == -1)
             {
             {
-                return new Tuple<int?, bool>(null, isSeasonFolder);
+                return (null, isSeasonFolder);
             }
             }
 
 
-            return new Tuple<int?, bool>(int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture), isSeasonFolder);
+            return (int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture), isSeasonFolder);
         }
         }
     }
     }
 }
 }

+ 2 - 0
Emby.Naming/TV/SeasonPathParserResult.cs

@@ -7,11 +7,13 @@ namespace Emby.Naming.TV
         /// </summary>
         /// </summary>
         /// <value>The season number.</value>
         /// <value>The season number.</value>
         public int? SeasonNumber { get; set; }
         public int? SeasonNumber { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this <see cref="SeasonPathParserResult"/> is success.
         /// Gets or sets a value indicating whether this <see cref="SeasonPathParserResult"/> is success.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if success; otherwise, <c>false</c>.</value>
         public bool Success { get; set; }
         public bool Success { get; set; }
+
         public bool IsSeasonFolder { get; set; }
         public bool IsSeasonFolder { get; set; }
     }
     }
 }
 }

+ 10 - 10
Emby.Naming/Video/CleanDateTimeParser.cs

@@ -27,8 +27,8 @@ namespace Emby.Naming.Video
             {
             {
                 var extension = Path.GetExtension(name) ?? string.Empty;
                 var extension = Path.GetExtension(name) ?? string.Empty;
                 // Check supported extensions
                 // Check supported extensions
-                if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase) &&
-                    !_options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+                if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)
+                    && !_options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                 {
                 {
                     // Dummy up a file extension because the expressions will fail without one
                     // Dummy up a file extension because the expressions will fail without one
                     // This is tricky because we can't just check Path.GetExtension for empty
                     // This is tricky because we can't just check Path.GetExtension for empty
@@ -38,7 +38,6 @@ namespace Emby.Naming.Video
             }
             }
             catch (ArgumentException)
             catch (ArgumentException)
             {
             {
-
             }
             }
 
 
             var result = _options.CleanDateTimeRegexes.Select(i => Clean(name, i))
             var result = _options.CleanDateTimeRegexes.Select(i => Clean(name, i))
@@ -69,14 +68,15 @@ namespace Emby.Naming.Video
 
 
             var match = expression.Match(name);
             var match = expression.Match(name);
 
 
-            if (match.Success && match.Groups.Count == 4)
+            if (match.Success
+                && match.Groups.Count == 4
+                && match.Groups[1].Success
+                && match.Groups[2].Success
+                && int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
             {
             {
-                if (match.Groups[1].Success && match.Groups[2].Success && int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
-                {
-                    name = match.Groups[1].Value;
-                    result.Year = year;
-                    result.HasChanged = true;
-                }
+                name = match.Groups[1].Value;
+                result.Year = year;
+                result.HasChanged = true;
             }
             }
 
 
             result.Name = name;
             result.Name = name;

+ 0 - 2
Emby.Naming/Video/ExtraResolver.cs

@@ -56,7 +56,6 @@ namespace Emby.Naming.Video
                     result.Rule = rule;
                     result.Rule = rule;
                 }
                 }
             }
             }
-
             else if (rule.RuleType == ExtraRuleType.Suffix)
             else if (rule.RuleType == ExtraRuleType.Suffix)
             {
             {
                 var filename = Path.GetFileNameWithoutExtension(path);
                 var filename = Path.GetFileNameWithoutExtension(path);
@@ -67,7 +66,6 @@ namespace Emby.Naming.Video
                     result.Rule = rule;
                     result.Rule = rule;
                 }
                 }
             }
             }
-
             else if (rule.RuleType == ExtraRuleType.Regex)
             else if (rule.RuleType == ExtraRuleType.Regex)
             {
             {
                 var filename = Path.GetFileName(path);
                 var filename = Path.GetFileName(path);

+ 2 - 2
Emby.Naming/Video/FileStack.cs

@@ -15,9 +15,9 @@ namespace Emby.Naming.Video
             Files = new List<string>();
             Files = new List<string>();
         }
         }
 
 
-        public bool ContainsFile(string file, bool IsDirectory)
+        public bool ContainsFile(string file, bool isDirectory)
         {
         {
-            if (IsDirectoryStack == IsDirectory)
+            if (IsDirectoryStack == isDirectory)
             {
             {
                 return Files.Contains(file, StringComparer.OrdinalIgnoreCase);
                 return Files.Contains(file, StringComparer.OrdinalIgnoreCase);
             }
             }

+ 7 - 3
Emby.Naming/Video/Format3DParser.cs

@@ -15,10 +15,12 @@ namespace Emby.Naming.Video
 
 
         public Format3DResult Parse(string path)
         public Format3DResult Parse(string path)
         {
         {
-            var delimeters = _options.VideoFlagDelimiters.ToList();
-            delimeters.Add(' ');
+            int oldLen = _options.VideoFlagDelimiters.Length;
+            var delimeters = new char[oldLen + 1];
+            _options.VideoFlagDelimiters.CopyTo(delimeters, 0);
+            delimeters[oldLen] = ' ';
 
 
-            return Parse(new FlagParser(_options).GetFlags(path, delimeters.ToArray()));
+            return Parse(new FlagParser(_options).GetFlags(path, delimeters));
         }
         }
 
 
         internal Format3DResult Parse(string[] videoFlags)
         internal Format3DResult Parse(string[] videoFlags)
@@ -66,8 +68,10 @@ namespace Emby.Naming.Video
                             format = flag;
                             format = flag;
                             result.Tokens.Add(rule.Token);
                             result.Tokens.Add(rule.Token);
                         }
                         }
+
                         break;
                         break;
                     }
                     }
+
                     foundPrefix = string.Equals(flag, rule.PreceedingToken, StringComparison.OrdinalIgnoreCase);
                     foundPrefix = string.Equals(flag, rule.PreceedingToken, StringComparison.OrdinalIgnoreCase);
                 }
                 }
 
 

+ 7 - 5
Emby.Naming/Video/Format3DResult.cs

@@ -4,25 +4,27 @@ namespace Emby.Naming.Video
 {
 {
     public class Format3DResult
     public class Format3DResult
     {
     {
+        public Format3DResult()
+        {
+            Tokens = new List<string>();
+        }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [is3 d].
         /// Gets or sets a value indicating whether [is3 d].
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         public bool Is3D { get; set; }
         public bool Is3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the format3 d.
         /// Gets or sets the format3 d.
         /// </summary>
         /// </summary>
         /// <value>The format3 d.</value>
         /// <value>The format3 d.</value>
         public string Format3D { get; set; }
         public string Format3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the tokens.
         /// Gets or sets the tokens.
         /// </summary>
         /// </summary>
         /// <value>The tokens.</value>
         /// <value>The tokens.</value>
         public List<string> Tokens { get; set; }
         public List<string> Tokens { get; set; }
-
-        public Format3DResult()
-        {
-            Tokens = new List<string>();
-        }
     }
     }
 }
 }

+ 13 - 6
Emby.Naming/Video/StackResolver.cs

@@ -40,17 +40,24 @@ namespace Emby.Naming.Video
             var result = new StackResult();
             var result = new StackResult();
             foreach (var directory in files.GroupBy(file => file.IsDirectory ? file.FullName : Path.GetDirectoryName(file.FullName)))
             foreach (var directory in files.GroupBy(file => file.IsDirectory ? file.FullName : Path.GetDirectoryName(file.FullName)))
             {
             {
-                var stack = new FileStack();
-                stack.Name = Path.GetFileName(directory.Key);
-                stack.IsDirectoryStack = false;
+                var stack = new FileStack()
+                {
+                    Name = Path.GetFileName(directory.Key),
+                    IsDirectoryStack = false
+                };
                 foreach (var file in directory)
                 foreach (var file in directory)
                 {
                 {
                     if (file.IsDirectory)
                     if (file.IsDirectory)
+                    {
                         continue;
                         continue;
+                    }
+
                     stack.Files.Add(file.FullName);
                     stack.Files.Add(file.FullName);
                 }
                 }
+
                 result.Stacks.Add(stack);
                 result.Stacks.Add(stack);
             }
             }
+
             return result;
             return result;
         }
         }
 
 
@@ -114,16 +121,16 @@ namespace Emby.Naming.Video
                                 {
                                 {
                                     if (!string.Equals(volume1, volume2, StringComparison.OrdinalIgnoreCase))
                                     if (!string.Equals(volume1, volume2, StringComparison.OrdinalIgnoreCase))
                                     {
                                     {
-                                        if (string.Equals(ignore1, ignore2, StringComparison.OrdinalIgnoreCase) &&
-                                            string.Equals(extension1, extension2, StringComparison.OrdinalIgnoreCase))
+                                        if (string.Equals(ignore1, ignore2, StringComparison.OrdinalIgnoreCase)
+                                            && string.Equals(extension1, extension2, StringComparison.OrdinalIgnoreCase))
                                         {
                                         {
                                             if (stack.Files.Count == 0)
                                             if (stack.Files.Count == 0)
                                             {
                                             {
                                                 stack.Name = title1 + ignore1;
                                                 stack.Name = title1 + ignore1;
                                                 stack.IsDirectoryStack = file1.IsDirectory;
                                                 stack.IsDirectoryStack = file1.IsDirectory;
-                                                //stack.Name = title1 + ignore1 + extension1;
                                                 stack.Files.Add(file1.FullName);
                                                 stack.Files.Add(file1.FullName);
                                             }
                                             }
+
                                             stack.Files.Add(file2.FullName);
                                             stack.Files.Add(file2.FullName);
                                         }
                                         }
                                         else
                                         else

+ 20 - 12
Emby.Naming/Video/StubResolver.cs

@@ -9,24 +9,32 @@ namespace Emby.Naming.Video
     {
     {
         public static StubResult ResolveFile(string path, NamingOptions options)
         public static StubResult ResolveFile(string path, NamingOptions options)
         {
         {
-            var result = new StubResult();
-            var extension = Path.GetExtension(path) ?? string.Empty;
+            if (path == null)
+            {
+                return default(StubResult);
+            }
+
+            var extension = Path.GetExtension(path);
 
 
-            if (options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
+            if (!options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
             {
             {
-                result.IsStub = true;
+                return default(StubResult);
+            }
 
 
-                path = Path.GetFileNameWithoutExtension(path);
+            var result = new StubResult()
+            {
+                IsStub = true
+            };
 
 
-                var token = (Path.GetExtension(path) ?? string.Empty).TrimStart('.');
+            path = Path.GetFileNameWithoutExtension(path);
+            var token = Path.GetExtension(path).TrimStart('.');
 
 
-                foreach (var rule in options.StubTypes)
+            foreach (var rule in options.StubTypes)
+            {
+                if (string.Equals(rule.Token, token, StringComparison.OrdinalIgnoreCase))
                 {
                 {
-                    if (string.Equals(rule.Token, token, StringComparison.OrdinalIgnoreCase))
-                    {
-                        result.StubType = rule.StubType;
-                        break;
-                    }
+                    result.StubType = rule.StubType;
+                    break;
                 }
                 }
             }
             }
 
 

+ 1 - 0
Emby.Naming/Video/StubResult.cs

@@ -7,6 +7,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         public bool IsStub { get; set; }
         public bool IsStub { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type of the stub.
         /// Gets or sets the type of the stub.
         /// </summary>
         /// </summary>

+ 1 - 0
Emby.Naming/Video/StubTypeRule.cs

@@ -7,6 +7,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// </summary>
         /// <value>The token.</value>
         /// <value>The token.</value>
         public string Token { get; set; }
         public string Token { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type of the stub.
         /// Gets or sets the type of the stub.
         /// </summary>
         /// </summary>

+ 11 - 1
Emby.Naming/Video/VideoFileInfo.cs

@@ -1,4 +1,3 @@
-
 namespace Emby.Naming.Video
 namespace Emby.Naming.Video
 {
 {
     /// <summary>
     /// <summary>
@@ -11,56 +10,67 @@ namespace Emby.Naming.Video
         /// </summary>
         /// </summary>
         /// <value>The path.</value>
         /// <value>The path.</value>
         public string Path { get; set; }
         public string Path { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the container.
         /// Gets or sets the container.
         /// </summary>
         /// </summary>
         /// <value>The container.</value>
         /// <value>The container.</value>
         public string Container { get; set; }
         public string Container { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the name.
         /// Gets or sets the name.
         /// </summary>
         /// </summary>
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the year.
         /// Gets or sets the year.
         /// </summary>
         /// </summary>
         /// <value>The year.</value>
         /// <value>The year.</value>
         public int? Year { get; set; }
         public int? Year { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type of the extra, e.g. trailer, theme song, behing the scenes, etc.
         /// Gets or sets the type of the extra, e.g. trailer, theme song, behing the scenes, etc.
         /// </summary>
         /// </summary>
         /// <value>The type of the extra.</value>
         /// <value>The type of the extra.</value>
         public string ExtraType { get; set; }
         public string ExtraType { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the extra rule.
         /// Gets or sets the extra rule.
         /// </summary>
         /// </summary>
         /// <value>The extra rule.</value>
         /// <value>The extra rule.</value>
         public ExtraRule ExtraRule { get; set; }
         public ExtraRule ExtraRule { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the format3 d.
         /// Gets or sets the format3 d.
         /// </summary>
         /// </summary>
         /// <value>The format3 d.</value>
         /// <value>The format3 d.</value>
         public string Format3D { get; set; }
         public string Format3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether [is3 d].
         /// Gets or sets a value indicating whether [is3 d].
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if [is3 d]; otherwise, <c>false</c>.</value>
         public bool Is3D { get; set; }
         public bool Is3D { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets a value indicating whether this instance is stub.
         /// Gets or sets a value indicating whether this instance is stub.
         /// </summary>
         /// </summary>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         /// <value><c>true</c> if this instance is stub; otherwise, <c>false</c>.</value>
         public bool IsStub { get; set; }
         public bool IsStub { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type of the stub.
         /// Gets or sets the type of the stub.
         /// </summary>
         /// </summary>
         /// <value>The type of the stub.</value>
         /// <value>The type of the stub.</value>
         public string StubType { get; set; }
         public string StubType { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the type.
         /// Gets or sets the type.
         /// </summary>
         /// </summary>
         /// <value>The type.</value>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }
         public bool IsDirectory { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets the file name without extension.
         /// Gets the file name without extension.
         /// </summary>
         /// </summary>

+ 4 - 0
Emby.Naming/Video/VideoInfo.cs

@@ -12,21 +12,25 @@ namespace Emby.Naming.Video
         /// </summary>
         /// </summary>
         /// <value>The name.</value>
         /// <value>The name.</value>
         public string Name { get; set; }
         public string Name { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the year.
         /// Gets or sets the year.
         /// </summary>
         /// </summary>
         /// <value>The year.</value>
         /// <value>The year.</value>
         public int? Year { get; set; }
         public int? Year { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the files.
         /// Gets or sets the files.
         /// </summary>
         /// </summary>
         /// <value>The files.</value>
         /// <value>The files.</value>
         public List<VideoFileInfo> Files { get; set; }
         public List<VideoFileInfo> Files { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the extras.
         /// Gets or sets the extras.
         /// </summary>
         /// </summary>
         /// <value>The extras.</value>
         /// <value>The extras.</value>
         public List<VideoFileInfo> Extras { get; set; }
         public List<VideoFileInfo> Extras { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets the alternate versions.
         /// Gets or sets the alternate versions.
         /// </summary>
         /// </summary>

+ 18 - 22
Emby.Naming/Video/VideoListResolver.cs

@@ -53,7 +53,7 @@ namespace Emby.Naming.Video
                     Name = stack.Name
                     Name = stack.Name
                 };
                 };
 
 
-                info.Year = info.Files.First().Year;
+                info.Year = info.Files[0].Year;
 
 
                 var extraBaseNames = new List<string>
                 var extraBaseNames = new List<string>
                 {
                 {
@@ -87,7 +87,7 @@ namespace Emby.Naming.Video
                     Name = media.Name
                     Name = media.Name
                 };
                 };
 
 
-                info.Year = info.Files.First().Year;
+                info.Year = info.Files[0].Year;
 
 
                 var extras = GetExtras(remainingFiles, new List<string> { media.FileNameWithoutExtension });
                 var extras = GetExtras(remainingFiles, new List<string> { media.FileNameWithoutExtension });
 
 
@@ -115,7 +115,7 @@ namespace Emby.Naming.Video
 
 
                 if (!string.IsNullOrEmpty(parentPath))
                 if (!string.IsNullOrEmpty(parentPath))
                 {
                 {
-                    var folderName = Path.GetFileName(Path.GetDirectoryName(videoPath));
+                    var folderName = Path.GetFileName(parentPath);
                     if (!string.IsNullOrEmpty(folderName))
                     if (!string.IsNullOrEmpty(folderName))
                     {
                     {
                         var extras = GetExtras(remainingFiles, new List<string> { folderName });
                         var extras = GetExtras(remainingFiles, new List<string> { folderName });
@@ -163,9 +163,7 @@ namespace Emby.Naming.Video
                 Year = i.Year
                 Year = i.Year
             }));
             }));
 
 
-            var orderedList = list.OrderBy(i => i.Name);
-
-            return orderedList;
+            return list.OrderBy(i => i.Name);
         }
         }
 
 
         private IEnumerable<VideoInfo> GetVideosGroupedByVersion(List<VideoInfo> videos)
         private IEnumerable<VideoInfo> GetVideosGroupedByVersion(List<VideoInfo> videos)
@@ -179,23 +177,21 @@ namespace Emby.Naming.Video
 
 
             var folderName = Path.GetFileName(Path.GetDirectoryName(videos[0].Files[0].Path));
             var folderName = Path.GetFileName(Path.GetDirectoryName(videos[0].Files[0].Path));
 
 
-            if (!string.IsNullOrEmpty(folderName) && folderName.Length > 1)
+            if (!string.IsNullOrEmpty(folderName)
+                && folderName.Length > 1
+                && videos.All(i => i.Files.Count == 1
+                && IsEligibleForMultiVersion(folderName, i.Files[0].Path))
+                && HaveSameYear(videos))
             {
             {
-                if (videos.All(i => i.Files.Count == 1 && IsEligibleForMultiVersion(folderName, i.Files[0].Path)))
-                {
-                    if (HaveSameYear(videos))
-                    {
-                        var ordered = videos.OrderBy(i => i.Name).ToList();
+                var ordered = videos.OrderBy(i => i.Name).ToList();
 
 
-                        list.Add(ordered[0]);
+                list.Add(ordered[0]);
 
 
-                        list[0].AlternateVersions = ordered.Skip(1).Select(i => i.Files[0]).ToList();
-                        list[0].Name = folderName;
-                        list[0].Extras.AddRange(ordered.Skip(1).SelectMany(i => i.Extras));
+                list[0].AlternateVersions = ordered.Skip(1).Select(i => i.Files[0]).ToList();
+                list[0].Name = folderName;
+                list[0].Extras.AddRange(ordered.Skip(1).SelectMany(i => i.Extras));
 
 
-                        return list;
-                    }
-                }
+                return list;
             }
             }
 
 
             return videos;
             return videos;
@@ -213,9 +209,9 @@ namespace Emby.Naming.Video
             if (testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
             if (testFilename.StartsWith(folderName, StringComparison.OrdinalIgnoreCase))
             {
             {
                 testFilename = testFilename.Substring(folderName.Length).Trim();
                 testFilename = testFilename.Substring(folderName.Length).Trim();
-                return string.IsNullOrEmpty(testFilename) ||
-                       testFilename.StartsWith("-") ||
-                       string.IsNullOrWhiteSpace(Regex.Replace(testFilename, @"\[([^]]*)\]", string.Empty)) ;
+                return string.IsNullOrEmpty(testFilename)
+                    || testFilename[0] == '-'
+                    || string.IsNullOrWhiteSpace(Regex.Replace(testFilename, @"\[([^]]*)\]", string.Empty));
             }
             }
 
 
             return false;
             return false;

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

@@ -38,10 +38,11 @@ namespace Emby.Naming.Video
         /// Resolves the specified path.
         /// Resolves the specified path.
         /// </summary>
         /// </summary>
         /// <param name="path">The path.</param>
         /// <param name="path">The path.</param>
-        /// <param name="IsDirectory">if set to <c>true</c> [is folder].</param>
+        /// <param name="isDirectory">if set to <c>true</c> [is folder].</param>
+        /// <param name="parseName">Whether or not the name should be parsed for info</param>
         /// <returns>VideoFileInfo.</returns>
         /// <returns>VideoFileInfo.</returns>
         /// <exception cref="ArgumentNullException">path</exception>
         /// <exception cref="ArgumentNullException">path</exception>
-        public VideoFileInfo Resolve(string path, bool IsDirectory, bool parseName = true)
+        public VideoFileInfo Resolve(string path, bool isDirectory, bool parseName = true)
         {
         {
             if (string.IsNullOrEmpty(path))
             if (string.IsNullOrEmpty(path))
             {
             {
@@ -52,9 +53,10 @@ namespace Emby.Naming.Video
             string container = null;
             string container = null;
             string stubType = null;
             string stubType = null;
 
 
-            if (!IsDirectory)
+            if (!isDirectory)
             {
             {
                 var extension = Path.GetExtension(path);
                 var extension = Path.GetExtension(path);
+
                 // Check supported extensions
                 // Check supported extensions
                 if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                 if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                 {
                 {
@@ -79,7 +81,7 @@ namespace Emby.Naming.Video
 
 
             var extraResult = new ExtraResolver(_options).GetExtraInfo(path);
             var extraResult = new ExtraResolver(_options).GetExtraInfo(path);
 
 
-            var name = IsDirectory
+            var name = isDirectory
                 ? Path.GetFileName(path)
                 ? Path.GetFileName(path)
                 : Path.GetFileNameWithoutExtension(path);
                 : Path.GetFileNameWithoutExtension(path);
 
 
@@ -108,7 +110,7 @@ namespace Emby.Naming.Video
                 Is3D = format3DResult.Is3D,
                 Is3D = format3DResult.Is3D,
                 Format3D = format3DResult.Format3D,
                 Format3D = format3DResult.Format3D,
                 ExtraType = extraResult.ExtraType,
                 ExtraType = extraResult.ExtraType,
-                IsDirectory = IsDirectory,
+                IsDirectory = isDirectory,
                 ExtraRule = extraResult.Rule
                 ExtraRule = extraResult.Rule
             };
             };
         }
         }

+ 2 - 2
Emby.Server.Implementations/Emby.Server.Implementations.csproj

@@ -52,8 +52,8 @@
 
 
   <!-- Code analysers-->
   <!-- Code analysers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.3" />
-    <PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.2" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 1 - 1
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -2368,7 +2368,7 @@ namespace Emby.Server.Implementations.Library
 
 
         public int? GetSeasonNumberFromPath(string path)
         public int? GetSeasonNumberFromPath(string path)
         {
         {
-            return new SeasonPathParser(GetNamingOptions()).Parse(path, true, true).SeasonNumber;
+            return new SeasonPathParser().Parse(path, true, true).SeasonNumber;
         }
         }
 
 
         public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)
         public bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh)

+ 1 - 1
Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs

@@ -52,7 +52,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 
 
                 var path = args.Path;
                 var path = args.Path;
 
 
-                var seasonParserResult = new SeasonPathParser(namingOptions).Parse(path, true, true);
+                var seasonParserResult = new SeasonPathParser().Parse(path, true, true);
 
 
                 var season = new Season
                 var season = new Season
                 {
                 {

+ 1 - 3
Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs

@@ -194,9 +194,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
         /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
         /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns>
         private static bool IsSeasonFolder(string path, bool isTvContentType, ILibraryManager libraryManager)
         private static bool IsSeasonFolder(string path, bool isTvContentType, ILibraryManager libraryManager)
         {
         {
-            var namingOptions = ((LibraryManager)libraryManager).GetNamingOptions();
-
-            var seasonNumber = new SeasonPathParser(namingOptions).Parse(path, isTvContentType, isTvContentType).SeasonNumber;
+            var seasonNumber = new SeasonPathParser().Parse(path, isTvContentType, isTvContentType).SeasonNumber;
 
 
             return seasonNumber.HasValue;
             return seasonNumber.HasValue;
         }
         }

+ 3 - 3
Jellyfin.Server/Jellyfin.Server.csproj

@@ -12,7 +12,7 @@
     <!-- We need C# 7.1 for async main-->
     <!-- We need C# 7.1 for async main-->
     <LangVersion>latest</LangVersion>
     <LangVersion>latest</LangVersion>
     <!-- Disable documentation warnings (for now) -->
     <!-- Disable documentation warnings (for now) -->
-    <NoWarn>SA1600;SA1601;CS1591</NoWarn>
+    <NoWarn>SA1600;SA1601;SA1629;CS1591</NoWarn>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
   </PropertyGroup>
 
 
@@ -26,8 +26,8 @@
 
 
   <!-- Code analysers-->
   <!-- Code analysers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.6.3" />
-    <PackageReference Include="StyleCop.Analyzers" Version="1.0.2" />
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.2" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" />
   </ItemGroup>
   </ItemGroup>
 
 

+ 5 - 1
Jellyfin.Server/Program.cs

@@ -122,8 +122,12 @@ namespace Jellyfin.Server
             // The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
             // The default connection limit is 10 for ASP.NET hosted applications and 2 for all others.
             ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
             ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
 
 
+// CA5359: Do Not Disable Certificate Validation
+#pragma warning disable CA5359
+
             // Allow all https requests
             // Allow all https requests
             ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
             ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
+#pragma warning restore CA5359
 
 
             var fileSystem = new ManagedFileSystem(_loggerFactory, appPaths);
             var fileSystem = new ManagedFileSystem(_loggerFactory, appPaths);
 
 
@@ -368,7 +372,7 @@ namespace Jellyfin.Server
             }
             }
             catch (Exception ex)
             catch (Exception ex)
             {
             {
-                _logger.LogInformation(ex, "Skia not available. Will fallback to NullIMageEncoder. {0}");
+                _logger.LogInformation(ex, "Skia not available. Will fallback to NullIMageEncoder.");
             }
             }
 
 
             return new NullImageEncoder();
             return new NullImageEncoder();

+ 5 - 0
jellyfin.ruleset

@@ -14,12 +14,17 @@
     <Rule Id="SA1200" Action="None" />
     <Rule Id="SA1200" Action="None" />
     <!-- disable warning SA1309: Fields must not begin with an underscore -->
     <!-- disable warning SA1309: Fields must not begin with an underscore -->
     <Rule Id="SA1309" Action="None" />
     <Rule Id="SA1309" Action="None" />
+    <!-- disable warning SA1413: Use trailing comma in multi-line initializers -->
+    <Rule Id="SA1413" Action="None" />
     <!-- disable warning SA1512: Single-line comments must not be followed by blank line -->
     <!-- disable warning SA1512: Single-line comments must not be followed by blank line -->
     <Rule Id="SA1512" Action="None" />
     <Rule Id="SA1512" Action="None" />
     <!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
     <!-- disable warning SA1633: The file header is missing or not located at the top of the file -->
     <Rule Id="SA1633" Action="None" />
     <Rule Id="SA1633" Action="None" />
   </Rules>
   </Rules>
+
   <Rules AnalyzerId="Microsoft.CodeAnalysis.FxCopAnalyzers" RuleNamespace="Microsoft.Design">
   <Rules AnalyzerId="Microsoft.CodeAnalysis.FxCopAnalyzers" RuleNamespace="Microsoft.Design">
+    <!-- disable warning CA1031: Do not catch general exception types -->
+    <Rule Id="CA1031" Action="Info" />
     <!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
     <!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
     <Rule Id="CA1822" Action="Info" />
     <Rule Id="CA1822" Action="Info" />