Selaa lähdekoodia

Merge branch 'master' into nullable2

Bond_009 5 vuotta sitten
vanhempi
sitoutus
f96bc23c4f
100 muutettua tiedostoa jossa 619 lisäystä ja 372 poistoa
  1. 4 7
      Emby.Naming/Audio/AlbumParser.cs
  2. 0 26
      Emby.Naming/Audio/MultiPartResult.cs
  3. 1 1
      Emby.Naming/AudioBook/AudioBookFileInfo.cs
  4. 3 16
      Emby.Naming/AudioBook/AudioBookListResolver.cs
  5. 18 18
      Emby.Naming/Common/EpisodeExpression.cs
  6. 43 40
      Emby.Naming/Common/NamingOptions.cs
  7. 2 2
      Emby.Naming/Emby.Naming.csproj
  8. 3 2
      Emby.Naming/TV/EpisodePathParser.cs
  9. 6 14
      Emby.Naming/TV/EpisodeResolver.cs
  10. 20 19
      Emby.Naming/TV/SeasonPathParser.cs
  11. 7 14
      Emby.Naming/Video/StackResolver.cs
  12. 0 17
      Emby.Naming/Video/StackResult.cs
  13. 9 11
      Emby.Naming/Video/StubResolver.cs
  14. 1 1
      Emby.Naming/Video/VideoFileInfo.cs
  15. 11 7
      Emby.Naming/Video/VideoInfo.cs
  16. 26 17
      Emby.Naming/Video/VideoListResolver.cs
  17. 9 12
      Emby.Naming/Video/VideoResolver.cs
  18. 1 1
      Emby.Server.Implementations/Library/LibraryManager.cs
  19. 6 14
      Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
  20. 35 38
      Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
  21. 10 11
      Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
  22. 1 1
      Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
  23. 2 2
      Emby.Server.Implementations/Localization/Core/fi.json
  24. 3 1
      Emby.Server.Implementations/Localization/Core/gl.json
  25. 60 2
      Emby.Server.Implementations/Localization/Core/id.json
  26. 0 53
      MediaBrowser.Controller/Entities/Person.cs
  27. 63 0
      MediaBrowser.Controller/Entities/PersonInfo.cs
  28. 12 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  29. 11 11
      MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs
  30. 3 0
      MediaBrowser.Model/Activity/ActivityLogEntry.cs
  31. 3 0
      MediaBrowser.Model/Activity/IActivityManager.cs
  32. 3 0
      MediaBrowser.Model/Activity/IActivityRepository.cs
  33. 6 0
      MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs
  34. 4 0
      MediaBrowser.Model/Branding/BrandingOptions.cs
  35. 3 0
      MediaBrowser.Model/Channels/ChannelFeatures.cs
  36. 3 0
      MediaBrowser.Model/Channels/ChannelFolderType.cs
  37. 3 0
      MediaBrowser.Model/Channels/ChannelInfo.cs
  38. 3 0
      MediaBrowser.Model/Channels/ChannelItemSortField.cs
  39. 3 0
      MediaBrowser.Model/Channels/ChannelMediaContentType.cs
  40. 3 0
      MediaBrowser.Model/Channels/ChannelMediaType.cs
  41. 3 0
      MediaBrowser.Model/Channels/ChannelQuery.cs
  42. 3 0
      MediaBrowser.Model/Collections/CollectionCreationResult.cs
  43. 5 0
      MediaBrowser.Model/Configuration/AccessSchedule.cs
  44. 3 0
      MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs
  45. 7 2
      MediaBrowser.Model/Configuration/EncodingOptions.cs
  46. 4 0
      MediaBrowser.Model/Configuration/ImageOption.cs
  47. 3 0
      MediaBrowser.Model/Configuration/ImageSavingConvention.cs
  48. 3 0
      MediaBrowser.Model/Configuration/LibraryOptions.cs
  49. 3 0
      MediaBrowser.Model/Configuration/MetadataConfiguration.cs
  50. 3 0
      MediaBrowser.Model/Configuration/MetadataOptions.cs
  51. 3 0
      MediaBrowser.Model/Configuration/MetadataPlugin.cs
  52. 3 0
      MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
  53. 3 0
      MediaBrowser.Model/Configuration/MetadataPluginType.cs
  54. 3 0
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  55. 3 0
      MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs
  56. 3 0
      MediaBrowser.Model/Configuration/UnratedItem.cs
  57. 3 0
      MediaBrowser.Model/Configuration/UserConfiguration.cs
  58. 3 0
      MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
  59. 3 0
      MediaBrowser.Model/Cryptography/ICryptoProvider.cs
  60. 3 0
      MediaBrowser.Model/Devices/ContentUploadHistory.cs
  61. 14 5
      MediaBrowser.Model/Devices/DeviceInfo.cs
  62. 4 0
      MediaBrowser.Model/Devices/DeviceQuery.cs
  63. 3 0
      MediaBrowser.Model/Devices/DevicesOptions.cs
  64. 3 0
      MediaBrowser.Model/Devices/LocalFileInfo.cs
  65. 3 0
      MediaBrowser.Model/Diagnostics/IProcess.cs
  66. 3 0
      MediaBrowser.Model/Diagnostics/IProcessFactory.cs
  67. 3 0
      MediaBrowser.Model/Dlna/AudioOptions.cs
  68. 6 2
      MediaBrowser.Model/Dlna/CodecProfile.cs
  69. 3 0
      MediaBrowser.Model/Dlna/CodecType.cs
  70. 3 0
      MediaBrowser.Model/Dlna/ConditionProcessor.cs
  71. 3 0
      MediaBrowser.Model/Dlna/ContainerProfile.cs
  72. 3 0
      MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
  73. 15 1
      MediaBrowser.Model/Dlna/DeviceIdentification.cs
  74. 3 0
      MediaBrowser.Model/Dlna/DeviceProfile.cs
  75. 3 0
      MediaBrowser.Model/Dlna/DeviceProfileInfo.cs
  76. 3 0
      MediaBrowser.Model/Dlna/DeviceProfileType.cs
  77. 3 0
      MediaBrowser.Model/Dlna/DirectPlayProfile.cs
  78. 3 0
      MediaBrowser.Model/Dlna/DlnaFlags.cs
  79. 4 1
      MediaBrowser.Model/Dlna/DlnaMaps.cs
  80. 3 0
      MediaBrowser.Model/Dlna/DlnaProfileType.cs
  81. 3 0
      MediaBrowser.Model/Dlna/EncodingContext.cs
  82. 3 0
      MediaBrowser.Model/Dlna/HeaderMatchType.cs
  83. 3 0
      MediaBrowser.Model/Dlna/HttpHeaderInfo.cs
  84. 3 0
      MediaBrowser.Model/Dlna/IDeviceDiscovery.cs
  85. 3 0
      MediaBrowser.Model/Dlna/ITranscoderSupport.cs
  86. 3 0
      MediaBrowser.Model/Dlna/MediaFormatProfile.cs
  87. 3 1
      MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
  88. 3 0
      MediaBrowser.Model/Dlna/PlaybackErrorCode.cs
  89. 3 0
      MediaBrowser.Model/Dlna/ProfileCondition.cs
  90. 3 0
      MediaBrowser.Model/Dlna/ProfileConditionType.cs
  91. 3 0
      MediaBrowser.Model/Dlna/ProfileConditionValue.cs
  92. 3 0
      MediaBrowser.Model/Dlna/ResolutionConfiguration.cs
  93. 3 0
      MediaBrowser.Model/Dlna/ResolutionNormalizer.cs
  94. 3 0
      MediaBrowser.Model/Dlna/ResolutionOptions.cs
  95. 3 0
      MediaBrowser.Model/Dlna/ResponseProfile.cs
  96. 3 0
      MediaBrowser.Model/Dlna/SearchCriteria.cs
  97. 3 0
      MediaBrowser.Model/Dlna/SearchType.cs
  98. 3 0
      MediaBrowser.Model/Dlna/SortCriteria.cs
  99. 3 1
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  100. 3 1
      MediaBrowser.Model/Dlna/StreamInfo.cs

+ 4 - 7
Emby.Naming/Audio/AlbumParser.cs

@@ -19,15 +19,13 @@ namespace Emby.Naming.Audio
             _options = options;
         }
 
-        public MultiPartResult ParseMultiPart(string path)
+        public bool IsMultiPart(string path)
         {
-            var result = new MultiPartResult();
-
             var filename = Path.GetFileName(path);
 
             if (string.IsNullOrEmpty(filename))
             {
-                return result;
+                return false;
             }
 
             // TODO: Move this logic into options object
@@ -57,12 +55,11 @@ namespace Emby.Naming.Audio
 
                 if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
                 {
-                    result.IsMultiPart = true;
-                    break;
+                    return true;
                 }
             }
 
