diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs index 58552d847d..fbe68b6b97 100644 --- a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs +++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// /// the configured content types. - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs index 2bf77d729a..d8e4141acb 100644 --- a/Jellyfin.Api/Attributes/ProducesFileAttribute.cs +++ b/Jellyfin.Api/Attributes/ProducesFileAttribute.cs @@ -25,6 +25,6 @@ namespace Jellyfin.Api.Attributes /// Gets the configured content types. /// /// the configured content types. - public string[] GetContentTypes() => _contentTypes; + public string[] ContentTypes => _contentTypes; } } diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs index 0c63d24b70..e327831fe7 100644 --- a/Jellyfin.Api/BaseJellyfinApiController.cs +++ b/Jellyfin.Api/BaseJellyfinApiController.cs @@ -17,24 +17,6 @@ namespace Jellyfin.Api JsonDefaults.PascalCaseMediaType)] public class BaseJellyfinApiController : ControllerBase { - /// - /// Create a new . - /// - /// The value to return. - /// The type to return. - /// The . - protected ActionResult> Ok(List value) - => new OkResult>(value); - - /// - /// Create a new . - /// - /// The value to return. - /// The type to return. - /// The . - protected ActionResult> Ok(IReadOnlyList value) - => new OkResult>(value); - /// /// Create a new . /// diff --git a/Jellyfin.Api/Controllers/ApiKeyController.cs b/Jellyfin.Api/Controllers/ApiKeyController.cs index 593846adc9..024a15349e 100644 --- a/Jellyfin.Api/Controllers/ApiKeyController.cs +++ b/Jellyfin.Api/Controllers/ApiKeyController.cs @@ -36,7 +36,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetKeys() { - var keys = await _authenticationManager.GetApiKeys(); + var keys = await _authenticationManager.GetApiKeys().ConfigureAwait(false); return new QueryResult(keys); } diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index 49342ad5ce..534667c8c6 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -106,24 +106,26 @@ namespace Jellyfin.Api.Controllers } 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))); + + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + + return NoContent(); } - - 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); - - return NoContent(); } /// @@ -153,24 +155,26 @@ namespace Jellyfin.Api.Controllers } 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))); + + await _providerManager + .SaveImage(memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + + return NoContent(); } - - 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); - - return NoContent(); } /// @@ -341,14 +345,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).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); - // 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(); + } } /// @@ -377,14 +383,16 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - await using var memoryStream = await GetMemoryStream(Request.Body).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); - // 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(); + } } /// @@ -1788,32 +1796,35 @@ namespace Jellyfin.Api.Controllers [AcceptsImageFile] public async Task UploadCustomSplashscreen() { - await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); - - var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; - - if (!mimeType.HasValue) + var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + await using (memoryStream.ConfigureAwait(false)) { - return BadRequest("Error reading mimetype from uploaded image"); + var mimeType = MediaTypeHeaderValue.Parse(Request.ContentType).MediaType; + + 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 filePath = Path.Combine(_appPaths.DataPath, "splashscreen-upload" + extension); + var brandingOptions = _serverConfigurationManager.GetConfiguration("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); + } + + return NoContent(); } - - 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("branding"); - brandingOptions.SplashscreenLocation = filePath; - _serverConfigurationManager.SaveConfiguration("branding", brandingOptions); - - 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(); } /// diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 94710d78f2..5228e0babf 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1011,10 +1011,9 @@ namespace Jellyfin.Api.Controllers { if (!string.IsNullOrEmpty(pw)) { - using var sha = SHA1.Create(); // TODO: remove ToLower when Convert.ToHexString supports 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); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 0aa7c2ac9e..10f967dcde 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -145,7 +145,7 @@ namespace Jellyfin.Api.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult> GetRepositories() { - return _serverConfigurationManager.Configuration.PluginRepositories; + return Ok(_serverConfigurationManager.Configuration.PluginRepositories.AsEnumerable()); } /// @@ -157,7 +157,7 @@ namespace Jellyfin.Api.Controllers [HttpPost("Repositories")] [Authorize(Policy = Policies.RequiresElevation)] [ProducesResponseType(StatusCodes.Status204NoContent)] - public ActionResult SetRepositories([FromBody, Required] List repositoryInfos) + public ActionResult SetRepositories([FromBody, Required] RepositoryInfo[] repositoryInfos) { _serverConfigurationManager.Configuration.PluginRepositories = repositoryInfos; _serverConfigurationManager.SaveConfiguration(); diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 6a729b2373..b8a09990a5 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Text.Json; @@ -143,7 +144,7 @@ namespace Jellyfin.Api.Controllers public ActionResult UninstallPlugin([FromRoute, Required] Guid pluginId) { // 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. var plugin = plugins.FirstOrDefault(p => p.Instance is null) ?? plugins.OrderBy(p => p.Manifest.Status).FirstOrDefault(); diff --git a/Jellyfin.Api/Controllers/SubtitleController.cs b/Jellyfin.Api/Controllers/SubtitleController.cs index ff9bd095b5..c3ce1868e2 100644 --- a/Jellyfin.Api/Controllers/SubtitleController.cs +++ b/Jellyfin.Api/Controllers/SubtitleController.cs @@ -236,14 +236,17 @@ namespace Jellyfin.Api.Controllers 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( @@ -403,19 +406,22 @@ namespace Jellyfin.Api.Controllers { var video = (Video)_libraryManager.GetItemById(itemId); 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(); + } } /// diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index e194fc556e..99347246e0 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Constants; @@ -107,7 +108,7 @@ namespace Jellyfin.Api.Controllers { var currentSession = await RequestHelpers.GetSession(_sessionManager, _userManager, HttpContext).ConfigureAwait(false); var syncPlayRequest = new ListGroupsRequest(); - return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest)); + return Ok(_syncPlayManager.ListGroups(currentSession, syncPlayRequest).AsEnumerable()); } /// diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index 411c987f39..2d594293e0 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -216,8 +216,7 @@ namespace Jellyfin.Api.Controllers public ActionResult> GetWakeOnLanInfo() { var result = _network.GetMacAddresses() - .Select(i => new WakeOnLanInfo(i)) - .ToList(); + .Select(i => new WakeOnLanInfo(i)); return Ok(result); } } diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index c18fa29af6..cd21c5f6ff 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -211,7 +211,7 @@ namespace Jellyfin.Api.Controllers if (item is IHasTrailers hasTrailers) { 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() diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 889f7dc9ab..eca68c6dfa 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -12,10 +12,6 @@ AD0001 - - false - - diff --git a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs index f43822da77..e293c461cf 100644 --- a/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs +++ b/Jellyfin.Api/Models/LiveTvDtos/ChannelMappingOptionsDto.cs @@ -14,14 +14,12 @@ namespace Jellyfin.Api.Models.LiveTvDtos /// /// Gets or sets list of tuner channels. /// - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "TunerChannels", Justification = "Imported from ServiceStack")] - public List TunerChannels { get; set; } = null!; + required public IReadOnlyList TunerChannels { get; set; } /// /// Gets or sets list of provider channels. /// - [SuppressMessage("Microsoft.Performance", "CA2227:ReadOnlyRemoveSetter", MessageId = "ProviderChannels", Justification = "Imported from ServiceStack")] - public List ProviderChannels { get; set; } = null!; + required public IReadOnlyList ProviderChannels { get; set; } /// /// Gets or sets list of mappings. diff --git a/Jellyfin.Server/Filters/FileRequestFilter.cs b/Jellyfin.Server/Filters/FileRequestFilter.cs index 69e10994f4..bb5d6a4123 100644 --- a/Jellyfin.Server/Filters/FileRequestFilter.cs +++ b/Jellyfin.Server/Filters/FileRequestFilter.cs @@ -15,7 +15,7 @@ namespace Jellyfin.Server.Filters { if (attribute is AcceptsFileAttribute acceptsFileAttribute) { - operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes()); + operation.RequestBody = GetRequestBody(acceptsFileAttribute.ContentTypes); break; } } diff --git a/Jellyfin.Server/Filters/FileResponseFilter.cs b/Jellyfin.Server/Filters/FileResponseFilter.cs index 544fdbfd63..1a4559d260 100644 --- a/Jellyfin.Server/Filters/FileResponseFilter.cs +++ b/Jellyfin.Server/Filters/FileResponseFilter.cs @@ -40,7 +40,7 @@ namespace Jellyfin.Server.Filters response.Value.Content.Clear(); // Add all content-types as file. - foreach (var contentType in producesFileAttribute.GetContentTypes()) + foreach (var contentType in producesFileAttribute.ContentTypes) { response.Value.Content.Add(contentType, _openApiMediaType); } diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs index f6d8c9cc0d..9e12c2e6bd 100644 --- a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs @@ -38,7 +38,7 @@ namespace Jellyfin.Server.Migrations.Routines /// public void Perform() { - _serverConfigurationManager.Configuration.PluginRepositories.Add(_defaultRepositoryInfo); + _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo }; _serverConfigurationManager.SaveConfiguration(); } } diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index 394f14d63c..9cfaec46f8 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -39,9 +39,9 @@ namespace Jellyfin.Server.Migrations.Routines public void Perform() { // 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(); } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index a07ab7121e..d3e042abaa 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -194,7 +194,7 @@ namespace MediaBrowser.Model.Configuration public string[] CodecsUsed { get; set; } = Array.Empty(); - public List PluginRepositories { get; set; } = new List(); + public RepositoryInfo[] PluginRepositories { get; set; } = Array.Empty(); public bool EnableExternalContentInSuggestions { get; set; } = true; diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 71385cee2a..3fda774b8d 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -138,6 +138,10 @@ + + + +