浏览代码

Fix all warnings in Jellyfin.Api (#9003)

Bond-009 2 年之前
父节点
当前提交
69a51c425a

+ 1 - 1
Jellyfin.Api/Attributes/AcceptsFileAttribute.cs

@@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes
         /// Gets the configured content types.
         /// Gets the configured content types.
         /// </summary>
         /// </summary>
         /// <returns>the configured content types.</returns>
         /// <returns>the configured content types.</returns>
-        public string[] GetContentTypes() => _contentTypes;
+        public string[] ContentTypes => _contentTypes;
     }
     }
 }
 }

+ 1 - 1
Jellyfin.Api/Attributes/ProducesFileAttribute.cs

@@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes
         /// Gets the configured content types.
         /// Gets the configured content types.
         /// </summary>
         /// </summary>
         /// <returns>the configured content types.</returns>
         /// <returns>the configured content types.</returns>
-        public string[] GetContentTypes() => _contentTypes;
+        public string[] ContentTypes => _contentTypes;
     }
     }
 }
 }

+ 0 - 18
Jellyfin.Api/BaseJellyfinApiController.cs

@@ -17,24 +17,6 @@ namespace Jellyfin.Api
         JsonDefaults.PascalCaseMediaType)]
         JsonDefaults.PascalCaseMediaType)]
     public class BaseJellyfinApiController : ControllerBase
     public class BaseJellyfinApiController : ControllerBase
     {
     {
-        /// <summary>
-        /// Create a new <see cref="OkResult{T}"/>.
-        /// </summary>
-        /// <param name="value">The value to return.</param>
-        /// <typeparam name="T">The type to return.</typeparam>
-        /// <returns>The <see cref="ActionResult{T}"/>.</returns>
-        protected ActionResult<IEnumerable<T>> Ok<T>(List<T> value)
-            => new OkResult<IEnumerable<T>>(value);
-
-        /// <summary>
-        /// Create a new <see cref="OkResult{T}"/>.
-        /// </summary>
-        /// <param name="value">The value to return.</param>
-        /// <typeparam name="T">The type to return.</typeparam>
-        /// <returns>The <see cref="ActionResult{T}"/>.</returns>
-        protected ActionResult<IEnumerable<T>> Ok<T>(IReadOnlyList<T> value)
-            => new OkResult<IEnumerable<T>>(value);
-
         /// <summary>
         /// <summary>
         /// Create a new <see cref="OkResult{T}"/>.
         /// Create a new <see cref="OkResult{T}"/>.
         /// </summary>
         /// </summary>

+ 1 - 1
Jellyfin.Api/Controllers/ApiKeyController.cs

@@ -36,7 +36,7 @@ namespace Jellyfin.Api.Controllers
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         public async Task<ActionResult<QueryResult<AuthenticationInfo>>> GetKeys()
         public async Task<ActionResult<QueryResult<AuthenticationInfo>>> GetKeys()
         {
         {
-            var keys = await _authenticationManager.GetApiKeys();
+            var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false);
 
 
             return new QueryResult<AuthenticationInfo>(keys);
             return new QueryResult<AuthenticationInfo>(keys);
         }
         }

+ 73 - 62
Jellyfin.Api/Controllers/ImageController.cs

@@ -106,24 +106,26 @@ namespace Jellyfin.Api.Controllers
             }
             }
 
 
             var user = _userManager.GetUserById(userId);
             var user = _userManager.GetUserById(userId);
-            await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
-
-            // Handle image/png; charset=utf-8
-            var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
-            var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);
-            if (user.ProfileImage is not null)
+            var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            await using (memoryStream.ConfigureAwait(false))
             {
             {
-                await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
-            }
+                // Handle image/png; charset=utf-8
+                var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
+                var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);
+                if (user.ProfileImage is not null)
+                {
+                    await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
+                }
 
 
-            user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
+                user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
 
 
-            await _providerManager
-                .SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
-                .ConfigureAwait(false);
-            await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
+                await _providerManager
+                    .SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
+                    .ConfigureAwait(false);
+                await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
 
 
-            return NoContent();
+                return NoContent();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -153,24 +155,26 @@ namespace Jellyfin.Api.Controllers
             }
             }
 
 
             var user = _userManager.GetUserById(userId);
             var user = _userManager.GetUserById(userId);
