瀏覽代碼

Enable more analyser rules as errors

Also deduplicates a bit of code inside of SeasonPathParser and adds some more tests
Bond_009 10 月之前
父節點
當前提交
0a0de6708e

+ 6 - 9
Emby.Naming/TV/SeasonPathParser.cs

@@ -24,6 +24,8 @@ namespace Emby.Naming.TV
             "stagione"
         };
 
+        private static readonly char[] _splitChars = ['.', '_', ' ', '-'];
+
         /// <summary>
         /// Attempts to parse season number from path.
         /// </summary>
@@ -83,14 +85,9 @@ namespace Emby.Naming.TV
                 }
             }
 
-            if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase))
+            if (TryGetSeasonNumberFromPart(filename, out int seasonNumber))
             {
-                var testFilename = filename.AsSpan().Slice(1);
-
-                if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out var val))
-                {
-                    return (val, true);
-                }
+                return (seasonNumber, true);
             }
 
             // Look for one of the season folder names
@@ -108,10 +105,10 @@ namespace Emby.Naming.TV
                 }
             }
 
-            var parts = filename.Split(new[] { '.', '_', ' ', '-' }, StringSplitOptions.RemoveEmptyEntries);
+            var parts = filename.Split(_splitChars, StringSplitOptions.RemoveEmptyEntries);
             foreach (var part in parts)
             {
-                if (TryGetSeasonNumberFromPart(part, out int seasonNumber))
+                if (TryGetSeasonNumberFromPart(part, out seasonNumber))
                 {
                     return (seasonNumber, true);
                 }

+ 1 - 1
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -1304,7 +1304,7 @@ namespace MediaBrowser.Model.Dlna
 
                     // Check audio codec
                     MediaStream? selectedAudioStream = null;
-                    if (candidateAudioStreams.Any())
+                    if (candidateAudioStreams.Count != 0)
                     {
                         selectedAudioStream = candidateAudioStreams.FirstOrDefault(audioStream => directPlayProfile.SupportsAudioCodec(audioStream.Codec));
                         if (selectedAudioStream is null)

+ 22 - 0
jellyfin.ruleset

@@ -105,6 +105,28 @@
     <Rule Id="CA1851" Action="Error" />
     <!-- error on CA1854: Prefer a 'TryGetValue' call over a Dictionary indexer access guarded by a 'ContainsKey' check to avoid double lookup -->
     <Rule Id="CA1854" Action="Error" />
+    <!-- error on CA1860: Avoid using 'Enumerable.Any()' extension method -->
+    <Rule Id="CA1860" Action="Error" />
+    <!-- error on CA1862: Use the 'StringComparison' method overloads to perform case-insensitive string comparisons -->
+    <Rule Id="CA1862" Action="Error" />
+    <!-- error on CA1863: Use 'CompositeFormat' -->
+    <Rule Id="CA1863" Action="Error" />
+    <!-- error on CA1864: Prefer the 'IDictionary.TryAdd(TKey, TValue)' method -->
+    <Rule Id="CA1864" Action="Error" />
+    <!-- error on CA1865-CA1867: Use 'string.Method(char)' instead of 'string.Method(string)' for string with single char -->
+    <Rule Id="CA1865" Action="Error" />
+    <Rule Id="CA1866" Action="Error" />
+    <Rule Id="CA1867" Action="Error" />
+    <!-- error on CA1868: Unnecessary call to 'Contains' for sets -->
+    <Rule Id="CA1868" Action="Error" />
+    <!-- error on CA1869: Cache and reuse 'JsonSerializerOptions' instances -->
+    <Rule Id="CA1869" Action="Error" />
+    <!-- error on CA1870: Use a cached 'SearchValues' instance -->
+    <Rule Id="CA1870" Action="Error" />
+    <!-- error on CA1871: Do not pass a nullable struct to 'ArgumentNullException.ThrowIfNull' -->
+    <Rule Id="CA1871" Action="Error" />
+    <!-- error on CA1872: Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString' -->
+    <Rule Id="CA1872" Action="Error" />
     <!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
         or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
     <Rule Id="CA2016" Action="Error" />

+ 0 - 35
tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs

@@ -1,35 +0,0 @@
-using Emby.Naming.TV;
-using Xunit;
-
-namespace Jellyfin.Naming.Tests.TV
-{
-    public class SeasonFolderTests
-    {
-        [Theory]
-        [InlineData("/Drive/Season 1", 1, true)]
-        [InlineData("/Drive/Season 2", 2, true)]
-        [InlineData("/Drive/Season 02", 2, true)]
-        [InlineData("/Drive/Seinfeld/S02", 2, true)]
-        [InlineData("/Drive/Seinfeld/2", 2, true)]
-        [InlineData("/Drive/Season 2009", 2009, true)]
-        [InlineData("/Drive/Season1", 1, true)]
-        [InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)]
-        [InlineData("/Drive/Season 7 (2016)", 7, false)]
-        [InlineData("/Drive/Staffel 7 (2016)", 7, false)]
-        [InlineData("/Drive/Stagione 7 (2016)", 7, false)]
-        [InlineData("/Drive/Season (8)", null, false)]
-        [InlineData("/Drive/3.Staffel", 3, false)]
-        [InlineData("/Drive/s06e05", null, false)]
-        [InlineData("/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null, false)]
-        [InlineData("/Drive/extras", 0, true)]
-        [InlineData("/Drive/specials", 0, true)]
-        public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory)
-        {
-            var result = SeasonPathParser.Parse(path, true, true);
-
-            Assert.Equal(result.SeasonNumber is not null, result.Success);
-            Assert.Equal(result.SeasonNumber, seasonNumber);
-            Assert.Equal(isSeasonDirectory, result.IsSeasonFolder);
-        }
-    }
-}

+ 37 - 0
tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs

@@ -0,0 +1,37 @@
+using Emby.Naming.TV;
+using Xunit;
+
+namespace Jellyfin.Naming.Tests.TV;
+
+public class SeasonPathParserTests
+{
+    [Theory]
+    [InlineData("/Drive/Season 1", 1, true)]
+    [InlineData("/Drive/s1", 1, true)]
+    [InlineData("/Drive/S1", 1, true)]
+    [InlineData("/Drive/Season 2", 2, true)]
+    [InlineData("/Drive/Season 02", 2, true)]
+    [InlineData("/Drive/Seinfeld/S02", 2, true)]
+    [InlineData("/Drive/Seinfeld/2", 2, true)]
+    [InlineData("/Drive/Seinfeld - S02", 2, true)]
+    [InlineData("/Drive/Season 2009", 2009, true)]
+    [InlineData("/Drive/Season1", 1, true)]
+    [InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)]
+    [InlineData("/Drive/Season 7 (2016)", 7, false)]
+    [InlineData("/Drive/Staffel 7 (2016)", 7, false)]
+    [InlineData("/Drive/Stagione 7 (2016)", 7, false)]
+    [InlineData("/Drive/Season (8)", null, false)]
+    [InlineData("/Drive/3.Staffel", 3, false)]
+    [InlineData("/Drive/s06e05", null, false)]
+    [InlineData("/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null, false)]
+    [InlineData("/Drive/extras", 0, true)]
+    [InlineData("/Drive/specials", 0, true)]
+    public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory)
+    {
+        var result = SeasonPathParser.Parse(path, true, true);
+
+        Assert.Equal(result.SeasonNumber is not null, result.Success);
+        Assert.Equal(result.SeasonNumber, seasonNumber);
+        Assert.Equal(isSeasonDirectory, result.IsSeasonFolder);
+    }
+}