-            return result;
+            return false;
         }
     }
 }

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

@@ -1,26 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
-namespace Emby.Naming.Audio
-{
-    public class MultiPartResult
-    {
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-
-        /// <summary>
-        /// Gets or sets the part.
-        /// </summary>
-        /// <value>The part.</value>
-        public string Part { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance is multi part.
-        /// </summary>
-        /// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value>
-        public bool IsMultiPart { get; set; }
-    }
-}

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

@@ -32,7 +32,7 @@ namespace Emby.Naming.AudioBook
         public int? ChapterNumber { get; set; }
 
         /// <summary>
-        /// Gets or sets the type.
+        /// Gets or sets a value indicating whether this instance is a directory.
         /// </summary>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }

+ 3 - 16
Emby.Naming/AudioBook/AudioBookListResolver.cs

@@ -39,9 +39,7 @@ namespace Emby.Naming.AudioBook
             var stackResult = new StackResolver(_options)
                 .ResolveAudioBooks(metadata);
 
-            var list = new List<AudioBookInfo>();
-
-            foreach (var stack in stackResult.Stacks)
+            foreach (var stack in stackResult)
             {
                 var stackFiles = stack.Files.Select(i => audioBookResolver.Resolve(i, stack.IsDirectoryStack)).ToList();
                 stackFiles.Sort();
@@ -50,20 +48,9 @@ namespace Emby.Naming.AudioBook
                     Files = stackFiles,
                     Name = stack.Name
                 };
-                list.Add(info);
-            }
-
-            // Whatever files are left, just add them
-            /*list.AddRange(remainingFiles.Select(i => new AudioBookInfo
-            {
-                Files = new List<AudioBookFileInfo> { i },
-                Name = i.,
-                Year = i.Year
-            }));*/
-
-            var orderedList = list.OrderBy(i => i.Name);
 
-            return orderedList;
+                yield return info;
+            }
         }
     }
 }

+ 18 - 18
Emby.Naming/Common/EpisodeExpression.cs

@@ -11,6 +11,24 @@ namespace Emby.Naming.Common
         private string _expression;
         private Regex _regex;
 
+        public EpisodeExpression(string expression, bool byDate)
+        {
+            Expression = expression;
+            IsByDate = byDate;
+            DateTimeFormats = Array.Empty<string>();
+            SupportsAbsoluteEpisodeNumbers = true;
+        }
+
+        public EpisodeExpression(string expression)
+            : this(expression, false)
+        {
+        }
+
+        public EpisodeExpression()
+            : this(null)
+        {
+        }
+
         public string Expression
         {
             get => _expression;
@@ -32,23 +50,5 @@ namespace Emby.Naming.Common
         public string[] DateTimeFormats { get; set; }
 
         public Regex Regex => _regex ?? (_regex = new Regex(Expression, RegexOptions.IgnoreCase | RegexOptions.Compiled));
-
-        public EpisodeExpression(string expression, bool byDate)
-        {
-            Expression = expression;
-            IsByDate = byDate;
-            DateTimeFormats = Array.Empty<string>();
-            SupportsAbsoluteEpisodeNumbers = true;
-        }
-
-        public EpisodeExpression(string expression)
-            : this(expression, false)
-        {
-        }
-
-        public EpisodeExpression()
-            : this(null)
-        {
-        }
     }
 }

+ 43 - 40
Emby.Naming/Common/NamingOptions.cs