-            await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
-
-            // Handle image/png; charset=utf-8
-            var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
-            var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);
-            if (user.ProfileImage is not null)
+            var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            await using (memoryStream.ConfigureAwait(false))
             {
             {
-                await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
-            }
+                // Handle image/png; charset=utf-8
+                var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
+                var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username);
+                if (user.ProfileImage is not null)
+                {
+                    await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
+                }
 
 
-            user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
+                user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
 
 
-            await _providerManager
-                .SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
-                .ConfigureAwait(false);
-            await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
+                await _providerManager
+                    .SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
+                    .ConfigureAwait(false);
+                await _userManager.UpdateUserAsync(user).ConfigureAwait(false);
 
 
-            return NoContent();
+                return NoContent();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -341,14 +345,16 @@ namespace Jellyfin.Api.Controllers
                 return NotFound();
                 return NotFound();
             }
             }
 
 
-            await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
-
-            // Handle image/png; charset=utf-8
-            var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
-            await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
-            await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
+            var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            await using (memoryStream.ConfigureAwait(false))
+            {
+                // Handle image/png; charset=utf-8
+                var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
+                await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
+                await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
 
 
-            return NoContent();
+                return NoContent();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -377,14 +383,16 @@ namespace Jellyfin.Api.Controllers
                 return NotFound();
                 return NotFound();
             }
             }
 
 
-            await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
-
-            // Handle image/png; charset=utf-8
-            var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
-            await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
-            await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
+            var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            await using (memoryStream.ConfigureAwait(false))
+            {
+                // Handle image/png; charset=utf-8
+                var mimeType = Request.ContentType?.Split(';').FirstOrDefault();
+                await _providerManager.SaveImage(item, memoryStream, mimeType, imageType, null, CancellationToken.None).ConfigureAwait(false);
+                await item.UpdateToRepositoryAsync(ItemUpdateType.ImageUpdate, CancellationToken.None).ConfigureAwait(false);
 
 
-            return NoContent();
+                return NoContent();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -1788,32 +1796,35 @@ namespace Jellyfin.Api.Controllers
         [AcceptsImageFile]
         [AcceptsImageFile]
         public async Task<ActionResult> UploadCustomSplashscreen()
         public async Task<ActionResult> UploadCustomSplashscreen()
         {
         {
-            await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false);
+            await using (memoryStream.ConfigureAwait(false))
+            {
+                var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType;
 
 
-            var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType;
+                if (!mimeType.HasValue)
+                {
+                    return BadRequest("Error reading mimetype from uploaded image");
+                }
 
 
-            if (!mimeType.HasValue)
-            {
-                return BadRequest("Error reading mimetype from uploaded image");
-            }
+                var extension = MimeTypes.ToExtension(mimeType.Value);
+                if (string.IsNullOrEmpty(extension))
+                {
+                    return BadRequest("Error converting mimetype to an image extension");
+                }
 
 
-            var extension = MimeTypes.ToExtension(mimeType.Value);
-            if (string.IsNullOrEmpty(extension))
-            {
-                return BadRequest("Error converting mimetype to an image extension");
-            }
+                var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension);
+                var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding");
+                brandingOptions.SplashscreenLocation = filePath;
+                _serverConfigurationManager.SaveConfiguration("branding", brandingOptions);
 
 
-            var filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension);
-            var brandingOptions = _serverConfigurationManager.GetConfiguration<BrandingOptions>("branding");
-            brandingOptions.SplashscreenLocation = filePath;
-            _serverConfigurationManager.SaveConfiguration("branding", brandingOptions);
+                var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous);
+                await using (fs.ConfigureAwait(false))
+                {
+                    await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false);
+                }
 
 
-            await using (var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, IODefaults.FileStreamBufferSize, FileOptions.Asynchronous))
-            {
-                await memoryStream.CopyToAsync(fs, CancellationToken.None).ConfigureAwait(false);
+                return NoContent();
             }
             }
