diff options
| author | JPVenson <github@jpb.email> | 2026-03-01 13:10:32 +0000 |
|---|---|---|
| committer | JPVenson <github@jpb.email> | 2026-03-01 13:10:32 +0000 |
| commit | e70eaf8bc1470436fdafb7fef6e23898b4a3423b (patch) | |
| tree | 1225e94b022dae4248b8af2f850ab35c185ecc14 | |
| parent | f680495ca377b20488cc8133a054317d6daf48fc (diff) | |
Add startup mode to migrate or seed the database on cmd
| -rw-r--r-- | Jellyfin.Server/Configuration/StartupMode.cs | 24 | ||||
| -rw-r--r-- | Jellyfin.Server/Migrations/JellyfinMigrationService.cs | 6 | ||||
| -rw-r--r-- | Jellyfin.Server/Program.cs | 28 | ||||
| -rw-r--r-- | Jellyfin.Server/StartupOptions.cs | 8 | ||||
| -rw-r--r-- | tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs | 2 |
5 files changed, 54 insertions, 14 deletions
diff --git a/Jellyfin.Server/Configuration/StartupMode.cs b/Jellyfin.Server/Configuration/StartupMode.cs new file mode 100644 index 0000000000..f4d63652d8 --- /dev/null +++ b/Jellyfin.Server/Configuration/StartupMode.cs @@ -0,0 +1,24 @@ +using MediaBrowser.Model.Configuration; + +namespace Jellyfin.Server.Configuration; + +/// <summary> +/// Defines types for usage with the <see cref="StartupOptions.StartupMode"/>. +/// </summary> +public enum StartupMode +{ + /// <summary> + /// Default startup mode, runs the jellyfin server in normal operation. + /// </summary> + MediaServer = 0, + + /// <summary> + /// Attempts to Migrate the selected database only then shuts down. + /// </summary> + MigrateDatabase = 1, + + /// <summary> + /// Runs the Database seed function regardless of <see cref="BaseApplicationConfiguration.IsStartupWizardCompleted"/> state. + /// </summary> + SeedDatabase = 2 +} diff --git a/Jellyfin.Server/Migrations/JellyfinMigrationService.cs b/Jellyfin.Server/Migrations/JellyfinMigrationService.cs index 188d3c4a9a..9d70ef1208 100644 --- a/Jellyfin.Server/Migrations/JellyfinMigrationService.cs +++ b/Jellyfin.Server/Migrations/JellyfinMigrationService.cs @@ -90,7 +90,7 @@ internal class JellyfinMigrationService private HashSet<MigrationStage> Migrations { get; set; } - public async Task CheckFirstTimeRunOrMigration(IApplicationPaths appPaths) + public async Task CheckFirstTimeRunOrMigration(IApplicationPaths appPaths, StartupOptions startupOptions) { var logger = _startupLogger.With(_loggerFactory.CreateLogger<JellyfinMigrationService>()).BeginGroup($"Migration Startup"); logger.LogInformation("Initialise Migration service."); @@ -98,9 +98,9 @@ internal class JellyfinMigrationService var serverConfig = File.Exists(appPaths.SystemConfigurationFilePath) ? (ServerConfiguration)xmlSerializer.DeserializeFromFile(typeof(ServerConfiguration), appPaths.SystemConfigurationFilePath)! : new ServerConfiguration(); - if (!serverConfig.IsStartupWizardCompleted) + if (!serverConfig.IsStartupWizardCompleted || startupOptions.StartupMode is Configuration.StartupMode.SeedDatabase) { - logger.LogInformation("System initialisation detected. Seed data."); + logger.LogInformation("System initialization detected. Seed data. Startup mode is: {StartupMode}", startupOptions.StartupMode ?? Configuration.StartupMode.MediaServer); var flatApplyMigrations = Migrations.SelectMany(e => e.Where(f => !f.Metadata.RunMigrationOnSetup)).ToArray(); var dbContext = await _dbContextFactory.CreateDbContextAsync().ConfigureAwait(false); diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 93f71fdc69..e774c16510 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -137,7 +137,7 @@ namespace Jellyfin.Server StartupHelpers.PerformStaticInitialization(); - await ApplyStartupMigrationAsync(appPaths, startupConfig).ConfigureAwait(false); + await ApplyStartupMigrationAsync(appPaths, startupConfig, options).ConfigureAwait(false); do { @@ -214,13 +214,17 @@ namespace Jellyfin.Server { configurationCompleted = true; await _setupServer!.StopAsync().ConfigureAwait(false); - await _jellyfinHost.StartAsync().ConfigureAwait(false); - if (!OperatingSystem.IsWindows() && startupConfig.UseUnixSocket()) + if (options.StartupMode is null or Configuration.StartupMode.MediaServer) { - var socketPath = StartupHelpers.GetUnixSocketPath(startupConfig, appPaths); + await _jellyfinHost.StartAsync().ConfigureAwait(false); - StartupHelpers.SetUnixSocketPermissions(startupConfig, socketPath, _logger); + if (!OperatingSystem.IsWindows() && startupConfig.UseUnixSocket()) + { + var socketPath = StartupHelpers.GetUnixSocketPath(startupConfig, appPaths); + + StartupHelpers.SetUnixSocketPermissions(startupConfig, socketPath, _logger); + } } } catch (Exception) @@ -229,11 +233,14 @@ namespace Jellyfin.Server throw; } - await appHost.RunStartupTasksAsync().ConfigureAwait(false); + if (options.StartupMode is null or Configuration.StartupMode.MediaServer) + { + await appHost.RunStartupTasksAsync().ConfigureAwait(false); + _logger.LogInformation("Startup complete {Time:g}", Stopwatch.GetElapsedTime(_startTimestamp)); - _logger.LogInformation("Startup complete {Time:g}", Stopwatch.GetElapsedTime(_startTimestamp)); + await _jellyfinHost.WaitForShutdownAsync().ConfigureAwait(false); + } - await _jellyfinHost.WaitForShutdownAsync().ConfigureAwait(false); _restartOnShutdown = appHost.ShouldRestart; _restoreFromBackup = appHost.RestoreBackupPath; } @@ -274,8 +281,9 @@ namespace Jellyfin.Server /// </remarks> /// <param name="appPaths">Application Paths.</param> /// <param name="startupConfig">Startup Config.</param> + /// <param name="startupOptions">The applications startup options.</param> /// <returns>A task.</returns> - public static async Task ApplyStartupMigrationAsync(ServerApplicationPaths appPaths, IConfiguration startupConfig) + public static async Task ApplyStartupMigrationAsync(ServerApplicationPaths appPaths, IConfiguration startupConfig, StartupOptions startupOptions) { _migrationLogger = StartupLogger.Logger.BeginGroup<JellyfinMigrationService>($"Migration Service"); var startupConfigurationManager = new ServerConfigurationManager(appPaths, _loggerFactory, new MyXmlSerializer()); @@ -293,7 +301,7 @@ namespace Jellyfin.Server PrepareDatabaseProvider(startupService); var jellyfinMigrationService = ActivatorUtilities.CreateInstance<JellyfinMigrationService>(startupService); - await jellyfinMigrationService.CheckFirstTimeRunOrMigration(appPaths).ConfigureAwait(false); + await jellyfinMigrationService.CheckFirstTimeRunOrMigration(appPaths, startupOptions).ConfigureAwait(false); await jellyfinMigrationService.MigrateStepAsync(Migrations.Stages.JellyfinMigrationStageTypes.PreInitialisation, startupService).ConfigureAwait(false); } diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index 4890ccbb2e..4716bc1746 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using CommandLine; using Emby.Server.Implementations; +using Jellyfin.Server.Configuration; using static MediaBrowser.Controller.Extensions.ConfigurationExtensions; namespace Jellyfin.Server @@ -80,6 +81,13 @@ namespace Jellyfin.Server public string? RestoreArchive { get; set; } /// <summary> + /// Gets or sets the mode of operation the server should perform when started. + /// Defaults to: <see cref="StartupMode.MediaServer"/>. + /// </summary> + [Option("mode", Required = false, HelpText = "Mode which selects what action the jellyfin server should perform when started.")] + public StartupMode? StartupMode { get; set; } + + /// <summary> /// Gets the command line options as a dictionary that can be used in the .NET configuration system. /// </summary> /// <returns>The configuration dictionary.</returns> diff --git a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs index 0952fb8b63..54f443de2d 100644 --- a/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs +++ b/tests/Jellyfin.Server.Integration.Tests/JellyfinApplicationFactory.cs @@ -111,7 +111,7 @@ namespace Jellyfin.Server.Integration.Tests var appHost = (TestAppHost)host.Services.GetRequiredService<IApplicationHost>(); appHost.ServiceProvider = host.Services; var applicationPaths = appHost.ServiceProvider.GetRequiredService<IApplicationPaths>(); - Program.ApplyStartupMigrationAsync((ServerApplicationPaths)applicationPaths, appHost.ServiceProvider.GetRequiredService<IConfiguration>()).GetAwaiter().GetResult(); + Program.ApplyStartupMigrationAsync((ServerApplicationPaths)applicationPaths, appHost.ServiceProvider.GetRequiredService<IConfiguration>(), new()).GetAwaiter().GetResult(); Program.ApplyCoreMigrationsAsync(appHost.ServiceProvider, Migrations.Stages.JellyfinMigrationStageTypes.CoreInitialisation).GetAwaiter().GetResult(); appHost.InitializeServices(Mock.Of<IConfiguration>()).GetAwaiter().GetResult(); Program.ApplyCoreMigrationsAsync(appHost.ServiceProvider, Migrations.Stages.JellyfinMigrationStageTypes.AppInitialisation).GetAwaiter().GetResult(); |