@@ -11,46 +11,6 @@ namespace Emby.Naming.Common
 {
     public class NamingOptions
     {
-        public string[] AudioFileExtensions { get; set; }
-
-        public string[] AlbumStackingPrefixes { get; set; }
-
-        public string[] SubtitleFileExtensions { get; set; }
-
-        public char[] SubtitleFlagDelimiters { get; set; }
-
-        public string[] SubtitleForcedFlags { get; set; }
-
-        public string[] SubtitleDefaultFlags { get; set; }
-
-        public EpisodeExpression[] EpisodeExpressions { get; set; }
-
-        public string[] EpisodeWithoutSeasonExpressions { get; set; }
-
-        public string[] EpisodeMultiPartExpressions { get; set; }
-
-        public string[] VideoFileExtensions { get; set; }
-
-        public string[] StubFileExtensions { get; set; }
-
-        public string[] AudioBookPartsExpressions { get; set; }
-
-        public StubTypeRule[] StubTypes { get; set; }
-
-        public char[] VideoFlagDelimiters { get; set; }
-
-        public Format3DRule[] Format3DRules { get; set; }
-
-        public string[] VideoFileStackingExpressions { get; set; }
-
-        public string[] CleanDateTimes { get; set; }
-
-        public string[] CleanStrings { get; set; }
-
-        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
-
-        public ExtraRule[] VideoExtraRules { get; set; }
-
         public NamingOptions()
         {
             VideoFileExtensions = new[]
@@ -681,11 +641,54 @@ namespace Emby.Naming.Common
             Compile();
         }
 
+        public string[] AudioFileExtensions { get; set; }
+
+        public string[] AlbumStackingPrefixes { get; set; }
+
+        public string[] SubtitleFileExtensions { get; set; }
+
+        public char[] SubtitleFlagDelimiters { get; set; }
+
+        public string[] SubtitleForcedFlags { get; set; }
+
+        public string[] SubtitleDefaultFlags { get; set; }
+
+        public EpisodeExpression[] EpisodeExpressions { get; set; }
+
+        public string[] EpisodeWithoutSeasonExpressions { get; set; }
+
+        public string[] EpisodeMultiPartExpressions { get; set; }
+
+        public string[] VideoFileExtensions { get; set; }
+
+        public string[] StubFileExtensions { get; set; }
+
+        public string[] AudioBookPartsExpressions { get; set; }
+
+        public StubTypeRule[] StubTypes { get; set; }
+
+        public char[] VideoFlagDelimiters { get; set; }
+
+        public Format3DRule[] Format3DRules { get; set; }
+
+        public string[] VideoFileStackingExpressions { get; set; }
+
+        public string[] CleanDateTimes { get; set; }
+
+        public string[] CleanStrings { get; set; }
+
+        public EpisodeExpression[] MultipleEpisodeExpressions { get; set; }
+
+        public ExtraRule[] VideoExtraRules { get; set; }
+
         public Regex[] VideoFileStackingRegexes { get; private set; }
+
         public Regex[] CleanDateTimeRegexes { get; private set; }
+
         public Regex[] CleanStringRegexes { get; private set; }
 
         public Regex[] EpisodeWithoutSeasonRegexes { get; private set; }
+
         public Regex[] EpisodeMultiPartRegexes { get; private set; }
 
         public void Compile()

+ 2 - 2
Emby.Naming/Emby.Naming.csproj

@@ -4,7 +4,7 @@
     <TargetFramework>netstandard2.1</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
-    <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' " >true</TreatWarningsAsErrors>
+    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
 
   <ItemGroup>
@@ -24,7 +24,7 @@
 
   <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+    <!-- TODO: <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> -->
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
     <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
     <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />

+ 3 - 2
Emby.Naming/TV/EpisodePathParser.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 using System;
 using System.Collections.Generic;
@@ -28,7 +29,7 @@ namespace Emby.Naming.TV
                 path += ".mp4";
             }
 
-            EpisodePathParserResult result = null;
+            EpisodePathParserResult? result = null;
 
             foreach (var expression in _options.EpisodeExpressions)
             {
@@ -136,7 +137,7 @@ namespace Emby.Naming.TV
                         // 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;
                         if (nextIndex >= name.Length
-                            || "0123456789iIpP".IndexOf(name[nextIndex]) == -1)
+                            || !"0123456789iIpP".Contains(name[nextIndex], StringComparison.Ordinal))
                         {
                             if (int.TryParse(endingNumberGroup.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                             {

+ 6 - 14
Emby.Naming/TV/EpisodeResolver.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 using System;
 using System.IO;
@@ -18,7 +19,7 @@ namespace Emby.Naming.TV
             _options = options;
         }
 
-        public EpisodeInfo Resolve(
+        public EpisodeInfo? Resolve(
             string path,
             bool isDirectory,
             bool? isNamed = null,
@@ -26,14 +27,9 @@ namespace Emby.Naming.TV
             bool? supportsAbsoluteNumbers = null,
             bool fillExtendedInfo = true)
         {
-            if (string.IsNullOrEmpty(path))
-            {
-                throw new ArgumentNullException(nameof(path));
-            }
-
             bool isStub = false;
-            string container = null;
-            string stubType = null;
+            string? container = null;
+            string? stubType = null;
 
             if (!isDirectory)
             {
@@ -41,17 +37,13 @@ namespace Emby.Naming.TV
                 // Check supported extensions
                 if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                 {
-                    var stubResult = StubResolver.ResolveFile(path, _options);
-
-                    isStub = stubResult.IsStub;
-
                     // It's not supported. Check stub extensions
-                    if (!isStub)
+                    if (!StubResolver.TryResolveFile(path, _options, out stubType))
                     {
                         return null;
                     }
 
-                    stubType = stubResult.StubType;
+                    isStub = true;
                 }
 
                 container = extension.TrimStart('.');

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

@@ -8,9 +8,24 @@ using System.Linq;
 
 namespace Emby.Naming.TV
 {
-    public class SeasonPathParser
+    public static class SeasonPathParser
     {
-        public SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
+        /// <summary>
+        /// A season folder must contain one of these somewhere in the name.
+        /// </summary>
+        private static readonly string[] _seasonFolderNames =
+        {
+            "season",
+            "sæson",
+            "temporada",
+            "saison",
+            "staffel",
+            "series",
+            "сезон",
+            "stagione"
+        };
+
+        public static SeasonPathParserResult Parse(string path, bool supportSpecialAliases, bool supportNumericSeasonFolders)
         {
             var result = new SeasonPathParserResult();
 
@@ -27,21 +42,6 @@ namespace Emby.Naming.TV
             return result;
         }
 
-        /// <summary>
-        /// A season folder must contain one of these somewhere in the name.
-        /// </summary>
-        private static readonly string[] _seasonFolderNames =
-        {
-            "season",
-            "sæson",
-            "temporada",
-            "saison",
-            "staffel",
-            "series",
-            "сезон",
-            "stagione"
-        };
-
         /// <summary>
         /// Gets the season number from path.
         /// </summary>
@@ -150,6 +150,7 @@ namespace Emby.Naming.TV
                         {
                             numericStart = i;
                         }
+
                         length++;
                     }
                 }
@@ -161,11 +162,11 @@ namespace Emby.Naming.TV
                 }
 
                 var currentChar = path[i];
-                if (currentChar.Equals('('))
+                if (currentChar == '(')
                 {
                     hasOpenParenth = true;
                 }
-                else if (currentChar.Equals(')'))
+                else if (currentChar == ')')
                 {
                     hasOpenParenth = false;
                 }

+ 7 - 14
Emby.Naming/Video/StackResolver.cs

@@ -20,7 +20,7 @@ namespace Emby.Naming.Video
             _options = options;
         }
 
-        public StackResult ResolveDirectories(IEnumerable<string> files)
+        public IEnumerable<FileStack> ResolveDirectories(IEnumerable<string> files)
         {
             return Resolve(files.Select(i => new FileSystemMetadata
             {
@@ -29,7 +29,7 @@ namespace Emby.Naming.Video
             }));
         }
 
-        public StackResult ResolveFiles(IEnumerable<string> files)
+        public IEnumerable<FileStack> ResolveFiles(IEnumerable<string> files)
         {
             return Resolve(files.Select(i => new FileSystemMetadata
             {
@@ -38,9 +38,8 @@ namespace Emby.Naming.Video
             }));
         }
 
-        public StackResult ResolveAudioBooks(IEnumerable<FileSystemMetadata> files)
+        public IEnumerable<FileStack> ResolveAudioBooks(IEnumerable<FileSystemMetadata> files)
         {
-            var result = new StackResult();
             foreach (var directory in files.GroupBy(file => file.IsDirectory ? file.FullName : Path.GetDirectoryName(file.FullName)))
             {
                 var stack = new FileStack()
@@ -58,20 +57,16 @@ namespace Emby.Naming.Video
                     stack.Files.Add(file.FullName);
                 }
 
-                result.Stacks.Add(stack);
+                yield return stack;
             }
-
-            return result;
         }
 
-        public StackResult Resolve(IEnumerable<FileSystemMetadata> files)
+        public IEnumerable<FileStack> Resolve(IEnumerable<FileSystemMetadata> files)
         {
-            var result = new StackResult();
-
             var resolver = new VideoResolver(_options);
 
             var list = files
-                .Where(i => i.IsDirectory || (resolver.IsVideoFile(i.FullName) || resolver.IsStubFile(i.FullName)))
+                .Where(i => i.IsDirectory || resolver.IsVideoFile(i.FullName) || resolver.IsStubFile(i.FullName))
                 .OrderBy(i => i.FullName)
                 .ToList();
 
@@ -191,14 +186,12 @@ namespace Emby.Naming.Video
 
                     if (stack.Files.Count > 1)
                     {
-                        result.Stacks.Add(stack);
+                        yield return stack;
                         i += stack.Files.Count - 1;
                         break;
                     }
                 }
             }
-
-            return result;
         }
 
         private string GetRegexInput(FileSystemMetadata file)

+ 0 - 17
Emby.Naming/Video/StackResult.cs

@@ -1,17 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
-using System.Collections.Generic;
-
-namespace Emby.Naming.Video
-{
-    public class StackResult
-    {
-        public List<FileStack> Stacks { get; set; }
-
-        public StackResult()
-        {
-            Stacks = new List<FileStack>();
-        }
-    }
-}

+ 9 - 11
Emby.Naming/Video/StubResolver.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 using System;
 using System.IO;
@@ -10,25 +11,22 @@ namespace Emby.Naming.Video
 {
     public static class StubResolver
     {
-        public static StubResult ResolveFile(string path, NamingOptions options)
+        public static bool TryResolveFile(string path, NamingOptions options, out string? stubType)
         {
+            stubType = default;
+
             if (path == null)
             {
-                return default;
+                return false;
             }
 
             var extension = Path.GetExtension(path);
 
             if (!options.StubFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
             {
-                return default;
+                return false;
             }
 
-            var result = new StubResult()
-            {
-                IsStub = true
-            };
-
             path = Path.GetFileNameWithoutExtension(path);
             var token = Path.GetExtension(path).TrimStart('.');
 
@@ -36,12 +34,12 @@ namespace Emby.Naming.Video
             {
                 if (string.Equals(rule.Token, token, StringComparison.OrdinalIgnoreCase))
                 {
-                    result.StubType = rule.StubType;
-                    break;
+                    stubType = rule.StubType;
+                    return true;
                 }
             }
 
-            return result;
+            return true;
         }
     }
 }

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

@@ -68,7 +68,7 @@ namespace Emby.Naming.Video
         public string StubType { get; set; }
 
         /// <summary>
-        /// Gets or sets the type.
+        /// Gets or sets a value indicating whether this instance is a directory.
         /// </summary>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }

+ 11 - 7
Emby.Naming/Video/VideoInfo.cs

@@ -1,3 +1,4 @@
+using System;
 using System.Collections.Generic;
 
 namespace Emby.Naming.Video
@@ -10,11 +11,14 @@ namespace Emby.Naming.Video
         /// <summary>
         /// Initializes a new instance of the <see cref="VideoInfo" /> class.
         /// </summary>
-        public VideoInfo()
+        /// <param name="name">The name.</param>
+        public VideoInfo(string name)
         {
-            Files = new List<VideoFileInfo>();
-            Extras = new List<VideoFileInfo>();
-            AlternateVersions = new List<VideoFileInfo>();
+            Name = name;
+
+            Files = Array.Empty<VideoFileInfo>();
+            Extras = Array.Empty<VideoFileInfo>();
+            AlternateVersions = Array.Empty<VideoFileInfo>();
         }
 
         /// <summary>
@@ -33,18 +37,18 @@ namespace Emby.Naming.Video
         /// Gets or sets the files.
         /// </summary>
         /// <value>The files.</value>
-        public List<VideoFileInfo> Files { get; set; }
+        public IReadOnlyList<VideoFileInfo> Files { get; set; }
 
         /// <summary>
         /// Gets or sets the extras.
         /// </summary>
         /// <value>The extras.</value>
-        public List<VideoFileInfo> Extras { get; set; }
+        public IReadOnlyList<VideoFileInfo> Extras { get; set; }
 
         /// <summary>
         /// Gets or sets the alternate versions.
         /// </summary>
         /// <value>The alternate versions.</value>
-        public List<VideoFileInfo> AlternateVersions { get; set; }
+        public IReadOnlyList<VideoFileInfo> AlternateVersions { get; set; }
     }
 }

+ 26 - 17
Emby.Naming/Video/VideoListResolver.cs

@@ -41,20 +41,19 @@ namespace Emby.Naming.Video
                 });
 
             var stackResult = new StackResolver(_options)