-
-            return NoContent();
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 2
Jellyfin.Api/Controllers/LiveTvController.cs

@@ -1011,10 +1011,9 @@ namespace Jellyfin.Api.Controllers
         {
         {
             if (!string.IsNullOrEmpty(pw))
             if (!string.IsNullOrEmpty(pw))
             {
             {
-                using var sha = SHA1.Create();
                 // TODO: remove ToLower when Convert.ToHexString supports lowercase
                 // TODO: remove ToLower when Convert.ToHexString supports lowercase
                 // Schedules Direct requires the hex to be lowercase
                 // Schedules Direct requires the hex to be lowercase
-                listingsProviderInfo.Password = Convert.ToHexString(sha.ComputeHash(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant();
+                listingsProviderInfo.Password = Convert.ToHexString(SHA1.HashData(Encoding.UTF8.GetBytes(pw))).ToLowerInvariant();
             }
             }
 
 
             return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false);
             return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false);

+ 2 - 2
Jellyfin.Api/Controllers/PackageController.cs

@@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status200OK)]
         public ActionResult<IEnumerable<RepositoryInfo>> GetRepositories()
         public ActionResult<IEnumerable<RepositoryInfo>> GetRepositories()
         {
         {
-            return _serverConfigurationManager.Configuration.PluginRepositories;
+            return Ok(_serverConfigurationManager.Configuration.PluginRepositories.AsEnumerable());
         }
         }
 
 
         /// <summary>
         /// <summary>
@@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers
         [HttpPost("Repositories")]
         [HttpPost("Repositories")]
         [Authorize(Policy = Policies.RequiresElevation)]
         [Authorize(Policy = Policies.RequiresElevation)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
         [ProducesResponseType(StatusCodes.Status204NoContent)]
-        public ActionResult SetRepositories([FromBody, Required] List<RepositoryInfo> repositoryInfos)
+        public ActionResult SetRepositories([FromBody, Required] RepositoryInfo[] repositoryInfos)
         {
         {
             _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos;
             _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos;
             _serverConfigurationManager.SaveConfiguration();
             _serverConfigurationManager.SaveConfiguration();

+ 2 - 1
Jellyfin.Api/Controllers/PluginsController.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using System.Text.Json;
 using System.Text.Json;
@@ -143,7 +144,7 @@ namespace Jellyfin.Api.Controllers
         public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId)
         public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId)
         {
         {
             // If no version is given, return the current instance.
             // If no version is given, return the current instance.
-            var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId));
+            var plugins = _pluginManager.Plugins.Where(p => p.Id.Equals(pluginId)).ToList();
 
 
             // Select the un-instanced one first.
             // Select the un-instanced one first.
             var plugin = plugins.FirstOrDefault(p => p.Instance is null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault();
             var plugin = plugins.FirstOrDefault(p => p.Instance is null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault();

+ 23 - 17
Jellyfin.Api/Controllers/SubtitleController.cs

@@ -236,14 +236,17 @@ namespace Jellyfin.Api.Controllers
 
 
             if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap)
             if (string.Equals(format, "vtt", StringComparison.OrdinalIgnoreCase) && addVttTimeMap)
             {
             {
-                await using Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
-                using var reader = new StreamReader(stream);
+                Stream stream = await EncodeSubtitles(itemId.Value, mediaSourceId, index.Value, format, startPositionTicks, endPositionTicks, copyTimestamps).ConfigureAwait(false);
+                await using (stream.ConfigureAwait(false))
+                {
+                    using var reader = new StreamReader(stream);
 
 
-                var text = await reader.ReadToEndAsync().ConfigureAwait(false);
+                    var text = await reader.ReadToEndAsync().ConfigureAwait(false);
 
 
-                text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal);
+                    text = text.Replace("WEBVTT", "WEBVTT\nX-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000", StringComparison.Ordinal);
 
 
-                return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format));
+                    return File(Encoding.UTF8.GetBytes(text), MimeTypes.GetMimeType("file." + format));
+                }
             }
             }
 
 
             return File(
             return File(
@@ -403,19 +406,22 @@ namespace Jellyfin.Api.Controllers
         {
         {
             var video = (Video)_libraryManager.GetItemById(itemId);
             var video = (Video)_libraryManager.GetItemById(itemId);
             var data = Convert.FromBase64String(body.Data);
             var data = Convert.FromBase64String(body.Data);
-            await using var memoryStream = new MemoryStream(data);
-            await _subtitleManager.UploadSubtitle(
-                video,
-                new SubtitleResponse
-                {
-                    Format = body.Format,
-                    Language = body.Language,
-                    IsForced = body.IsForced,
-                    Stream = memoryStream
-                }).ConfigureAwait(false);
-            _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
+            var memoryStream = new MemoryStream(data, 0, data.Length, false, true);
+            await using (memoryStream.ConfigureAwait(false))
+            {
+                await _subtitleManager.UploadSubtitle(
+                    video,
+                    new SubtitleResponse
+                    {
+                        Format = body.Format,
+                        Language = body.Language,
+                        IsForced = body.IsForced,
+                        Stream = memoryStream
+                    }).ConfigureAwait(false);
+                _providerManager.QueueRefresh(video.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), RefreshPriority.High);
 
 
-            return NoContent();
+                return NoContent();
+            }
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 2 - 1
Jellyfin.Api/Controllers/SyncPlayController.cs

@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations;
+using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Jellyfin.Api.Constants;
 using Jellyfin.Api.Constants;
@@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers
         {
         {
             var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false);
             var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false);
             var syncPlayRequest = new ListGroupsRequest();
             var syncPlayRequest = new ListGroupsRequest();
-            return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest));
+            return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest).AsEnumerable());
         }
         }
 
 
         /// <summary>
         /// <summary>

