Add startup mode to migrate or seed the database on cmd

This commit is contained in:
JPVenson 2026-03-01 13:10:32 +00:00
parent f680495ca3
commit e70eaf8bc1
No known key found for this signature in database
GPG key ID: DDAEFD5596EEC477
5 changed files with 54 additions and 14 deletions

View file

@ -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
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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
@ -79,6 +80,13 @@ namespace Jellyfin.Server
[Option("restore-archive", Required = false, HelpText = "Path to a Jellyfin backup archive to restore from")]
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>

View file

@ -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();