-                .Resolve(nonExtras);
+                .Resolve(nonExtras).ToList();
 
             var remainingFiles = videoInfos
-                .Where(i => !stackResult.Stacks.Any(s => s.ContainsFile(i.Path, i.IsDirectory)))
+                .Where(i => !stackResult.Any(s => s.ContainsFile(i.Path, i.IsDirectory)))
                 .ToList();
 
             var list = new List<VideoInfo>();
 
-            foreach (var stack in stackResult.Stacks)
+            foreach (var stack in stackResult)
             {
-                var info = new VideoInfo
+                var info = new VideoInfo(stack.Name)
                 {
-                    Files = stack.Files.Select(i => videoResolver.Resolve(i, stack.IsDirectoryStack)).ToList(),
-                    Name = stack.Name
+                    Files = stack.Files.Select(i => videoResolver.Resolve(i, stack.IsDirectoryStack)).ToList()
                 };
 
                 info.Year = info.Files[0].Year;
@@ -85,10 +84,9 @@ namespace Emby.Naming.Video
 
             foreach (var media in standaloneMedia)
             {
-                var info = new VideoInfo
+                var info = new VideoInfo(media.Name)
                 {
-                    Files = new List<VideoFileInfo> { media },
-                    Name = media.Name
+                    Files = new List<VideoFileInfo> { media }
                 };
 
                 info.Year = info.Files[0].Year;
@@ -128,7 +126,8 @@ namespace Emby.Naming.Video
                             .Except(extras)
                             .ToList();
 
-                        info.Extras.AddRange(extras);
+                        extras.AddRange(info.Extras);
+                        info.Extras = extras;
                     }
                 }
 
@@ -141,7 +140,8 @@ namespace Emby.Naming.Video
                     .Except(extrasByFileName)
                     .ToList();
 
-                info.Extras.AddRange(extrasByFileName);
+                extrasByFileName.AddRange(info.Extras);
+                info.Extras = extrasByFileName;
             }
 
             // If there's only one video, accept all trailers
@@ -152,7 +152,8 @@ namespace Emby.Naming.Video
                     .Where(i => i.ExtraType == ExtraType.Trailer)
                     .ToList();
 
-                list[0].Extras.AddRange(trailers);
+                trailers.AddRange(list[0].Extras);
+                list[0].Extras = trailers;
 
                 remainingFiles = remainingFiles
                     .Except(trailers)
@@ -160,14 +161,13 @@ namespace Emby.Naming.Video
             }
 
             // Whatever files are left, just add them
-            list.AddRange(remainingFiles.Select(i => new VideoInfo
+            list.AddRange(remainingFiles.Select(i => new VideoInfo(i.Name)
             {
                 Files = new List<VideoFileInfo> { i },
-                Name = i.Name,
                 Year = i.Year
             }));
 
-            return list.OrderBy(i => i.Name);
+            return list;
         }
 
         private IEnumerable<VideoInfo> GetVideosGroupedByVersion(List<VideoInfo> videos)
@@ -191,9 +191,18 @@ namespace Emby.Naming.Video
 
                 list.Add(ordered[0]);
 
-                list[0].AlternateVersions = ordered.Skip(1).Select(i => i.Files[0]).ToList();
+                var alternateVersionsLen = ordered.Count - 1;
+                var alternateVersions = new VideoFileInfo[alternateVersionsLen];
+                for (int i = 0; i < alternateVersionsLen; i++)
+                {
+                    alternateVersions[i] = ordered[i + 1].Files[0];
+                }
+
+                list[0].AlternateVersions = alternateVersions;
                 list[0].Name = folderName;
-                list[0].Extras.AddRange(ordered.Skip(1).SelectMany(i => i.Extras));
+                var extras = ordered.Skip(1).SelectMany(i => i.Extras).ToList();
+                extras.AddRange(list[0].Extras);
+                list[0].Extras = extras;
 
                 return list;
             }

+ 9 - 12
Emby.Naming/Video/VideoResolver.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 #pragma warning disable SA1600
+#nullable enable
 
 using System;
 using System.IO;
@@ -22,7 +23,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>VideoFileInfo.</returns>
-        public VideoFileInfo ResolveDirectory(string path)
+        public VideoFileInfo? ResolveDirectory(string path)
         {
             return Resolve(path, true);
         }
@@ -32,7 +33,7 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <param name="path">The path.</param>
         /// <returns>VideoFileInfo.</returns>
-        public VideoFileInfo ResolveFile(string path)
+        public VideoFileInfo? ResolveFile(string path)
         {
             return Resolve(path, false);
         }
@@ -42,10 +43,10 @@ namespace Emby.Naming.Video
         /// </summary>
         /// <param name="path">The path.</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>
+        /// <param name="parseName">Whether or not the name should be parsed for info.</param>
         /// <returns>VideoFileInfo.</returns>
         /// <exception cref="ArgumentNullException"><c>path</c> is <c>null</c>.</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))
             {
@@ -53,8 +54,8 @@ namespace Emby.Naming.Video
             }
 
             bool isStub = false;
-            string container = null;
-            string stubType = null;
+            string? container = null;
+            string? stubType = null;
 
             if (!isDirectory)
             {
@@ -63,17 +64,13 @@ namespace Emby.Naming.Video
                 // Check supported extensions
                 if (!_options.VideoFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
                 {
-                    var stubResult = StubResolver.ResolveFile(path, _options);
-
-                    isStub = stubResult.IsStub;
-
                     // It's not supported. Check stub extensions
-                    if (!isStub)
+                    if (!StubResolver.TryResolveFile(path, _options, out stubType))
                     {
                         return null;
                     }
 
-                    stubType = stubResult.StubType;
+                    isStub = true;
                 }
 
                 container = extension.TrimStart('.');

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

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

+ 6 - 14
Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs

@@ -76,7 +76,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
         }
 
         /// <summary>
-        /// Determine if the supplied file data points to a music album
+        /// Determine if the supplied file data points to a music album.
         /// </summary>
         public bool IsMusicAlbum(string path, IDirectoryService directoryService, LibraryOptions libraryOptions)
         {
@@ -84,7 +84,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
         }
 
         /// <summary>
-        /// Determine if the supplied resolve args should be considered a music album
+        /// Determine if the supplied resolve args should be considered a music album.
         /// </summary>
         /// <param name="args">The args.</param>
         /// <returns><c>true</c> if [is music album] [the specified args]; otherwise, <c>false</c>.</returns>
@@ -104,7 +104,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
         }
 
         /// <summary>