+ 1 - 2
Jellyfin.Api/Controllers/SystemController.cs

@@ -216,8 +216,7 @@ namespace Jellyfin.Api.Controllers
         public ActionResult<IEnumerable<WakeOnLanInfo>> GetWakeOnLanInfo()
         public ActionResult<IEnumerable<WakeOnLanInfo>> GetWakeOnLanInfo()
         {
         {
             var result = _network.GetMacAddresses()
             var result = _network.GetMacAddresses()
-                .Select(i => new WakeOnLanInfo(i))
-                .ToList();
+                .Select(i => new WakeOnLanInfo(i));
             return Ok(result);
             return Ok(result);
         }
         }
     }
     }

+ 1 - 1
Jellyfin.Api/Controllers/UserLibraryController.cs

@@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers
             if (item is IHasTrailers hasTrailers)
             if (item is IHasTrailers hasTrailers)
             {
             {
                 var trailers = hasTrailers.LocalTrailers;
                 var trailers = hasTrailers.LocalTrailers;
-                return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item));
+                return Ok(_dtoService.GetBaseItemDtos(trailers, dtoOptions, user, item).AsEnumerable());
             }
             }
 
 
             return Ok(item.GetExtras()
             return Ok(item.GetExtras()

+ 0 - 4
Jellyfin.Api/Jellyfin.Api.csproj

@@ -12,10 +12,6 @@
     <NoWarn>AD0001</NoWarn>
     <NoWarn>AD0001</NoWarn>
   </PropertyGroup>
   </PropertyGroup>
 
 
-  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
-  </PropertyGroup>
-
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.1" />
     <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.1" />
     <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
     <PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />

+ 2 - 4
Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs

@@ -14,14 +14,12 @@ namespace Jellyfin.Api.Models.LiveTvDtos
         /// <summary>
         /// <summary>
         /// Gets or sets list of tuner channels.
         /// Gets or sets list of tuner channels.
         /// </summary>
         /// </summary>
-        [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "TunerChannels", Justification = "Imported from ServiceStack")]
-        public List<TunerChannelMapping> TunerChannels { get; set; } = null!;
+        required public IReadOnlyList<TunerChannelMapping> TunerChannels { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets list of provider channels.
         /// Gets or sets list of provider channels.
         /// </summary>
         /// </summary>
-        [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "ProviderChannels", Justification = "Imported from ServiceStack")]
-        public List<NameIdPair> ProviderChannels { get; set; } = null!;
+        required public IReadOnlyList<NameIdPair> ProviderChannels { get; set; }
 
 
         /// <summary>
         /// <summary>
         /// Gets or sets list of mappings.
         /// Gets or sets list of mappings.

+ 1 - 1
Jellyfin.Server/Filters/FileRequestFilter.cs

@@ -15,7 +15,7 @@ namespace Jellyfin.Server.Filters
             {
             {
                 if (attribute is AcceptsFileAttribute acceptsFileAttribute)
                 if (attribute is AcceptsFileAttribute acceptsFileAttribute)
                 {
                 {
-                    operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes());
+                    operation.RequestBody = GetRequestBody(acceptsFileAttribute.ContentTypes);
                     break;
                     break;
                 }
                 }
             }
             }

