diff --git a/Jellyfin.Server/Migrations/JellyfinMigrationAttribute.cs b/Jellyfin.Server/Migrations/JellyfinMigrationAttribute.cs
index f523bc76c1..5c8322ef78 100644
--- a/Jellyfin.Server/Migrations/JellyfinMigrationAttribute.cs
+++ b/Jellyfin.Server/Migrations/JellyfinMigrationAttribute.cs
@@ -17,7 +17,9 @@ public sealed class JellyfinMigrationAttribute : Attribute
///
/// The ordering this migration should be applied to. Must be a valid DateTime ISO8601 formatted string.
/// The name of this Migration.
+#pragma warning disable CS0618 // Type or member is obsolete
public JellyfinMigrationAttribute(string order, string name) : this(order, name, null)
+#pragma warning restore CS0618 // Type or member is obsolete
{
}
@@ -27,6 +29,7 @@ public sealed class JellyfinMigrationAttribute : Attribute
/// The ordering this migration should be applied to. Must be a valid DateTime ISO8601 formatted string.
/// The name of this Migration.
/// [ONLY FOR LEGACY MIGRATIONS]The unique key of this migration. Must be a valid Guid formatted string.
+ [Obsolete("This Constructor should only be used for Legacy migrations. Use the (Order,Name) one for all new ones instead.")]
public JellyfinMigrationAttribute(string order, string name, string? key)
{
Order = DateTime.Parse(order, CultureInfo.InvariantCulture);
diff --git a/Jellyfin.Server/Migrations/JellyfinMigrationService.cs b/Jellyfin.Server/Migrations/JellyfinMigrationService.cs
index 46c22d16cc..ebffab7ef0 100644
--- a/Jellyfin.Server/Migrations/JellyfinMigrationService.cs
+++ b/Jellyfin.Server/Migrations/JellyfinMigrationService.cs
@@ -108,8 +108,9 @@ internal class JellyfinMigrationService
{
var historyRepository = dbContext.GetService();
var appliedMigrations = await dbContext.Database.GetAppliedMigrationsAsync().ConfigureAwait(false);
- var oldMigrations = Migrations.SelectMany(e => e)
- .Where(e => migrationOptions.Applied.Any(f => f.Id.Equals(e.Metadata.Key!.Value))) // this is a legacy migration that will always have its own ID.
+ var oldMigrations = Migrations
+ .SelectMany(e => e.Where(e => e.Metadata.Key is not null)) // only consider migrations that have the key set as its the reference marker for legacy migrations.
+ .Where(e => migrationOptions.Applied.Any(f => f.Id.Equals(e.Metadata.Key!.Value)))
.Where(e => !appliedMigrations.Contains(e.BuildCodeMigrationId()))
.ToArray();
var startupScripts = oldMigrations.Select(e => (Migration: e.Metadata, Script: historyRepository.GetInsertScript(new HistoryRow(e.BuildCodeMigrationId(), GetJellyfinVersion()))));
diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs
index a62523b88f..fd472cff7c 100644
--- a/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs
+++ b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs
@@ -8,8 +8,8 @@ using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.PreStartupRoutines;
///
-[JellyfinMigration("2025-04-20T00:00:00", nameof(CreateNetworkConfiguration), "9B354818-94D5-4B68-AC49-E35CB85F9D84", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T00:00:00", nameof(CreateNetworkConfiguration), "9B354818-94D5-4B68-AC49-E35CB85F9D84", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
public class CreateNetworkConfiguration : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateEncodingOptions.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateEncodingOptions.cs
index 3455696994..0141b43c96 100644
--- a/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateEncodingOptions.cs
+++ b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateEncodingOptions.cs
@@ -10,8 +10,8 @@ using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.PreStartupRoutines;
///
-[JellyfinMigration("2025-04-20T03:00:00", nameof(MigrateEncodingOptions), "A8E61960-7726-4450-8F3D-82C12DAABBCB", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T03:00:00", nameof(MigrateEncodingOptions), "A8E61960-7726-4450-8F3D-82C12DAABBCB", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
public class MigrateEncodingOptions : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateMusicBrainzTimeout.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateMusicBrainzTimeout.cs
index bdbf0c1ce4..e8da9f515d 100644
--- a/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateMusicBrainzTimeout.cs
+++ b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateMusicBrainzTimeout.cs
@@ -9,8 +9,8 @@ using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.PreStartupRoutines;
///
-[JellyfinMigration("2025-04-20T02:00:00", nameof(MigrateMusicBrainzTimeout), "A6DCACF4-C057-4Ef9-80D3-61CEF9DDB4F0", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T02:00:00", nameof(MigrateMusicBrainzTimeout), "A6DCACF4-C057-4Ef9-80D3-61CEF9DDB4F0", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
public class MigrateMusicBrainzTimeout : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/RenameEnableGroupingIntoCollections.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/RenameEnableGroupingIntoCollections.cs
index c0ca7896fb..995b2bbf9b 100644
--- a/Jellyfin.Server/Migrations/PreStartupRoutines/RenameEnableGroupingIntoCollections.cs
+++ b/Jellyfin.Server/Migrations/PreStartupRoutines/RenameEnableGroupingIntoCollections.cs
@@ -9,8 +9,8 @@ using Microsoft.Extensions.Logging;
namespace Jellyfin.Server.Migrations.PreStartupRoutines;
///
-[JellyfinMigration("2025-04-20T04:00:00", nameof(RenameEnableGroupingIntoCollections), "E73B777D-CD5C-4E71-957A-B86B3660B7CF", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T04:00:00", nameof(RenameEnableGroupingIntoCollections), "E73B777D-CD5C-4E71-957A-B86B3660B7CF", Stage = Stages.JellyfinMigrationStageTypes.PreInitialisation)]
public class RenameEnableGroupingIntoCollections : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs
index 7e92433423..00d152b4b8 100644
--- a/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs
+++ b/Jellyfin.Server/Migrations/Routines/AddDefaultCastReceivers.cs
@@ -7,8 +7,8 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to add the default cast receivers to the system config.
///
-[JellyfinMigration("2025-04-20T16:00:00", nameof(AddDefaultCastReceivers), "34A1A1C4-5572-418E-A2F8-32CDFE2668E8", RunMigrationOnSetup = true)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T16:00:00", nameof(AddDefaultCastReceivers), "34A1A1C4-5572-418E-A2F8-32CDFE2668E8", RunMigrationOnSetup = true)]
public class AddDefaultCastReceivers : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs
index 603e01c180..8c8398a161 100644
--- a/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs
+++ b/Jellyfin.Server/Migrations/Routines/AddDefaultPluginRepository.cs
@@ -7,8 +7,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// Migration to initialize system configuration with the default plugin repository.
///
- [JellyfinMigration("2025-04-20T09:00:00", nameof(AddDefaultPluginRepository), "EB58EBEE-9514-4B9B-8225-12E1A40020DF", RunMigrationOnSetup = true)]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T09:00:00", nameof(AddDefaultPluginRepository), "EB58EBEE-9514-4B9B-8225-12E1A40020DF", RunMigrationOnSetup = true)]
public class AddDefaultPluginRepository : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
index 9d2a901cd9..1326a6dc8d 100644
--- a/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
+++ b/Jellyfin.Server/Migrations/Routines/CreateUserLoggingConfigFile.cs
@@ -12,8 +12,8 @@ namespace Jellyfin.Server.Migrations.Routines
/// If the deprecated logging.json file exists and has a custom config, it will be used as logging.user.json,
/// otherwise a blank file will be created.
///
- [JellyfinMigration("2025-04-20T06:00:00", nameof(CreateUserLoggingConfigFile), "EF103419-8451-40D8-9F34-D1A8E93A1679")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T06:00:00", nameof(CreateUserLoggingConfigFile), "EF103419-8451-40D8-9F34-D1A8E93A1679")]
internal class CreateUserLoggingConfigFile : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
index ca9bf32648..acf2835fe0 100644
--- a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
+++ b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
@@ -7,8 +7,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// Disable transcode throttling for all installations since it is currently broken for certain video formats.
///
- [JellyfinMigration("2025-04-20T05:00:00", nameof(DisableTranscodingThrottling), "4124C2CD-E939-4FFB-9BE9-9B311C413638")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T05:00:00", nameof(DisableTranscodingThrottling), "4124C2CD-E939-4FFB-9BE9-9B311C413638")]
internal class DisableTranscodingThrottling : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/FixAudioData.cs b/Jellyfin.Server/Migrations/Routines/FixAudioData.cs
index 6ebb5000e4..af8787b955 100644
--- a/Jellyfin.Server/Migrations/Routines/FixAudioData.cs
+++ b/Jellyfin.Server/Migrations/Routines/FixAudioData.cs
@@ -16,8 +16,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// Fixes the data column of audio types to be deserializable.
///
- [JellyfinMigration("2025-04-20T18:00:00", nameof(FixAudioData), "CF6FABC2-9FBE-4933-84A5-FFE52EF22A58")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T18:00:00", nameof(FixAudioData), "CF6FABC2-9FBE-4933-84A5-FFE52EF22A58")]
internal class FixAudioData : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs
index f31c1afbd3..56614ece3c 100644
--- a/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs
+++ b/Jellyfin.Server/Migrations/Routines/FixPlaylistOwner.cs
@@ -13,8 +13,8 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Properly set playlist owner.
///
-[JellyfinMigration("2025-04-20T15:00:00", nameof(FixPlaylistOwner), "615DFA9E-2497-4DBB-A472-61938B752C5B")]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T15:00:00", nameof(FixPlaylistOwner), "615DFA9E-2497-4DBB-A472-61938B752C5B")]
internal class FixPlaylistOwner : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
index 14089cac75..a954d307e1 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateActivityLogDb.cs
@@ -14,8 +14,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// The migration routine for migrating the activity log database to EF Core.
///
- [JellyfinMigration("2025-04-20T07:00:00", nameof(MigrateActivityLogDb), "3793eb59-bc8c-456c-8b9f-bd5a62a42978")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T07:00:00", nameof(MigrateActivityLogDb), "3793eb59-bc8c-456c-8b9f-bd5a62a42978")]
public class MigrateActivityLogDb : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs
index e4362f44da..c6699c21df 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateAuthenticationDb.cs
@@ -15,8 +15,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// A migration that moves data from the authentication database into the new schema.
///
- [JellyfinMigration("2025-04-20T14:00:00", nameof(MigrateAuthenticationDb), "5BD72F41-E6F3-4F60-90AA-09869ABE0E22")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T14:00:00", nameof(MigrateAuthenticationDb), "5BD72F41-E6F3-4F60-90AA-09869ABE0E22")]
public class MigrateAuthenticationDb : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
index 49ed01d6bb..0d9952ce97 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateDisplayPreferencesDb.cs
@@ -20,8 +20,8 @@ namespace Jellyfin.Server.Migrations.Routines
///
/// The migration routine for migrating the display preferences database to EF Core.
///
- [JellyfinMigration("2025-04-20T12:00:00", nameof(MigrateDisplayPreferencesDb), "06387815-C3CC-421F-A888-FB5F9992BEA8")]
#pragma warning disable CS0618 // Type or member is obsolete
+ [JellyfinMigration("2025-04-20T12:00:00", nameof(MigrateDisplayPreferencesDb), "06387815-C3CC-421F-A888-FB5F9992BEA8")]
public class MigrateDisplayPreferencesDb : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs
index 1ee4c41c37..03a5212585 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateKeyframeData.cs
@@ -19,7 +19,7 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to move extracted files to the new directories.
///
-[JellyfinMigration("2025-04-21T00:00:00", nameof(MigrateKeyframeData), "EA4bCAE1-09A4-428E-9B90-4B4FD2EA1B24")]
+[JellyfinMigration("2025-04-21T00:00:00", nameof(MigrateKeyframeData))]
public class MigrateKeyframeData : IDatabaseMigrationRoutine
{
private readonly ILogger _logger;
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
index 8374508e66..c9d2899407 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateLibraryDb.cs
@@ -9,26 +9,16 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
-using System.Threading;
using Emby.Server.Implementations.Data;
using Jellyfin.Database.Implementations;
using Jellyfin.Database.Implementations.Entities;
using Jellyfin.Extensions;
using Jellyfin.Server.Implementations.Item;
using MediaBrowser.Controller;
-using MediaBrowser.Controller.Channels;
-using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Globalization;
-using MediaBrowser.Model.IO;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using BaseItemEntity = Jellyfin.Database.Implementations.Entities.BaseItemEntity;
using Chapter = Jellyfin.Database.Implementations.Entities.Chapter;
@@ -38,7 +28,7 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// The migration routine for migrating the userdata database to EF Core.
///
-[JellyfinMigration("2025-04-20T20:00:00", nameof(MigrateLibraryDb), "36445464-849f-429f-9ad0-bb130efa0664")]
+[JellyfinMigration("2025-04-20T20:00:00", nameof(MigrateLibraryDb))]
internal class MigrateLibraryDb : IDatabaseMigrationRoutine
{
private const string DbFilename = "library.db";
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs
index 96276e9b10..234965c0a5 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateRatingLevels.cs
@@ -5,62 +5,63 @@ using MediaBrowser.Model.Globalization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
-namespace Jellyfin.Server.Migrations.Routines
+namespace Jellyfin.Server.Migrations.Routines;
+
+///
+/// Migrate rating levels.
+///
+#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T22:00:00", nameof(MigrateRatingLevels))]
+#pragma warning restore CS0618 // Type or member is obsolete
+internal class MigrateRatingLevels : IDatabaseMigrationRoutine
{
- ///
- /// Migrate rating levels.
- ///
- [JellyfinMigration("2025-04-20T22:00:00", nameof(MigrateRatingLevels), "98724538-EB11-40E3-931A-252C55BDDE7A")]
- internal class MigrateRatingLevels : IDatabaseMigrationRoutine
+ private readonly ILogger _logger;
+ private readonly IDbContextFactory _provider;
+ private readonly ILocalizationManager _localizationManager;
+
+ public MigrateRatingLevels(
+ IDbContextFactory provider,
+ ILoggerFactory loggerFactory,
+ ILocalizationManager localizationManager)
{
- private readonly ILogger _logger;
- private readonly IDbContextFactory _provider;
- private readonly ILocalizationManager _localizationManager;
+ _provider = provider;
+ _localizationManager = localizationManager;
+ _logger = loggerFactory.CreateLogger();
+ }
- public MigrateRatingLevels(
- IDbContextFactory provider,
- ILoggerFactory loggerFactory,
- ILocalizationManager localizationManager)
+ ///
+ public void Perform()
+ {
+ _logger.LogInformation("Recalculating parental rating levels based on rating string.");
+ using var context = _provider.CreateDbContext();
+ using var transaction = context.Database.BeginTransaction();
+ var ratings = context.BaseItems.AsNoTracking().Select(e => e.OfficialRating).Distinct();
+ foreach (var rating in ratings)
{
- _provider = provider;
- _localizationManager = localizationManager;
- _logger = loggerFactory.CreateLogger();
- }
-
- ///
- public void Perform()
- {
- _logger.LogInformation("Recalculating parental rating levels based on rating string.");
- using var context = _provider.CreateDbContext();
- using var transaction = context.Database.BeginTransaction();
- var ratings = context.BaseItems.AsNoTracking().Select(e => e.OfficialRating).Distinct();
- foreach (var rating in ratings)
+ if (string.IsNullOrEmpty(rating))
{
- if (string.IsNullOrEmpty(rating))
- {
- int? value = null;
- context.BaseItems
- .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
- .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, value));
- context.BaseItems
- .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
- .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, value));
- }
- else
- {
- var ratingValue = _localizationManager.GetRatingScore(rating);
- var score = ratingValue?.Score;
- var subScore = ratingValue?.SubScore;
- context.BaseItems
- .Where(e => e.OfficialRating == rating)
- .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, score));
- context.BaseItems
- .Where(e => e.OfficialRating == rating)
- .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, subScore));
- }
+ int? value = null;
+ context.BaseItems
+ .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
+ .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, value));
+ context.BaseItems
+ .Where(e => e.OfficialRating == null || e.OfficialRating == string.Empty)
+ .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, value));
+ }
+ else
+ {
+ var ratingValue = _localizationManager.GetRatingScore(rating);
+ var score = ratingValue?.Score;
+ var subScore = ratingValue?.SubScore;
+ context.BaseItems
+ .Where(e => e.OfficialRating == rating)
+ .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingValue, score));
+ context.BaseItems
+ .Where(e => e.OfficialRating == rating)
+ .ExecuteUpdate(f => f.SetProperty(e => e.InheritedParentalRatingSubValue, subScore));
}
-
- transaction.Commit();
}
+
+ transaction.Commit();
}
}
diff --git a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
index 7a23fcc98c..e5584fb947 100644
--- a/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
+++ b/Jellyfin.Server/Migrations/Routines/MigrateUserDb.cs
@@ -17,201 +17,200 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using JsonSerializer = System.Text.Json.JsonSerializer;
-namespace Jellyfin.Server.Migrations.Routines
-{
- ///
- /// The migration routine for migrating the user database to EF Core.
- ///
- [JellyfinMigration("2025-04-20T10:00:00", nameof(MigrateUserDb), "5C4B82A2-F053-4009-BD05-B6FCAD82F14C")]
+namespace Jellyfin.Server.Migrations.Routines;
+
+///
+/// The migration routine for migrating the user database to EF Core.
+///
#pragma warning disable CS0618 // Type or member is obsolete
- public class MigrateUserDb : IMigrationRoutine
+[JellyfinMigration("2025-04-20T10:00:00", nameof(MigrateUserDb), "5C4B82A2-F053-4009-BD05-B6FCAD82F14C")]
+public class MigrateUserDb : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
+{
+ private const string DbFilename = "users.db";
+
+ private readonly ILogger _logger;
+ private readonly IServerApplicationPaths _paths;
+ private readonly IDbContextFactory _provider;
+ private readonly IXmlSerializer _xmlSerializer;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ /// The server application paths.
+ /// The database provider.
+ /// The xml serializer.
+ public MigrateUserDb(
+ ILogger logger,
+ IServerApplicationPaths paths,
+ IDbContextFactory provider,
+ IXmlSerializer xmlSerializer)
{
- private const string DbFilename = "users.db";
+ _logger = logger;
+ _paths = paths;
+ _provider = provider;
+ _xmlSerializer = xmlSerializer;
+ }
- private readonly ILogger _logger;
- private readonly IServerApplicationPaths _paths;
- private readonly IDbContextFactory _provider;
- private readonly IXmlSerializer _xmlSerializer;
+ ///
+ public void Perform()
+ {
+ var dataPath = _paths.DataPath;
+ _logger.LogInformation("Migrating the user database may take a while, do not stop Jellyfin.");
- ///
- /// Initializes a new instance of the class.
- ///
- /// The logger.
- /// The server application paths.
- /// The database provider.
- /// The xml serializer.
- public MigrateUserDb(
- ILogger logger,
- IServerApplicationPaths paths,
- IDbContextFactory provider,
- IXmlSerializer xmlSerializer)
+ using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}"))
{
- _logger = logger;
- _paths = paths;
- _provider = provider;
- _xmlSerializer = xmlSerializer;
- }
+ connection.Open();
+ using var dbContext = _provider.CreateDbContext();
- ///
- public void Perform()
- {
- var dataPath = _paths.DataPath;
- _logger.LogInformation("Migrating the user database may take a while, do not stop Jellyfin.");
+ var queryResult = connection.Query("SELECT * FROM LocalUsersv2");
- using (var connection = new SqliteConnection($"Filename={Path.Combine(dataPath, DbFilename)}"))
+ dbContext.RemoveRange(dbContext.Users);
+ dbContext.SaveChanges();
+
+ foreach (var entry in queryResult)
{
- connection.Open();
- using var dbContext = _provider.CreateDbContext();
-
- var queryResult = connection.Query("SELECT * FROM LocalUsersv2");
-
- dbContext.RemoveRange(dbContext.Users);
- dbContext.SaveChanges();
-
- foreach (var entry in queryResult)
+ UserMockup? mockup = JsonSerializer.Deserialize(entry.GetStream(2), JsonDefaults.Options);
+ if (mockup is null)
{
- UserMockup? mockup = JsonSerializer.Deserialize(entry.GetStream(2), JsonDefaults.Options);
- if (mockup is null)
- {
- continue;
- }
-
- var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
-
- var configPath = Path.Combine(userDataDir, "config.xml");
- var config = File.Exists(configPath)
- ? (UserConfiguration?)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), configPath) ?? new UserConfiguration()
- : new UserConfiguration();
-
- var policyPath = Path.Combine(userDataDir, "policy.xml");
- var policy = File.Exists(policyPath)
- ? (UserPolicy?)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), policyPath) ?? new UserPolicy()
- : new UserPolicy();
- policy.AuthenticationProviderId = policy.AuthenticationProviderId?.Replace(
- "Emby.Server.Implementations.Library",
- "Jellyfin.Server.Implementations.Users",
- StringComparison.Ordinal)
- ?? typeof(DefaultAuthenticationProvider).FullName;
-
- policy.PasswordResetProviderId = typeof(DefaultPasswordResetProvider).FullName;
- int? maxLoginAttempts = policy.LoginAttemptsBeforeLockout switch
- {
- -1 => null,
- 0 => 3,
- _ => policy.LoginAttemptsBeforeLockout
- };
-
- var user = new User(mockup.Name, policy.AuthenticationProviderId!, policy.PasswordResetProviderId!)
- {
- Id = entry.GetGuid(1),
- InternalId = entry.GetInt64(0),
- MaxParentalRatingScore = policy.MaxParentalRating,
- MaxParentalRatingSubScore = null,
- EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess,
- RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit,
- InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount,
- LoginAttemptsBeforeLockout = maxLoginAttempts,
- SubtitleMode = config.SubtitleMode,
- HidePlayedInLatest = config.HidePlayedInLatest,
- EnableLocalPassword = config.EnableLocalPassword,
- PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
- DisplayCollectionsView = config.DisplayCollectionsView,
- DisplayMissingEpisodes = config.DisplayMissingEpisodes,
- AudioLanguagePreference = config.AudioLanguagePreference,
- RememberAudioSelections = config.RememberAudioSelections,
- EnableNextEpisodeAutoPlay = config.EnableNextEpisodeAutoPlay,
- RememberSubtitleSelections = config.RememberSubtitleSelections,
- SubtitleLanguagePreference = config.SubtitleLanguagePreference,
- Password = mockup.Password,
- LastLoginDate = mockup.LastLoginDate,
- LastActivityDate = mockup.LastActivityDate
- };
-
- if (mockup.ImageInfos.Length > 0)
- {
- ItemImageInfo info = mockup.ImageInfos[0];
-
- user.ProfileImage = new ImageInfo(info.Path)
- {
- LastModified = info.DateModified
- };
- }
-
- user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator);
- user.SetPermission(PermissionKind.IsHidden, policy.IsHidden);
- user.SetPermission(PermissionKind.IsDisabled, policy.IsDisabled);
- user.SetPermission(PermissionKind.EnableSharedDeviceControl, policy.EnableSharedDeviceControl);
- user.SetPermission(PermissionKind.EnableRemoteAccess, policy.EnableRemoteAccess);
- user.SetPermission(PermissionKind.EnableLiveTvManagement, policy.EnableLiveTvManagement);
- user.SetPermission(PermissionKind.EnableLiveTvAccess, policy.EnableLiveTvAccess);
- user.SetPermission(PermissionKind.EnableMediaPlayback, policy.EnableMediaPlayback);
- user.SetPermission(PermissionKind.EnableAudioPlaybackTranscoding, policy.EnableAudioPlaybackTranscoding);
- user.SetPermission(PermissionKind.EnableVideoPlaybackTranscoding, policy.EnableVideoPlaybackTranscoding);
- user.SetPermission(PermissionKind.EnableContentDeletion, policy.EnableContentDeletion);
- user.SetPermission(PermissionKind.EnableContentDownloading, policy.EnableContentDownloading);
- user.SetPermission(PermissionKind.EnableSyncTranscoding, policy.EnableSyncTranscoding);
- user.SetPermission(PermissionKind.EnableMediaConversion, policy.EnableMediaConversion);
- user.SetPermission(PermissionKind.EnableAllChannels, policy.EnableAllChannels);
- user.SetPermission(PermissionKind.EnableAllDevices, policy.EnableAllDevices);
- user.SetPermission(PermissionKind.EnableAllFolders, policy.EnableAllFolders);
- user.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, policy.EnableRemoteControlOfOtherUsers);
- user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing);
- user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding);
- user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing);
- user.SetPermission(PermissionKind.EnableCollectionManagement, policy.EnableCollectionManagement);
-
- foreach (var policyAccessSchedule in policy.AccessSchedules)
- {
- user.AccessSchedules.Add(policyAccessSchedule);
- }
-
- user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags);
- user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels);
- user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices);
- user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders);
- user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders);
- user.SetPreference(PreferenceKind.OrderedViews, config.OrderedViews);
- user.SetPreference(PreferenceKind.GroupedFolders, config.GroupedFolders);
- user.SetPreference(PreferenceKind.MyMediaExcludes, config.MyMediaExcludes);
- user.SetPreference(PreferenceKind.LatestItemExcludes, config.LatestItemsExcludes);
-
- dbContext.Users.Add(user);
+ continue;
}
- dbContext.SaveChanges();
- }
+ var userDataDir = Path.Combine(_paths.UserConfigurationDirectoryPath, mockup.Name);
- try
- {
- File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
+ var configPath = Path.Combine(userDataDir, "config.xml");
+ var config = File.Exists(configPath)
+ ? (UserConfiguration?)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), configPath) ?? new UserConfiguration()
+ : new UserConfiguration();
- var journalPath = Path.Combine(dataPath, DbFilename + "-journal");
- if (File.Exists(journalPath))
+ var policyPath = Path.Combine(userDataDir, "policy.xml");
+ var policy = File.Exists(policyPath)
+ ? (UserPolicy?)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), policyPath) ?? new UserPolicy()
+ : new UserPolicy();
+ policy.AuthenticationProviderId = policy.AuthenticationProviderId?.Replace(
+ "Emby.Server.Implementations.Library",
+ "Jellyfin.Server.Implementations.Users",
+ StringComparison.Ordinal)
+ ?? typeof(DefaultAuthenticationProvider).FullName;
+
+ policy.PasswordResetProviderId = typeof(DefaultPasswordResetProvider).FullName;
+ int? maxLoginAttempts = policy.LoginAttemptsBeforeLockout switch
{
- File.Move(journalPath, Path.Combine(dataPath, DbFilename + ".old-journal"));
+ -1 => null,
+ 0 => 3,
+ _ => policy.LoginAttemptsBeforeLockout
+ };
+
+ var user = new User(mockup.Name, policy.AuthenticationProviderId!, policy.PasswordResetProviderId!)
+ {
+ Id = entry.GetGuid(1),
+ InternalId = entry.GetInt64(0),
+ MaxParentalRatingScore = policy.MaxParentalRating,
+ MaxParentalRatingSubScore = null,
+ EnableUserPreferenceAccess = policy.EnableUserPreferenceAccess,
+ RemoteClientBitrateLimit = policy.RemoteClientBitrateLimit,
+ InvalidLoginAttemptCount = policy.InvalidLoginAttemptCount,
+ LoginAttemptsBeforeLockout = maxLoginAttempts,
+ SubtitleMode = config.SubtitleMode,
+ HidePlayedInLatest = config.HidePlayedInLatest,
+ EnableLocalPassword = config.EnableLocalPassword,
+ PlayDefaultAudioTrack = config.PlayDefaultAudioTrack,
+ DisplayCollectionsView = config.DisplayCollectionsView,
+ DisplayMissingEpisodes = config.DisplayMissingEpisodes,
+ AudioLanguagePreference = config.AudioLanguagePreference,
+ RememberAudioSelections = config.RememberAudioSelections,
+ EnableNextEpisodeAutoPlay = config.EnableNextEpisodeAutoPlay,
+ RememberSubtitleSelections = config.RememberSubtitleSelections,
+ SubtitleLanguagePreference = config.SubtitleLanguagePreference,
+ Password = mockup.Password,
+ LastLoginDate = mockup.LastLoginDate,
+ LastActivityDate = mockup.LastActivityDate
+ };
+
+ if (mockup.ImageInfos.Length > 0)
+ {
+ ItemImageInfo info = mockup.ImageInfos[0];
+
+ user.ProfileImage = new ImageInfo(info.Path)
+ {
+ LastModified = info.DateModified
+ };
}
+
+ user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator);
+ user.SetPermission(PermissionKind.IsHidden, policy.IsHidden);
+ user.SetPermission(PermissionKind.IsDisabled, policy.IsDisabled);
+ user.SetPermission(PermissionKind.EnableSharedDeviceControl, policy.EnableSharedDeviceControl);
+ user.SetPermission(PermissionKind.EnableRemoteAccess, policy.EnableRemoteAccess);
+ user.SetPermission(PermissionKind.EnableLiveTvManagement, policy.EnableLiveTvManagement);
+ user.SetPermission(PermissionKind.EnableLiveTvAccess, policy.EnableLiveTvAccess);
+ user.SetPermission(PermissionKind.EnableMediaPlayback, policy.EnableMediaPlayback);
+ user.SetPermission(PermissionKind.EnableAudioPlaybackTranscoding, policy.EnableAudioPlaybackTranscoding);
+ user.SetPermission(PermissionKind.EnableVideoPlaybackTranscoding, policy.EnableVideoPlaybackTranscoding);
+ user.SetPermission(PermissionKind.EnableContentDeletion, policy.EnableContentDeletion);
+ user.SetPermission(PermissionKind.EnableContentDownloading, policy.EnableContentDownloading);
+ user.SetPermission(PermissionKind.EnableSyncTranscoding, policy.EnableSyncTranscoding);
+ user.SetPermission(PermissionKind.EnableMediaConversion, policy.EnableMediaConversion);
+ user.SetPermission(PermissionKind.EnableAllChannels, policy.EnableAllChannels);
+ user.SetPermission(PermissionKind.EnableAllDevices, policy.EnableAllDevices);
+ user.SetPermission(PermissionKind.EnableAllFolders, policy.EnableAllFolders);
+ user.SetPermission(PermissionKind.EnableRemoteControlOfOtherUsers, policy.EnableRemoteControlOfOtherUsers);
+ user.SetPermission(PermissionKind.EnablePlaybackRemuxing, policy.EnablePlaybackRemuxing);
+ user.SetPermission(PermissionKind.ForceRemoteSourceTranscoding, policy.ForceRemoteSourceTranscoding);
+ user.SetPermission(PermissionKind.EnablePublicSharing, policy.EnablePublicSharing);
+ user.SetPermission(PermissionKind.EnableCollectionManagement, policy.EnableCollectionManagement);
+
+ foreach (var policyAccessSchedule in policy.AccessSchedules)
+ {
+ user.AccessSchedules.Add(policyAccessSchedule);
+ }
+
+ user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags);
+ user.SetPreference(PreferenceKind.EnabledChannels, policy.EnabledChannels);
+ user.SetPreference(PreferenceKind.EnabledDevices, policy.EnabledDevices);
+ user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders);
+ user.SetPreference(PreferenceKind.EnableContentDeletionFromFolders, policy.EnableContentDeletionFromFolders);
+ user.SetPreference(PreferenceKind.OrderedViews, config.OrderedViews);
+ user.SetPreference(PreferenceKind.GroupedFolders, config.GroupedFolders);
+ user.SetPreference(PreferenceKind.MyMediaExcludes, config.MyMediaExcludes);
+ user.SetPreference(PreferenceKind.LatestItemExcludes, config.LatestItemsExcludes);
+
+ dbContext.Users.Add(user);
}
- catch (IOException e)
- {
- _logger.LogError(e, "Error renaming legacy user database to 'users.db.old'");
- }
+
+ dbContext.SaveChanges();
}
-#nullable disable
- internal class UserMockup
+ try
{
- public string Password { get; set; }
+ File.Move(Path.Combine(dataPath, DbFilename), Path.Combine(dataPath, DbFilename + ".old"));
- public string EasyPassword { get; set; }
-
- public DateTime? LastLoginDate { get; set; }
-
- public DateTime? LastActivityDate { get; set; }
-
- public string Name { get; set; }
-
- public ItemImageInfo[] ImageInfos { get; set; }
+ var journalPath = Path.Combine(dataPath, DbFilename + "-journal");
+ if (File.Exists(journalPath))
+ {
+ File.Move(journalPath, Path.Combine(dataPath, DbFilename + ".old-journal"));
+ }
+ }
+ catch (IOException e)
+ {
+ _logger.LogError(e, "Error renaming legacy user database to 'users.db.old'");
}
}
+
+#nullable disable
+ internal class UserMockup
+ {
+ public string Password { get; set; }
+
+ public string EasyPassword { get; set; }
+
+ public DateTime? LastLoginDate { get; set; }
+
+ public DateTime? LastActivityDate { get; set; }
+
+ public string Name { get; set; }
+
+ public ItemImageInfo[] ImageInfos { get; set; }
+ }
}
diff --git a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs
index c6471b24c8..8b4abdfe59 100644
--- a/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs
+++ b/Jellyfin.Server/Migrations/Routines/MoveExtractedFiles.cs
@@ -24,7 +24,7 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to move extracted files to the new directories.
///
-[JellyfinMigration("2025-04-20T21:00:00", nameof(MoveExtractedFiles), "9063b0Ef-CFF1-4EDC-9A13-74093681A89B")]
+[JellyfinMigration("2025-04-20T21:00:00", nameof(MoveExtractedFiles))]
#pragma warning disable CS0618 // Type or member is obsolete
public class MoveExtractedFiles : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
diff --git a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs b/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs
index 6077080439..63b0614fd4 100644
--- a/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs
+++ b/Jellyfin.Server/Migrations/Routines/MoveTrickplayFiles.cs
@@ -15,8 +15,8 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to move trickplay files to the new directory.
///
-[JellyfinMigration("2025-04-20T23:00:00", nameof(MoveTrickplayFiles), "9540D44A-D8DC-11EF-9CBB-B77274F77C52", RunMigrationOnSetup = true)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T23:00:00", nameof(MoveTrickplayFiles), RunMigrationOnSetup = true)]
public class MoveTrickplayFiles : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs
index 1ef1dd45fe..ebf4a2780e 100644
--- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs
+++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs
@@ -2,42 +2,41 @@ using System;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Updates;
-namespace Jellyfin.Server.Migrations.Routines
-{
- ///
- /// Migration to initialize system configuration with the default plugin repository.
- ///
- [JellyfinMigration("2025-04-20T11:00:00", nameof(ReaddDefaultPluginRepository), "5F86E7F6-D966-4C77-849D-7A7B40B68C4E", RunMigrationOnSetup = true)]
+namespace Jellyfin.Server.Migrations.Routines;
+
+///
+/// Migration to initialize system configuration with the default plugin repository.
+///
#pragma warning disable CS0618 // Type or member is obsolete
- public class ReaddDefaultPluginRepository : IMigrationRoutine
+[JellyfinMigration("2025-04-20T11:00:00", nameof(ReaddDefaultPluginRepository), "5F86E7F6-D966-4C77-849D-7A7B40B68C4E", RunMigrationOnSetup = true)]
+public class ReaddDefaultPluginRepository : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
+{
+ private readonly IServerConfigurationManager _serverConfigurationManager;
+
+ private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo
{
- private readonly IServerConfigurationManager _serverConfigurationManager;
+ Name = "Jellyfin Stable",
+ Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json"
+ };
- private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo
- {
- Name = "Jellyfin Stable",
- Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json"
- };
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ public ReaddDefaultPluginRepository(IServerConfigurationManager serverConfigurationManager)
+ {
+ _serverConfigurationManager = serverConfigurationManager;
+ }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Instance of the interface.
- public ReaddDefaultPluginRepository(IServerConfigurationManager serverConfigurationManager)
+ ///
+ public void Perform()
+ {
+ // Only add if repository list is empty
+ if (_serverConfigurationManager.Configuration.PluginRepositories.Length == 0)
{
- _serverConfigurationManager = serverConfigurationManager;
- }
-
- ///
- public void Perform()
- {
- // Only add if repository list is empty
- if (_serverConfigurationManager.Configuration.PluginRepositories.Length == 0)
- {
- _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo };
- _serverConfigurationManager.SaveConfiguration();
- }
+ _serverConfigurationManager.Configuration.PluginRepositories = new[] { _defaultRepositoryInfo };
+ _serverConfigurationManager.SaveConfiguration();
}
}
}
diff --git a/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs b/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs
index 9a95757a8c..b23a7dbc42 100644
--- a/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs
+++ b/Jellyfin.Server/Migrations/Routines/RefreshInternalDateModified.cs
@@ -19,7 +19,7 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to re-read creation dates for library items with internal metadata paths.
///
-[JellyfinMigration("2025-04-20T23:00:00", nameof(RefreshInternalDateModified), "32E762EB-4918-45CE-A44C-C801F66B877D", RunMigrationOnSetup = false)]
+[JellyfinMigration("2025-04-20T23:00:00", nameof(RefreshInternalDateModified))]
public class RefreshInternalDateModified : IDatabaseMigrationRoutine
{
private readonly ILogger _logger;
diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs
index 477363e0de..b626c473e3 100644
--- a/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs
+++ b/Jellyfin.Server/Migrations/Routines/RemoveDownloadImagesInAdvance.cs
@@ -3,44 +3,43 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using Microsoft.Extensions.Logging;
-namespace Jellyfin.Server.Migrations.Routines
-{
- ///
- /// Removes the old 'RemoveDownloadImagesInAdvance' from library options.
- ///
- [JellyfinMigration("2025-04-20T13:00:00", nameof(RemoveDownloadImagesInAdvance), "A81F75E0-8F43-416F-A5E8-516CCAB4D8CC")]
+namespace Jellyfin.Server.Migrations.Routines;
+
+///
+/// Removes the old 'RemoveDownloadImagesInAdvance' from library options.
+///
#pragma warning disable CS0618 // Type or member is obsolete
- internal class RemoveDownloadImagesInAdvance : IMigrationRoutine
+[JellyfinMigration("2025-04-20T13:00:00", nameof(RemoveDownloadImagesInAdvance), "A81F75E0-8F43-416F-A5E8-516CCAB4D8CC")]
+internal class RemoveDownloadImagesInAdvance : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
+{
+ private readonly ILogger _logger;
+ private readonly ILibraryManager _libraryManager;
+
+ public RemoveDownloadImagesInAdvance(ILogger logger, ILibraryManager libraryManager)
{
- private readonly ILogger _logger;
- private readonly ILibraryManager _libraryManager;
+ _logger = logger;
+ _libraryManager = libraryManager;
+ }
- public RemoveDownloadImagesInAdvance(ILogger logger, ILibraryManager libraryManager)
+ ///
+ public void Perform()
+ {
+ var virtualFolders = _libraryManager.GetVirtualFolders(false);
+ _logger.LogInformation("Removing 'RemoveDownloadImagesInAdvance' settings in all the libraries");
+ foreach (var virtualFolder in virtualFolders)
{
- _logger = logger;
- _libraryManager = libraryManager;
- }
-
- ///
- public void Perform()
- {
- var virtualFolders = _libraryManager.GetVirtualFolders(false);
- _logger.LogInformation("Removing 'RemoveDownloadImagesInAdvance' settings in all the libraries");
- foreach (var virtualFolder in virtualFolders)
+ // Some virtual folders don't have a proper item id.
+ if (!Guid.TryParse(virtualFolder.ItemId, out var folderId))
{
- // Some virtual folders don't have a proper item id.
- if (!Guid.TryParse(virtualFolder.ItemId, out var folderId))
- {
- continue;
- }
-
- var libraryOptions = virtualFolder.LibraryOptions;
- var collectionFolder = _libraryManager.GetItemById(folderId) ?? throw new InvalidOperationException("Failed to find CollectionFolder");
- // The property no longer exists in LibraryOptions, so we just re-save the options to get old data removed.
- collectionFolder.UpdateLibraryOptions(libraryOptions);
- _logger.LogInformation("Removed from '{VirtualFolder}'", virtualFolder.Name);
+ continue;
}
+
+ var libraryOptions = virtualFolder.LibraryOptions;
+ var collectionFolder = _libraryManager.GetItemById(folderId) ?? throw new InvalidOperationException("Failed to find CollectionFolder");
+ // The property no longer exists in LibraryOptions, so we just re-save the options to get old data removed.
+ collectionFolder.UpdateLibraryOptions(libraryOptions);
+ _logger.LogInformation("Removed from '{VirtualFolder}'", virtualFolder.Name);
}
}
}
diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs
index c80512deed..c9e66d0cfe 100644
--- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs
+++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicateExtras.cs
@@ -7,71 +7,70 @@ using MediaBrowser.Controller;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging;
-namespace Jellyfin.Server.Migrations.Routines
-{
- ///
- /// Remove duplicate entries which were caused by a bug where a file was considered to be an "Extra" to itself.
- ///
- [JellyfinMigration("2025-04-20T08:00:00", nameof(RemoveDuplicateExtras), "ACBE17B7-8435-4A83-8B64-6FCF162CB9BD")]
+namespace Jellyfin.Server.Migrations.Routines;
+
+///
+/// Remove duplicate entries which were caused by a bug where a file was considered to be an "Extra" to itself.
+///
#pragma warning disable CS0618 // Type or member is obsolete
- internal class RemoveDuplicateExtras : IMigrationRoutine
+[JellyfinMigration("2025-04-20T08:00:00", nameof(RemoveDuplicateExtras), "ACBE17B7-8435-4A83-8B64-6FCF162CB9BD")]
+internal class RemoveDuplicateExtras : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
+{
+ private const string DbFilename = "library.db";
+ private readonly ILogger _logger;
+ private readonly IServerApplicationPaths _paths;
+
+ public RemoveDuplicateExtras(ILogger logger, IServerApplicationPaths paths)
{
- private const string DbFilename = "library.db";
- private readonly ILogger _logger;
- private readonly IServerApplicationPaths _paths;
+ _logger = logger;
+ _paths = paths;
+ }
- public RemoveDuplicateExtras(ILogger logger, IServerApplicationPaths paths)
+ ///
+ public void Perform()
+ {
+ var dataPath = _paths.DataPath;
+ var dbPath = Path.Combine(dataPath, DbFilename);
+ using var connection = new SqliteConnection($"Filename={dbPath}");
+ connection.Open();
+ using (var transaction = connection.BeginTransaction())
{
- _logger = logger;
- _paths = paths;
- }
+ // Query the database for the ids of duplicate extras
+ var queryResult = connection.Query("SELECT t1.Path FROM TypedBaseItems AS t1, TypedBaseItems AS t2 WHERE t1.Path=t2.Path AND t1.Type!=t2.Type AND t1.Type='MediaBrowser.Controller.Entities.Video'");
+ var bads = string.Join(", ", queryResult.Select(x => x.GetString(0)));
- ///
- public void Perform()
- {
- var dataPath = _paths.DataPath;
- var dbPath = Path.Combine(dataPath, DbFilename);
- using var connection = new SqliteConnection($"Filename={dbPath}");
- connection.Open();
- using (var transaction = connection.BeginTransaction())
+ // Do nothing if no duplicate extras were detected
+ if (bads.Length == 0)
{
- // Query the database for the ids of duplicate extras
- var queryResult = connection.Query("SELECT t1.Path FROM TypedBaseItems AS t1, TypedBaseItems AS t2 WHERE t1.Path=t2.Path AND t1.Type!=t2.Type AND t1.Type='MediaBrowser.Controller.Entities.Video'");
- var bads = string.Join(", ", queryResult.Select(x => x.GetString(0)));
+ _logger.LogInformation("No duplicate extras detected, skipping migration.");
+ return;
+ }
- // Do nothing if no duplicate extras were detected
- if (bads.Length == 0)
+ // Back up the database before deleting any entries
+ for (int i = 1; ; i++)
+ {
+ var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i);
+ if (!File.Exists(bakPath))
{
- _logger.LogInformation("No duplicate extras detected, skipping migration.");
- return;
- }
-
- // Back up the database before deleting any entries
- for (int i = 1; ; i++)
- {
- var bakPath = string.Format(CultureInfo.InvariantCulture, "{0}.bak{1}", dbPath, i);
- if (!File.Exists(bakPath))
+ try
{
- try
- {
- File.Copy(dbPath, bakPath);
- _logger.LogInformation("Library database backed up to {BackupPath}", bakPath);
- break;
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath);
- throw;
- }
+ File.Copy(dbPath, bakPath);
+ _logger.LogInformation("Library database backed up to {BackupPath}", bakPath);
+ break;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Cannot make a backup of {Library} at path {BackupPath}", DbFilename, bakPath);
+ throw;
}
}
-
- // Delete all duplicate extras
- _logger.LogInformation("Removing found duplicated extras for the following items: {DuplicateExtras}", bads);
- connection.Execute("DELETE FROM TypedBaseItems WHERE rowid IN (SELECT t1.rowid FROM TypedBaseItems AS t1, TypedBaseItems AS t2 WHERE t1.Path=t2.Path AND t1.Type!=t2.Type AND t1.Type='MediaBrowser.Controller.Entities.Video')");
- transaction.Commit();
}
+
+ // Delete all duplicate extras
+ _logger.LogInformation("Removing found duplicated extras for the following items: {DuplicateExtras}", bads);
+ connection.Execute("DELETE FROM TypedBaseItems WHERE rowid IN (SELECT t1.rowid FROM TypedBaseItems AS t1, TypedBaseItems AS t2 WHERE t1.Path=t2.Path AND t1.Type!=t2.Type AND t1.Type='MediaBrowser.Controller.Entities.Video')");
+ transaction.Commit();
}
}
}
diff --git a/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs b/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
index ce2be2755c..23f212424b 100644
--- a/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
+++ b/Jellyfin.Server/Migrations/Routines/RemoveDuplicatePlaylistChildren.cs
@@ -11,8 +11,8 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Remove duplicate playlist entries.
///
-[JellyfinMigration("2025-04-20T19:00:00", nameof(RemoveDuplicatePlaylistChildren), "96C156A2-7A13-4B3B-A8B8-FB80C94D20C0")]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T19:00:00", nameof(RemoveDuplicatePlaylistChildren), "96C156A2-7A13-4B3B-A8B8-FB80C94D20C0")]
internal class RemoveDuplicatePlaylistChildren : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{
diff --git a/Jellyfin.Server/Migrations/Routines/UpdateDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/UpdateDefaultPluginRepository.cs
index cf3f5433b4..f58cf27413 100644
--- a/Jellyfin.Server/Migrations/Routines/UpdateDefaultPluginRepository.cs
+++ b/Jellyfin.Server/Migrations/Routines/UpdateDefaultPluginRepository.cs
@@ -6,8 +6,8 @@ namespace Jellyfin.Server.Migrations.Routines;
///
/// Migration to update the default Jellyfin plugin repository.
///
-[JellyfinMigration("2025-04-20T17:00:00", nameof(UpdateDefaultPluginRepository), "852816E0-2712-49A9-9240-C6FC5FCAD1A8", RunMigrationOnSetup = true)]
#pragma warning disable CS0618 // Type or member is obsolete
+[JellyfinMigration("2025-04-20T17:00:00", nameof(UpdateDefaultPluginRepository), "852816E0-2712-49A9-9240-C6FC5FCAD1A8", RunMigrationOnSetup = true)]
public class UpdateDefaultPluginRepository : IMigrationRoutine
#pragma warning restore CS0618 // Type or member is obsolete
{