-        /// Determine if the supplied list contains what we should consider music
+        /// Determine if the supplied list contains what we should consider music.
         /// </summary>
         private bool ContainsMusic(
             IEnumerable<FileSystemMetadata> list,
@@ -118,6 +118,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
             var discSubfolderCount = 0;
             var notMultiDisc = false;
 
+            var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
+            var parser = new AlbumParser(namingOptions);
             foreach (var fileSystemInfo in list)
             {
                 if (fileSystemInfo.IsDirectory)
@@ -134,7 +136,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
 
                         if (hasMusic)
                         {
-                            if (IsMultiDiscFolder(path, libraryOptions))
+                            if (parser.IsMultiPart(path))
                             {
                                 logger.LogDebug("Found multi-disc folder: " + path);
                                 discSubfolderCount++;
@@ -165,15 +167,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
 
             return discSubfolderCount > 0;
         }
-
-        private bool IsMultiDiscFolder(string path, LibraryOptions libraryOptions)
-        {
-            var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
-
-            var parser = new AlbumParser(namingOptions);
-            var result = parser.ParseMultiPart(path);
-
-            return result.IsMultiPart;
-        }
     }
 }

+ 35 - 38
Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -21,6 +21,28 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
     /// </summary>
     public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
     {
+        private string[] _validCollectionTypes = new[]
+        {
+                CollectionType.Movies,
+                CollectionType.HomeVideos,
+                CollectionType.MusicVideos,
+                CollectionType.Movies,
+                CollectionType.Photos
+        };
+
+        private readonly IImageProcessor _imageProcessor;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="MovieResolver"/> class.
+        /// </summary>
+        /// <param name="libraryManager">The library manager.</param>
+        /// <param name="imageProcessor">The image processor.</param>
+        public MovieResolver(ILibraryManager libraryManager, IImageProcessor imageProcessor)
+            : base(libraryManager)
+        {
+            _imageProcessor = imageProcessor;
+        }
+
         /// <summary>
         /// Gets the priority.
         /// </summary>
@@ -144,7 +166,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 
             foreach (var video in resolverResult)
             {
-                var firstVideo = video.Files.First();
+                var firstVideo = video.Files[0];
 
                 var videoItem = new T
                 {
@@ -230,7 +252,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                     // Owned items will be caught by the plain video resolver
                     if (args.Parent == null)
                     {
-                        //return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+                        // return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
                         return null;
                     }
 
@@ -275,7 +297,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             {
                 item = ResolveVideo<Movie>(args, true);
             }
-
             else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
                 string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
             {
@@ -319,7 +340,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
         {
             if (item is Movie || item is MusicVideo)
             {
-                //we need to only look at the name of this actual item (not parents)
+                // We need to only look at the name of this actual item (not parents)
                 var justName = item.IsInMixedFolder ? Path.GetFileName(item.Path) : Path.GetFileName(item.ContainingFolderPath);
 
                 if (!string.IsNullOrEmpty(justName))
@@ -347,9 +368,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
         }
 
         /// <summary>
-        /// Finds a movie based on a child file system entries
+        /// Finds a movie based on a child file system entries.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <returns>Movie.</returns>
         private T FindMovie<T>(ItemResolveArgs args, string path, Folder parent, List<FileSystemMetadata> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool parseName)
             where T : Video, new()
@@ -377,6 +397,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                         Set3DFormat(movie);
                         return movie;
                     }
+
                     if (IsBluRayDirectory(child.FullName, filename, directoryService))
                     {
                         var movie = new T
@@ -407,9 +428,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             }
 
             // TODO: Allow GetMultiDiscMovie in here
-            const bool supportsMultiVersion = true;
+            const bool SupportsMultiVersion = true;
 
-            var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, supportsMultiVersion, collectionType, parseName) ??
+            var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, SupportsMultiVersion, collectionType, parseName) ??
                 new MultiItemResolverResult();
 
             if (result.Items.Count == 1)
@@ -437,7 +458,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
         /// <summary>
         /// Gets the multi disc movie.
         /// </summary>
-        /// <typeparam name="T"></typeparam>
         /// <param name="multiDiscFolders">The folders.</param>
         /// <param name="directoryService">The directory service.</param>
         /// <returns>``0.</returns>
@@ -451,7 +471,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                 var subFileEntries = directoryService.GetFileSystemEntries(i);
 
                 var subfolders = subFileEntries
-                 .Where(e => e.IsDirectory)
+                    .Where(e => e.IsDirectory)
                     .ToList();
 
                 if (subfolders.Any(s => IsDvdDirectory(s.FullName, s.Name, directoryService)))
@@ -459,6 +479,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                     videoTypes.Add(VideoType.Dvd);
                     return true;
                 }
+
                 if (subfolders.Any(s => IsBluRayDirectory(s.FullName, s.Name, directoryService)))
                 {
                     videoTypes.Add(VideoType.BluRay);
@@ -476,7 +497,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                 }
 
                 return false;
-
             }).OrderBy(i => i).ToList();
 
             // If different video types were found, don't allow this
@@ -491,11 +511,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             }
 
             var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();
-            var resolver = new StackResolver(namingOptions);
 
-            var result = resolver.ResolveDirectories(folderPaths);
+            var result = new StackResolver(namingOptions).ResolveDirectories(folderPaths).ToList();
 
-            if (result.Stacks.Count != 1)
+            if (result.Count != 1)
             {
                 return null;
             }
@@ -508,7 +527,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
 
                 VideoType = videoTypes[0],
 
-                Name = result.Stacks[0].Name
+                Name = result[0].Name
             };
 
             SetIsoType(returnVideo);
@@ -516,15 +535,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             return returnVideo;
         }
 
-        private string[] ValidCollectionTypes = new[]
-        {
-                CollectionType.Movies,
-                CollectionType.HomeVideos,
-                CollectionType.MusicVideos,
-                CollectionType.Movies,
-                CollectionType.Photos
-        };
-
         private bool IsInvalid(Folder parent, string collectionType)
         {
             if (parent != null)
@@ -540,20 +550,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                 return false;
             }
 
-            return !ValidCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
-        }
-
-        private IImageProcessor _imageProcessor;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="MovieResolver"/> class.
-        /// </summary>
-        /// <param name="libraryManager">The library manager.</param>
-        /// <param name="imageProcessor">The image processor.</param>
-        public MovieResolver(ILibraryManager libraryManager, IImageProcessor imageProcessor)
-            : base(libraryManager)
-        {
-            _imageProcessor = imageProcessor;
+            return !_validCollectionTypes.Contains(collectionType, StringComparer.OrdinalIgnoreCase);
         }
     }
 }

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