+ 1 - 1
Jellyfin.Server/Filters/FileResponseFilter.cs

@@ -40,7 +40,7 @@ namespace Jellyfin.Server.Filters
                     response.Value.Content.Clear();
                     response.Value.Content.Clear();
 
 
                     // Add all content-types as file.
                     // Add all content-types as file.
-                    foreach (var contentType in producesFileAttribute.GetContentTypes())
+                    foreach (var contentType in producesFileAttribute.ContentTypes)
                     {
                     {
                         response.Value.Content.Add(contentType, _openApiMediaType);
                         response.Value.Content.Add(contentType, _openApiMediaType);
                     }
                     }

+ 1 - 1
Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs

@@ -38,7 +38,7 @@ namespace Jellyfin.Server.Migrations.Routines
         /// <inheritdoc/>
         /// <inheritdoc/>
         public void Perform()
         public void Perform()
         {
         {
-            _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo);
+            _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo };
             _serverConfigurationManager.SaveConfiguration();
             _serverConfigurationManager.SaveConfiguration();
         }
         }
     }
     }

+ 2 - 2
Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs

@@ -39,9 +39,9 @@ namespace Jellyfin.Server.Migrations.Routines
         public void Perform()
         public void Perform()
         {
         {
             // Only add if repository list is empty
             // Only add if repository list is empty
-            if (_serverConfigurationManager.Configuration.PluginRepositories.Count == 0)
+            if (_serverConfigurationManager.Configuration.PluginRepositories.Length == 0)
             {
             {
-                _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo);
+                _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo };
                 _serverConfigurationManager.SaveConfiguration();
                 _serverConfigurationManager.SaveConfiguration();
             }
             }
         }
         }

+ 1 - 1
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -194,7 +194,7 @@ namespace MediaBrowser.Model.Configuration
 
 
         public string[] CodecsUsed { get; set; } = Array.Empty<string>();
         public string[] CodecsUsed { get; set; } = Array.Empty<string>();
 
 
-        public List<RepositoryInfo> PluginRepositories { get; set; } = new List<RepositoryInfo>();
+        public RepositoryInfo[] PluginRepositories { get; set; } = Array.Empty<RepositoryInfo>();
 
 
         public bool EnableExternalContentInSuggestions { get; set; } = true;
         public bool EnableExternalContentInSuggestions { get; set; } = true;
 
 

+ 4 - 0
jellyfin.ruleset

@@ -138,6 +138,10 @@
     <Rule Id="CA2253" Action="Info" />
     <Rule Id="CA2253" Action="Info" />
     <!-- disable warning CA5394: Do not use insecure randomness -->
     <!-- disable warning CA5394: Do not use insecure randomness -->
     <Rule Id="CA5394" Action="Info" />
     <Rule Id="CA5394" Action="Info" />
+    <!-- error on CA3003: Review code for file path injection vulnerabilities -->
+    <Rule Id="CA3003" Action="Info" />
+    <!-- error on CA3006: Review code for process command injection vulnerabilities -->
+    <Rule Id="CA3006" Action="Info" />
 
 
     <!-- disable warning CA1054: Change the type of parameter url from string to System.Uri -->
     <!-- disable warning CA1054: Change the type of parameter url from string to System.Uri -->
     <Rule Id="CA1054" Action="None" />
     <Rule Id="CA1054" Action="None" />