diff --git a/Directory.Packages.props b/Directory.Packages.props
index 9d0a6c7f..fe4b3e30 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,6 +1,7 @@
true
+ $(NoWarn);NU1510
@@ -90,4 +91,4 @@
-
\ No newline at end of file
+
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 7da2c898..99cc2fe9 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -2,7 +2,7 @@
- $(NoWarn);CA1024;CA1031;CA1032;CA1034;CA1054;CA1055;CA1056;CA1062;CA1308;CA1303;CA1305;CA1508;CA1722;CA1724;CA1805;CA1813;CA1815;CA1816;CA1819;CA1821;CA1822;CA1823;CA1824;CA1825;CA1826;CA1830;CA1836;CA1839;CA1840;CA1841;CA1859;CA1861;CA1873;CA1911;CA2000;CA2007;CA2016;CA2025;CA2026;CA2100;CA2101;CA2102;CA2201;CA2202;CA2207;CA2208;CA2219;CA2220;CA2222;CA2225;CA2226;CA2230;CA2231;CA2234;CA2241;CA2242;CA2243;CA2244;CA2245;CA2246;CA2247;CA2248;CA2249;CA2250;CA2253;CA3001;CA3002;CA3003;CA3004;CA3005;CA3006;CA3007;CA3008;CA3009;CA3010;CA3011;CA3012;CA3061;CA3062;CA5359;CA5360;CA5361;CA5362;CA5363;CA5364;CA5365;CA5366;CA5367;CA5368;CA5369;CA5370;CA5371;CA5372;CA5373;CA5374;CA5375;CA5376;CA5377;CA5378;CA5379;CA5380;CA5381;CA5382;CA5383;CA5384;CA5385;CA5386;CA5387;CA5388;CA5389;CA5390;CA5391;CA5392;CA5393;CA5394;CA5395;CA5396;CA5397;CA5398;CA5399;CA5400;CA5401;CA5402;CA5403;NU1903;CA1848;CA1515;CA1812;CA1849;CA1860;CA1867;CA1517
+ $(NoWarn);CA1024;CA1031;CA1032;CA1034;CA1054;CA1055;CA1056;CA1062;CA1308;CA1303;CA1305;CA1508;CA1722;CA1724;CA1805;CA1813;CA1815;CA1816;CA1819;CA1821;CA1822;CA1823;CA1824;CA1825;CA1826;CA1830;CA1836;CA1839;CA1840;CA1841;CA1859;CA1861;CA1873;CA1911;CA2000;CA2007;CA2016;CA2025;CA2026;CA2100;CA2101;CA2102;CA2201;CA2202;CA2207;CA2208;CA2219;CA2220;CA2222;CA2225;CA2226;CA2230;CA2231;CA2234;CA2241;CA2242;CA2243;CA2244;CA2245;CA2246;CA2247;CA2248;CA2249;CA2250;CA2253;CA3001;CA3002;CA3003;CA3004;CA3005;CA3006;CA3007;CA3008;CA3009;CA3010;CA3011;CA3012;CA3061;CA3062;CA5359;CA5360;CA5361;CA5362;CA5363;CA5364;CA5365;CA5366;CA5367;CA5368;CA5369;CA5370;CA5371;CA5372;CA5373;CA5374;CA5375;CA5376;CA5377;CA5378;CA5379;CA5380;CA5381;CA5382;CA5383;CA5384;CA5385;CA5386;CA5387;CA5388;CA5389;CA5390;CA5391;CA5392;CA5393;CA5394;CA5395;CA5396;CA5397;CA5398;CA5399;CA5400;CA5401;CA5402;CA5403;NU1903;CA1848;CA1515;CA1812;CA1849;CA1860;CA1867;CA1517;NU1510
{E383961B-9356-4D5D-8233-9A1079D03055}
@@ -25,10 +25,9 @@
-
+
-
diff --git a/Jellyfin.Server.Implementations/ScheduledTasks/PostgresPeriodicTuner.cs b/Jellyfin.Server.Implementations/ScheduledTasks/PostgresPeriodicTuner.cs
new file mode 100644
index 00000000..f48ac429
--- /dev/null
+++ b/Jellyfin.Server.Implementations/ScheduledTasks/PostgresPeriodicTuner.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Jellyfin.Data.Queries;
+using Jellyfin.Extensions.Dapper;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Plugins;
+using MediaBrowser.Controller.Session;
+using MediaBrowser.Model.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Server.Implementations.ScheduledTasks
+{
+ ///
+ /// Class PostgresPeriodicTuner.
+ ///
+ public class PostgresPeriodicTuner : IScheduledTask, IConfigurableScheduledTask
+ {
+ private readonly ILogger _logger;
+ private readonly IDbContext _dbContext;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ /// The database context.
+ public PostgresPeriodicTuner(ILogger logger, IDbContext dbContext)
+ {
+ _logger = logger;
+ _dbContext = dbContext;
+ }
+
+ ///
+ public string Name => "PostgreSQL Periodic Tuner";
+
+ ///
+ public string Key => "PostgresPeriodicTuner";
+
+ ///
+ public string Description => "Periodically checks for dead tuples and runs VACUUM ANALYZE on tables that need it.";
+
+ ///
+ public string Category => "Database";
+
+ ///
+ public bool IsHidden => false;
+
+ ///
+ public bool IsEnabled => true;
+
+ ///
+ public bool IsLogged => true;
+
+ ///
+ /// Executes the task.
+ ///
+ /// The cancellation token.
+ /// The progress.
+ /// A representing the asynchronous operation.
+ public async Task ExecuteAsync(CancellationToken cancellationToken, IProgress progress)
+ {
+ _logger.LogInformation("PostgreSQL Periodic Tuner task started.");
+
+ try
+ {
+ const string DeadTupleQuery = @"
+ SELECT
+ relname AS TableName,
+ n_dead_tup AS DeadTuples
+ FROM
+ pg_stat_user_tables
+ WHERE
+ n_dead_tup > 1000 -- Example threshold: more than 1000 dead tuples
+ ORDER BY
+ n_dead_tup DESC;";
+
+ var tablesToVacuum = (await _dbContext.QueryAsync<(string TableName, long DeadTuples)>(DeadTupleQuery)).ToList();
+
+ if (tablesToVacuum.Count == 0)
+ {
+ _logger.LogInformation("No tables require vacuuming at this time.");
+ return;
+ }
+
+ progress.Report(10);
+
+ double progressStep = 90.0 / tablesToVacuum.Count;
+ double currentProgress = 10.0;
+
+ foreach (var table in tablesToVacuum)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ _logger.LogInformation("Found {DeadTuples} dead tuples in table {TableName}. Running VACUUM ANALYZE.", table.DeadTuples, table.TableName);
+
+ try
+ {
+ await _dbContext.ExecuteAsync($"VACUUM ANALYZE \"{table.TableName}\"");
+ _logger.LogInformation("Successfully vacuumed and analyzed table {TableName}.", table.TableName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error running VACUUM ANALYZE on table {TableName}.", table.TableName);
+ }
+
+ currentProgress += progressStep;
+ progress.Report(currentProgress);
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Error during PostgreSQL Periodic Tuner task.");
+ }
+ finally
+ {
+ _logger.LogInformation("PostgreSQL Periodic Tuner task finished.");
+ progress.Report(100);
+ }
+ }
+
+ ///
+ /// Gets the default triggers.
+ ///
+ /// IEnumerable<TaskTriggerInfo>.
+ public IEnumerable GetDefaultTriggers()
+ {
+ return new[]
+ {
+ new TaskTriggerInfo
+ {
+ Type = TaskTriggerInfo.TriggerInterval,
+ IntervalTicks = TimeSpan.FromHours(24).Ticks
+ }
+ };
+ }
+ }
+}
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 3529a443..d3a3a861 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -28,7 +28,6 @@ namespace Jellyfin.Server.Extensions
using Jellyfin.Database.Implementations.Enums;
using Jellyfin.Extensions.Json;
using Jellyfin.Server.Configuration;
- using Jellyfin.Server.Filters;
using MediaBrowser.Common.Api;
using MediaBrowser.Common.Net;
using MediaBrowser.Model.Entities;
@@ -43,7 +42,6 @@ namespace Jellyfin.Server.Extensions
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
- using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
@@ -254,20 +252,7 @@ namespace Jellyfin.Server.Extensions
// Allow parameters to properly be nullable.
c.UseAllOfToExtendReferenceSchemas();
c.SupportNonNullableReferenceTypes();
-
- // TODO - remove when all types are supported in System.Text.Json
- c.AddSwaggerTypeMappings();
-
- c.SchemaFilter();
- c.SchemaFilter();
- c.OperationFilter();
- c.OperationFilter();
- c.OperationFilter();
- c.OperationFilter();
- c.OperationFilter();
- c.DocumentFilter();
- })
- .Replace(ServiceDescriptor.Transient());
+ });
}
private static void AddPolicy(this AuthorizationOptions authorizationOptions, string policyName, IAuthorizationRequirement authorizationRequirement)
@@ -327,40 +312,5 @@ namespace Jellyfin.Server.Extensions
options.KnownIPNetworks.Add(new System.Net.IPNetwork(addr, prefixLength));
}
}
-
- private static void AddSwaggerTypeMappings(this SwaggerGenOptions options)
- {
- /*
- * TODO remove when System.Text.Json properly supports non-string keys.
- * Used in BaseItemDto.ImageBlurHashes
- */
- options.MapType>(() =>
- new OpenApiSchema
- {
- Type = "object",
- AdditionalProperties = new OpenApiSchema
- {
- Type = "string"
- }
- });
-
- // Support dictionary with nullable string value.
- options.MapType>(() =>
- new OpenApiSchema
- {
- Type = "object",
- AdditionalProperties = new OpenApiSchema
- {
- Type = "string",
- Nullable = true
- }
- });
-
- // Swashbuckle doesn't use JsonOptions to describe responses, so we need to manually describe it.
- options.MapType(() => new OpenApiSchema
- {
- Type = "string"
- });
- }
}
}
diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj
index 87dc1cd3..f4320974 100644
--- a/Jellyfin.Server/Jellyfin.Server.csproj
+++ b/Jellyfin.Server/Jellyfin.Server.csproj
@@ -18,6 +18,10 @@
true
+
+
+
+
@@ -81,6 +85,7 @@
+
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 194ddd1d..7287889b 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -2,7 +2,7 @@
- $(NoWarn);CA1024;CA1031;CA1032;CA1034;CA1054;CA1055;CA1056;CA1062;CA1308;CA1303;CA1305;CA1508;CA1722;CA1724;CA1805;CA1813;CA1815;CA1816;CA1819;CA1821;CA1822;CA1823;CA1824;CA1825;CA1826;CA1830;CA1836;CA1839;CA1840;CA1841;CA1859;CA1861;CA1873;CA1911;CA2000;CA2007;CA2016;CA2025;CA2026;CA2100;CA2101;CA2102;CA2201;CA2202;CA2207;CA2208;CA2219;CA2220;CA2222;CA2225;CA2226;CA2230;CA2231;CA2234;CA2241;CA2242;CA2243;CA2244;CA2245;CA2246;CA2247;CA2248;CA2249;CA2250;CA2253;CA3001;CA3002;CA3003;CA3004;CA3005;CA3006;CA3007;CA3008;CA3009;CA3010;CA3011;CA3012;CA3061;CA3062;CA5359;CA5360;CA5361;CA5362;CA5363;CA5364;CA5365;CA5366;CA5367;CA5368;CA5369;CA5370;CA5371;CA5372;CA5373;CA5374;CA5375;CA5376;CA5377;CA5378;CA5379;CA5380;CA5381;CA5382;CA5383;CA5384;CA5385;CA5386;CA5387;CA5388;CA5389;CA5390;CA5391;CA5392;CA5393;CA5394;CA5395;CA5396;CA5397;CA5398;CA5399;CA5400;CA5401;CA5402;CA5403;NU1903;CA1848;CA1515;CA1812;CA1849;CA1860;CA1867;CA1517
+ $(NoWarn);CA1024;CA1031;CA1032;CA1034;CA1054;CA1055;CA1056;CA1062;CA1308;CA1303;CA1305;CA1508;CA1722;CA1724;CA1805;CA1813;CA1815;CA1816;CA1819;CA1821;CA1822;CA1823;CA1824;CA1825;CA1826;CA1830;CA1836;CA1839;CA1840;CA1841;CA1859;CA1861;CA1873;CA1911;CA2000;CA2007;CA2016;CA2025;CA2026;CA2100;CA2101;CA2102;CA2201;CA2202;CA2207;CA2208;CA2219;CA2220;CA2222;CA2225;CA2226;CA2230;CA2231;CA2234;CA2241;CA2242;CA2243;CA2244;CA2245;CA2246;CA2247;CA2248;CA2249;CA2250;CA2253;CA3001;CA3002;CA3003;CA3004;CA3005;CA3006;CA3007;CA3008;CA3009;CA3010;CA3011;CA3012;CA3061;CA3062;CA5359;CA5360;CA5361;CA5362;CA5363;CA5364;CA5365;CA5366;CA5367;CA5368;CA5369;CA5370;CA5371;CA5372;CA5373;CA5374;CA5375;CA5376;CA5377;CA5378;CA5379;CA5380;CA5381;CA5382;CA5383;CA5384;CA5385;CA5386;CA5387;CA5388;CA5389;CA5390;CA5391;CA5392;CA5393;CA5394;CA5395;CA5396;CA5397;CA5398;CA5399;CA5400;CA5401;CA5402;CA5403;NU1903;CA1848;CA1515;CA1812;CA1849;CA1860;CA1867;CA1517;NU1510
{442B5058-DCAF-4263-BB6A-F21E31120A1B}
@@ -20,7 +20,6 @@
-
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
index 6c06572a..534c9a98 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/TmdbClientManager.cs
@@ -286,7 +286,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb
if (ep is not null)
{
seasonNumber = ep.SeasonNumber;
- episodeNumber = ep.EpisodeNumber;
+ episodeNumber = (int)ep.EpisodeNumber;
}
}