@@ -9,17 +9,12 @@ using Microsoft.Extensions.Logging;
 namespace Emby.Server.Implementations.Library.Resolvers.TV
 {
     /// <summary>
-    /// Class SeasonResolver
+    /// Class SeasonResolver.
     /// </summary>
     public class SeasonResolver : FolderResolver<Season>
     {
-        /// <summary>
-        /// The _config
-        /// </summary>
         private readonly IServerConfigurationManager _config;
-
         private readonly ILibraryManager _libraryManager;
-        private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
         private readonly ILocalizationManager _localization;
         private readonly ILogger _logger;
 
@@ -45,14 +40,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
         /// <returns>Season.</returns>
         protected override Season Resolve(ItemResolveArgs args)
         {
-            if (args.Parent is Series && args.IsDirectory)
+            if (args.Parent is Series series && args.IsDirectory)
             {
                 var namingOptions = ((LibraryManager)_libraryManager).GetNamingOptions();
-                var series = ((Series)args.Parent);
 
                 var path = args.Path;
 
-                var seasonParserResult = new SeasonPathParser().Parse(path, true, true);
+                var seasonParserResult = SeasonPathParser.Parse(path, true, true);
 
                 var season = new Season
                 {
@@ -74,7 +68,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
                     {
                         if (episodeInfo.EpisodeNumber.HasValue && episodeInfo.SeasonNumber.HasValue)
                         {
-                            _logger.LogDebug("Found folder underneath series with episode number: {0}. Season {1}. Episode {2}",
+                            _logger.LogDebug(
+                                "Found folder underneath series with episode number: {0}. Season {1}. Episode {2}",
                                 path,
                                 episodeInfo.SeasonNumber.Value,
                                 episodeInfo.EpisodeNumber.Value);
@@ -90,7 +85,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 
                     season.Name = seasonNumber == 0 ?
                         args.LibraryOptions.SeasonZeroDisplayName :
-                        string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.ToString(UsCulture), args.GetLibraryOptions().PreferredMetadataLanguage);
+                        string.Format(
+                            CultureInfo.InvariantCulture,
+                            _localization.GetLocalizedString("NameSeasonNumber"),
+                            seasonNumber,
+                            args.GetLibraryOptions().PreferredMetadataLanguage);
 
                 }
 

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

@@ -203,7 +203,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
         /// <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)
         {
-            var seasonNumber = new SeasonPathParser().Parse(path, isTvContentType, isTvContentType).SeasonNumber;
+            var seasonNumber = SeasonPathParser.Parse(path, isTvContentType, isTvContentType).SeasonNumber;
 
             return seasonNumber.HasValue;
         }

+ 2 - 2
Emby.Server.Implementations/Localization/Core/fi.json

@@ -24,12 +24,12 @@
     "HeaderFavoriteSongs": "Lempikappaleet",
     "HeaderFavoriteShows": "Lempisarjat",
     "HeaderFavoriteEpisodes": "Lempijaksot",
-    "HeaderCameraUploads": "Kamerasta Ladatut",
+    "HeaderCameraUploads": "Kamera lataukset",
     "HeaderFavoriteArtists": "Lempiartistit",
     "HeaderFavoriteAlbums": "Lempialbumit",
     "HeaderContinueWatching": "Jatka Katsomista",
     "HeaderAlbumArtists": "Albumiartistit",
-    "Genres": "Genret",
+    "Genres": "Lajipiiri",
     "Folders": "Kansiot",
     "Favorites": "Suosikit",
     "FailedLoginAttemptWithUserName": "Epäonnistunut kirjautumisyritys kohteesta {0}",

+ 3 - 1
Emby.Server.Implementations/Localization/Core/gl.json

@@ -1 +1,3 @@
-{}
+{
+    "Albums": "Álbumes"
+}

+ 60 - 2
Emby.Server.Implementations/Localization/Core/id.json

@@ -6,7 +6,7 @@
     "MessageApplicationUpdatedTo": "Jellyfin Server sudah diperbarui ke {0}",
     "MessageApplicationUpdated": "Jellyfin Server sudah diperbarui",
     "Latest": "Terbaru",
-    "LabelIpAddressValue": "IP address: {0}",
+    "LabelIpAddressValue": "Alamat IP: {0}",
     "ItemRemovedWithName": "{0} sudah dikeluarkan dari perpustakaan",
     "ItemAddedWithName": "{0} sudah dimasukkan ke dalam perpustakaan",
     "Inherit": "Warisan",
@@ -28,5 +28,63 @@
     "Collections": "Koleksi",
     "Books": "Buku",
     "Artists": "Artis",
-    "Application": "Aplikasi"
+    "Application": "Aplikasi",
+    "ChapterNameValue": "Bagian {0}",
+    "Channels": "Saluran",
+    "TvShows": "Seri TV",
+    "SubtitleDownloadFailureFromForItem": "Talop gagal diunduh dari {0} untuk {1}",
+    "StartupEmbyServerIsLoading": "Peladen Jellyfin sedang dimuat. Silakan coba kembali beberapa saat lagi.",
+    "Songs": "Lagu",
+    "Playlists": "Daftar putar",
+    "NotificationOptionPluginUninstalled": "Plugin dilepas",
+    "MusicVideos": "Video musik",
+    "VersionNumber": "Versi {0}",
+    "ValueSpecialEpisodeName": "Spesial - {0}",
+    "ValueHasBeenAddedToLibrary": "{0} telah ditambahkan ke pustaka media Anda",
+    "UserStoppedPlayingItemWithValues": "{0} telah selesai memutar {1} pada {2}",
+    "UserStartedPlayingItemWithValues": "{0} sedang memutar {1} pada {2}",
+    "UserPolicyUpdatedWithName": "Kebijakan pengguna telah diperbarui untuk {0}",
+    "UserPasswordChangedWithName": "Kata sandi telah diubah untuk pengguna {0}",
+    "UserOnlineFromDevice": "{0} sedang daring dari {1}",
+    "UserOfflineFromDevice": "{0} telah terputus dari {1}",
+    "UserLockedOutWithName": "Pengguna {0} telah dikunci",
+    "UserDownloadingItemWithValues": "{0} sedang mengunduh {1}",
+    "UserDeletedWithName": "Pengguna {0} telah dihapus",
+    "UserCreatedWithName": "Pengguna {0} telah dibuat",
+    "User": "Pengguna",
+    "System": "Sistem",
+    "Sync": "Sinkron",
+    "SubtitlesDownloadedForItem": "Talop telah diunduh untuk {0}",
+    "Shows": "Tayangan",
+    "ServerNameNeedsToBeRestarted": "{0} perlu dimuat ulang",
+    "ScheduledTaskStartedWithName": "{0} dimulai",
+    "ScheduledTaskFailedWithName": "{0} gagal",
+    "ProviderValue": "Penyedia: {0}",
+    "PluginUpdatedWithName": "{0} telah diperbarui",
+    "PluginInstalledWithName": "{0} telah dipasang",
+    "Plugin": "Plugin",
+    "Photos": "Foto",
+    "NotificationOptionUserLockedOut": "Pengguna terkunci",
+    "NotificationOptionTaskFailed": "Kegagalan tugas terjadwal",
+    "NotificationOptionServerRestartRequired": "Restart peladen dibutuhkan",
+    "NotificationOptionPluginUpdateInstalled": "Pembaruan plugin terpasang",
+    "NotificationOptionPluginInstalled": "Plugin terpasang",
+    "NotificationOptionPluginError": "Kegagalan plugin",
+    "NotificationOptionNewLibraryContent": "Konten baru ditambahkan",
+    "NotificationOptionInstallationFailed": "Kegagalan pemasangan",
+    "NotificationOptionCameraImageUploaded": "Gambar kamera terunggah",
+    "NotificationOptionApplicationUpdateInstalled": "Pembaruan aplikasi terpasang",
+    "NotificationOptionApplicationUpdateAvailable": "Pembaruan aplikasi tersedia",
+    "NewVersionIsAvailable": "Sebuah versi baru dari Peladen Jellyfin tersedia untuk diunduh.",
+    "NameSeasonUnknown": "Musim tak diketahui",
+    "NameSeasonNumber": "Musim {0}",
+    "NameInstallFailed": "{0} instalasi gagal",
+    "Music": "Musik",
+    "Movies": "Film",
+    "MessageServerConfigurationUpdated": "Konfigurasi peladen telah diperbarui",
+    "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi peladen bagian {0} telah diperbarui",
+    "FailedLoginAttemptWithUserName": "Percobaan login gagal dari {0}",
+    "CameraImageUploadedFrom": "Sebuah gambar baru telah diunggah dari {0}",
+    "DeviceOfflineWithName": "{0} telah terputus",
+    "DeviceOnlineWithName": "{0} telah terhubung"
 }

+ 0 - 53
MediaBrowser.Controller/Entities/Person.cs

@@ -135,57 +135,4 @@ namespace MediaBrowser.Controller.Entities
             return hasChanges;
         }
     }
-
-    /// <summary>
-    /// This is the small Person stub that is attached to BaseItems
-    /// </summary>
-    public class PersonInfo : IHasProviderIds
-    {
-        public PersonInfo()
-        {
-            ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        }
-
-        public Guid ItemId { get; set; }
-
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-        /// <summary>
-        /// Gets or sets the role.
-        /// </summary>
-        /// <value>The role.</value>
-        public string Role { get; set; }
-        /// <summary>
-        /// Gets or sets the type.
-        /// </summary>
-        /// <value>The type.</value>
-        public string Type { get; set; }
-
-        /// <summary>
-        /// Gets or sets the sort order - ascending
-        /// </summary>
-        /// <value>The sort order.</value>
-        public int? SortOrder { get; set; }
-
-        public string ImageUrl { get; set; }
-
-        public Dictionary<string, string> ProviderIds { get; set; }
-
-        /// <summary>
-        /// Returns a <see cref="string" /> that represents this instance.
-        /// </summary>
-        /// <returns>A <see cref="string" /> that represents this instance.</returns>
-        public override string ToString()
-        {
-            return Name;
-        }
-
-        public bool IsType(string type)
-        {
-            return string.Equals(Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(Role, type, StringComparison.OrdinalIgnoreCase);
-        }
-    }
 }

+ 63 - 0
MediaBrowser.Controller/Entities/PersonInfo.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Controller.Entities
+{
+    /// <summary>
+    /// This is a small Person stub that is attached to BaseItems.
+    /// </summary>
+    public sealed class PersonInfo : IHasProviderIds
+    {
+        public PersonInfo()
+        {
+            ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
+        }
+
+        public Guid ItemId { get; set; }
+
+        /// <summary>
+        /// Gets or sets the name.
+        /// </summary>
+        /// <value>The name.</value>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Gets or sets the role.
+        /// </summary>
+        /// <value>The role.</value>
+        public string Role { get; set; }
+
+        /// <summary>
+        /// Gets or sets the type.
+        /// </summary>
+        /// <value>The type.</value>
+        public string Type { get; set; }
+
+        /// <summary>
+        /// Gets or sets the ascending sort order.
+        /// </summary>
+        /// <value>The sort order.</value>
+        public int? SortOrder { get; set; }
+
+        public string ImageUrl { get; set; }
+
+        public Dictionary<string, string> ProviderIds { get; set; }
+
+        /// <summary>
+        /// Returns a <see cref="string" /> that represents this instance.
+        /// </summary>
+        /// <returns>A <see cref="string" /> that represents this instance.</returns>
+        public override string ToString()
+        {
+            return Name;
+        }
+
+        public bool IsType(string type)
+        {
+            return string.Equals(Type, type, StringComparison.OrdinalIgnoreCase)
+                || string.Equals(Role, type, StringComparison.OrdinalIgnoreCase);
+        }
+    }
+}

+ 12 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -26,4 +26,16 @@
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
 
+  <!-- Code Analyzers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+
 </Project>

+ 11 - 11
MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs

@@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Net
         /// <summary>
         /// The _active connections
         /// </summary>
-        protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> ActiveConnections =
+        private readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> _activeConnections =
             new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>();
 
         /// <summary>
@@ -100,9 +100,9 @@ namespace MediaBrowser.Controller.Net
                 InitialDelayMs = dueTimeMs
             };
 
-            lock (ActiveConnections)
+            lock (_activeConnections)
             {
-                ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>(message.Connection, cancellationTokenSource, state));
+                _activeConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>(message.Connection, cancellationTokenSource, state));
             }
         }
 
