aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Naming/TV/SeasonPathParser.cs15
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs2
-rw-r--r--jellyfin.ruleset22
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs35
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs37
5 files changed, 66 insertions, 45 deletions
diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs
index fc9ee8e56..45b91971b 100644
--- a/Emby.Naming/TV/SeasonPathParser.cs
+++ b/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);
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 4815dcc04..d2715e2ac 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/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)
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
index db116f46c..67ffd9a37 100644
--- a/jellyfin.ruleset
+++ b/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" />
diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs
deleted file mode 100644
index 6773bbeb1..000000000
--- a/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs
+++ /dev/null
@@ -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);
- }
- }
-}
diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonPathParserTests.cs
new file mode 100644
index 000000000..3a042df68
--- /dev/null
+++ b/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);
+ }
+}