@@ -110,9 +110,9 @@ namespace MediaBrowser.Controller.Net
         {
             Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>[] tuples;
 
-            lock (ActiveConnections)
+            lock (_activeConnections)
             {
-                tuples = ActiveConnections
+                tuples = _activeConnections
                     .Where(c =>
                     {
                         if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested)
@@ -180,9 +180,9 @@ namespace MediaBrowser.Controller.Net
         /// <param name="message">The message.</param>
         private void Stop(WebSocketMessageInfo message)
         {
-            lock (ActiveConnections)
+            lock (_activeConnections)
             {
-                var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection);
+                var connection = _activeConnections.FirstOrDefault(c => c.Item1 == message.Connection);
 
                 if (connection != null)
                 {
@@ -212,9 +212,9 @@ namespace MediaBrowser.Controller.Net
                 //TODO Investigate and properly fix.
             }
 
-            lock (ActiveConnections)
+            lock (_activeConnections)
             {
-                ActiveConnections.Remove(connection);
+                _activeConnections.Remove(connection);
             }
         }
 
@@ -226,9 +226,9 @@ namespace MediaBrowser.Controller.Net
         {
             if (dispose)
             {
-                lock (ActiveConnections)
+                lock (_activeConnections)
                 {
-                    foreach (var connection in ActiveConnections.ToArray())
+                    foreach (var connection in _activeConnections.ToArray())
                     {
                         DisposeConnection(connection);
                     }

+ 3 - 0
MediaBrowser.Model/Activity/ActivityLogEntry.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using Microsoft.Extensions.Logging;
 

+ 3 - 0
MediaBrowser.Model/Activity/IActivityManager.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Events;
 using MediaBrowser.Model.Querying;

+ 3 - 0
MediaBrowser.Model/Activity/IActivityRepository.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Querying;
 

+ 6 - 0
MediaBrowser.Model/ApiClient/ServerDiscoveryInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.ApiClient
 {
     public class ServerDiscoveryInfo
@@ -7,16 +10,19 @@ namespace MediaBrowser.Model.ApiClient
         /// </summary>
         /// <value>The address.</value>
         public string Address { get; set; }
+
         /// <summary>
         /// Gets or sets the server identifier.
         /// </summary>
         /// <value>The server identifier.</value>
         public string Id { get; set; }
+
         /// <summary>
         /// Gets or sets the name.
         /// </summary>
         /// <value>The name.</value>
         public string Name { get; set; }
+        
         /// <summary>
         /// Gets or sets the endpoint address.
         /// </summary>

+ 4 - 0
MediaBrowser.Model/Branding/BrandingOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Branding
 {
     public class BrandingOptions
@@ -7,6 +10,7 @@ namespace MediaBrowser.Model.Branding
         /// </summary>
         /// <value>The login disclaimer.</value>
         public string LoginDisclaimer { get; set; }
+        
         /// <summary>
         /// Gets or sets the custom CSS.
         /// </summary>

+ 3 - 0
MediaBrowser.Model/Channels/ChannelFeatures.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Channels

+ 3 - 0
MediaBrowser.Model/Channels/ChannelFolderType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Channels
 {
     public enum ChannelFolderType

+ 3 - 0
MediaBrowser.Model/Channels/ChannelInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Channels
 {
     public class ChannelInfo

+ 3 - 0
MediaBrowser.Model/Channels/ChannelItemSortField.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Channels
 {
     public enum ChannelItemSortField

+ 3 - 0
MediaBrowser.Model/Channels/ChannelMediaContentType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Channels
 {
     public enum ChannelMediaContentType

+ 3 - 0
MediaBrowser.Model/Channels/ChannelMediaType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Channels
 {
     public enum ChannelMediaType

+ 3 - 0
MediaBrowser.Model/Channels/ChannelQuery.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;

+ 3 - 0
MediaBrowser.Model/Collections/CollectionCreationResult.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Collections

+ 5 - 0
MediaBrowser.Model/Configuration/AccessSchedule.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public class AccessSchedule
@@ -7,11 +10,13 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value>The day of week.</value>
         public DynamicDayOfWeek DayOfWeek { get; set; }
+
         /// <summary>
         /// Gets or sets the start hour.
         /// </summary>
         /// <value>The start hour.</value>
         public double StartHour { get; set; }
+
         /// <summary>
         /// Gets or sets the end hour.
         /// </summary>

+ 3 - 0
MediaBrowser.Model/Configuration/DynamicDayOfWeek.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public enum DynamicDayOfWeek

+ 7 - 2
MediaBrowser.Model/Configuration/EncodingOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public class EncodingOptions
@@ -8,12 +11,14 @@ namespace MediaBrowser.Model.Configuration
         public bool EnableThrottling { get; set; }
         public int ThrottleDelaySeconds { get; set; }
         public string HardwareAccelerationType { get; set; }
+
         /// <summary>
-        /// FFmpeg path as set by the user via the UI
+        /// FFmpeg path as set by the user via the UI.
         /// </summary>
         public string EncoderAppPath { get; set; }
+
         /// <summary>
-        /// The current FFmpeg path being used by the system and displayed on the transcode page
+        /// The current FFmpeg path being used by the system and displayed on the transcode page.
         /// </summary>
         public string EncoderAppPathDisplay { get; set; }
         public string VaapiDevice { get; set; }

+ 4 - 0
MediaBrowser.Model/Configuration/ImageOption.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Model.Configuration
@@ -9,6 +12,7 @@ namespace MediaBrowser.Model.Configuration
         /// </summary>
         /// <value>The type.</value>
         public ImageType Type { get; set; }
+        
         /// <summary>
         /// Gets or sets the limit.
         /// </summary>

+ 3 - 0
MediaBrowser.Model/Configuration/ImageSavingConvention.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public enum ImageSavingConvention

+ 3 - 0
MediaBrowser.Model/Configuration/LibraryOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using MediaBrowser.Model.Entities;

+ 3 - 0
MediaBrowser.Model/Configuration/MetadataConfiguration.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public class MetadataConfiguration

+ 3 - 0
MediaBrowser.Model/Configuration/MetadataOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Configuration

+ 3 - 0
MediaBrowser.Model/Configuration/MetadataPlugin.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public class MetadataPlugin

+ 3 - 0
MediaBrowser.Model/Configuration/MetadataPluginSummary.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Entities;
 

+ 3 - 0
MediaBrowser.Model/Configuration/MetadataPluginType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     /// <summary>

+ 3 - 0
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Dto;
 

+ 3 - 0
MediaBrowser.Model/Configuration/SubtitlePlaybackMode.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public enum SubtitlePlaybackMode

+ 3 - 0
MediaBrowser.Model/Configuration/UnratedItem.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public enum UnratedItem

+ 3 - 0
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Configuration

+ 3 - 0
MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Configuration
 {
     public class XbmcMetadataOptions

+ 3 - 0
MediaBrowser.Model/Cryptography/ICryptoProvider.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Collections.Generic;
 
 namespace MediaBrowser.Model.Cryptography

+ 3 - 0
MediaBrowser.Model/Devices/ContentUploadHistory.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Devices
 {
     public class ContentUploadHistory

+ 14 - 5
MediaBrowser.Model/Devices/DeviceInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Session;
 
@@ -5,6 +8,11 @@ namespace MediaBrowser.Model.Devices
 {
     public class DeviceInfo
     {
+        public DeviceInfo()
+        {
+            Capabilities = new ClientCapabilities();
+        }
+        
         public string Name { get; set; }
 
         /// <summary>
@@ -12,42 +20,43 @@ namespace MediaBrowser.Model.Devices
         /// </summary>
         /// <value>The identifier.</value>
         public string Id { get; set; }
+
         /// <summary>
         /// Gets or sets the last name of the user.
         /// </summary>
         /// <value>The last name of the user.</value>
         public string LastUserName { get; set; }
+
         /// <summary>
         /// Gets or sets the name of the application.
         /// </summary>
         /// <value>The name of the application.</value>
         public string AppName { get; set; }
+
         /// <summary>
         /// Gets or sets the application version.
         /// </summary>
         /// <value>The application version.</value>
         public string AppVersion { get; set; }
+
         /// <summary>
         /// Gets or sets the last user identifier.
         /// </summary>
         /// <value>The last user identifier.</value>
         public Guid LastUserId { get; set; }
+
         /// <summary>
         /// Gets or sets the date last modified.
         /// </summary>
         /// <value>The date last modified.</value>
         public DateTime DateLastActivity { get; set; }
+
         /// <summary>
         /// Gets or sets the capabilities.
         /// </summary>
         /// <value>The capabilities.</value>
         public ClientCapabilities Capabilities { get; set; }
 
-        public DeviceInfo()
-        {
-            Capabilities = new ClientCapabilities();
-        }
-
         public string IconUrl { get; set; }
     }
 }

+ 4 - 0
MediaBrowser.Model/Devices/DeviceQuery.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Devices
@@ -9,6 +12,7 @@ namespace MediaBrowser.Model.Devices
         /// </summary>
         /// <value><c>null</c> if [supports synchronize] contains no value, <c>true</c> if [supports synchronize]; otherwise, <c>false</c>.</value>
         public bool? SupportsSync { get; set; }
+
         /// <summary>
         /// Gets or sets the user identifier.
         /// </summary>

+ 3 - 0
MediaBrowser.Model/Devices/DevicesOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Devices

+ 3 - 0
MediaBrowser.Model/Devices/LocalFileInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Devices
 {
     public class LocalFileInfo

+ 3 - 0
MediaBrowser.Model/Diagnostics/IProcess.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.IO;
 using System.Threading.Tasks;

+ 3 - 0
MediaBrowser.Model/Diagnostics/IProcessFactory.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Diagnostics
 {
     public interface IProcessFactory

+ 3 - 0
MediaBrowser.Model/Dlna/AudioOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Dto;
 

+ 6 - 2
MediaBrowser.Model/Dlna/CodecProfile.cs

@@ -1,3 +1,7 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
+using System;
 using System.Xml.Serialization;
 using MediaBrowser.Model.Extensions;
 
@@ -20,8 +24,8 @@ namespace MediaBrowser.Model.Dlna
 
         public CodecProfile()
         {
-            Conditions = new ProfileCondition[] { };
-            ApplyConditions = new ProfileCondition[] { };
+            Conditions = Array.Empty<ProfileCondition>();
+            ApplyConditions = Array.Empty<ProfileCondition>();
         }
 
         public string[] GetCodecs()

+ 3 - 0
MediaBrowser.Model/Dlna/CodecType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum CodecType

+ 3 - 0
MediaBrowser.Model/Dlna/ConditionProcessor.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Globalization;
 using MediaBrowser.Model.Extensions;

+ 3 - 0
MediaBrowser.Model/Dlna/ContainerProfile.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Xml.Serialization;
 using MediaBrowser.Model.Extensions;

+ 3 - 0
MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Globalization;

+ 15 - 1
MediaBrowser.Model/Dlna/DeviceIdentification.cs

@@ -1,3 +1,8 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
+using System;
+
 namespace MediaBrowser.Model.Dlna
 {
     public class DeviceIdentification
@@ -7,46 +12,55 @@ namespace MediaBrowser.Model.Dlna
         /// </summary>
         /// <value>The name of the friendly.</value>
         public string FriendlyName { get; set; }
+
         /// <summary>
         /// Gets or sets the model number.
         /// </summary>
         /// <value>The model number.</value>
         public string ModelNumber { get; set; }
+
         /// <summary>
         /// Gets or sets the serial number.
         /// </summary>
         /// <value>The serial number.</value>
         public string SerialNumber { get; set; }
+
         /// <summary>
         /// Gets or sets the name of the model.
         /// </summary>
         /// <value>The name of the model.</value>
         public string ModelName { get; set; }
+
         /// <summary>
         /// Gets or sets the model description.
         /// </summary>
         /// <value>The model description.</value>
         public string ModelDescription { get; set; }
+
         /// <summary>
         /// Gets or sets the device description.
         /// </summary>
         /// <value>The device description.</value>
         public string DeviceDescription { get; set; }
+
         /// <summary>
         /// Gets or sets the model URL.
         /// </summary>
         /// <value>The model URL.</value>
         public string ModelUrl { get; set; }
+
         /// <summary>
         /// Gets or sets the manufacturer.
         /// </summary>
         /// <value>The manufacturer.</value>
         public string Manufacturer { get; set; }
+
         /// <summary>
         /// Gets or sets the manufacturer URL.
         /// </summary>
         /// <value>The manufacturer URL.</value>
         public string ManufacturerUrl { get; set; }
+
         /// <summary>
         /// Gets or sets the headers.
         /// </summary>
@@ -55,7 +69,7 @@ namespace MediaBrowser.Model.Dlna
 
         public DeviceIdentification()
         {
-            Headers = new HttpHeaderInfo[] { };
+            Headers = Array.Empty<HttpHeaderInfo>();
         }
     }
 }

+ 3 - 0
MediaBrowser.Model/Dlna/DeviceProfile.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Xml.Serialization;
 using MediaBrowser.Model.Extensions;

+ 3 - 0
MediaBrowser.Model/Dlna/DeviceProfileInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public class DeviceProfileInfo

+ 3 - 0
MediaBrowser.Model/Dlna/DeviceProfileType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum DeviceProfileType

+ 3 - 0
MediaBrowser.Model/Dlna/DirectPlayProfile.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Xml.Serialization;
 
 namespace MediaBrowser.Model.Dlna

+ 3 - 0
MediaBrowser.Model/Dlna/DlnaFlags.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 
 namespace MediaBrowser.Model.Dlna

+ 4 - 1
MediaBrowser.Model/Dlna/DlnaMaps.cs

@@ -1,6 +1,9 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
-    public class DlnaMaps
+    public static class DlnaMaps
     {
         private static readonly string DefaultStreaming =
              FlagsToString(DlnaFlags.StreamingTransferMode |

+ 3 - 0
MediaBrowser.Model/Dlna/DlnaProfileType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum DlnaProfileType

+ 3 - 0
MediaBrowser.Model/Dlna/EncodingContext.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum EncodingContext

+ 3 - 0
MediaBrowser.Model/Dlna/HeaderMatchType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum HeaderMatchType

+ 3 - 0
MediaBrowser.Model/Dlna/HttpHeaderInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Xml.Serialization;
 
 namespace MediaBrowser.Model.Dlna

+ 3 - 0
MediaBrowser.Model/Dlna/IDeviceDiscovery.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Events;
 

+ 3 - 0
MediaBrowser.Model/Dlna/ITranscoderSupport.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public interface ITranscoderSupport

+ 3 - 0
MediaBrowser.Model/Dlna/MediaFormatProfile.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum MediaFormatProfile

+ 3 - 1
MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs

@@ -1,7 +1,9 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.MediaInfo;
 
 namespace MediaBrowser.Model.Dlna

+ 3 - 0
MediaBrowser.Model/Dlna/PlaybackErrorCode.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum PlaybackErrorCode

+ 3 - 0
MediaBrowser.Model/Dlna/ProfileCondition.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Xml.Serialization;
 
 namespace MediaBrowser.Model.Dlna

+ 3 - 0
MediaBrowser.Model/Dlna/ProfileConditionType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum ProfileConditionType

+ 3 - 0
MediaBrowser.Model/Dlna/ProfileConditionValue.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum ProfileConditionValue

+ 3 - 0
MediaBrowser.Model/Dlna/ResolutionConfiguration.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public class ResolutionConfiguration

+ 3 - 0
MediaBrowser.Model/Dlna/ResolutionNormalizer.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using MediaBrowser.Model.Extensions;
 

+ 3 - 0
MediaBrowser.Model/Dlna/ResolutionOptions.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public class ResolutionOptions

+ 3 - 0
MediaBrowser.Model/Dlna/ResponseProfile.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System.Xml.Serialization;
 
 namespace MediaBrowser.Model.Dlna

+ 3 - 0
MediaBrowser.Model/Dlna/SearchCriteria.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Text.RegularExpressions;
 using MediaBrowser.Model.Extensions;

+ 3 - 0
MediaBrowser.Model/Dlna/SearchType.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 namespace MediaBrowser.Model.Dlna
 {
     public enum SearchType

+ 3 - 0
MediaBrowser.Model/Dlna/SortCriteria.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using MediaBrowser.Model.Entities;
 
 namespace MediaBrowser.Model.Dlna

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

@@ -1,10 +1,12 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Linq;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Session;
 using Microsoft.Extensions.Logging;

+ 3 - 1
MediaBrowser.Model/Dlna/StreamInfo.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+#pragma warning disable SA1600
+
 using System;
 using System.Collections.Generic;
 using System.Globalization;
@@ -5,7 +8,6 @@ using System.Linq;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.MediaInfo;
 using MediaBrowser.Model.Session;
 

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä