|  | @@ -13,12 +13,14 @@ using System.Threading.Tasks;
 | 
	
		
			
				|  |  |  using CommandLine;
 | 
	
		
			
				|  |  |  using Emby.Drawing;
 | 
	
		
			
				|  |  |  using Emby.Server.Implementations;
 | 
	
		
			
				|  |  | +using Emby.Server.Implementations.HttpServer;
 | 
	
		
			
				|  |  |  using Emby.Server.Implementations.IO;
 | 
	
		
			
				|  |  |  using Emby.Server.Implementations.Networking;
 | 
	
		
			
				|  |  |  using Jellyfin.Drawing.Skia;
 | 
	
		
			
				|  |  |  using MediaBrowser.Common.Configuration;
 | 
	
		
			
				|  |  |  using MediaBrowser.Controller.Drawing;
 | 
	
		
			
				|  |  | -using MediaBrowser.Model.Globalization;
 | 
	
		
			
				|  |  | +using MediaBrowser.Controller.Extensions;
 | 
	
		
			
				|  |  | +using MediaBrowser.WebDashboard.Api;
 | 
	
		
			
				|  |  |  using Microsoft.AspNetCore.Hosting;
 | 
	
		
			
				|  |  |  using Microsoft.Extensions.Configuration;
 | 
	
		
			
				|  |  |  using Microsoft.Extensions.DependencyInjection;
 | 
	
	
		
			
				|  | @@ -112,9 +114,10 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |              // $JELLYFIN_LOG_DIR needs to be set for the logger configuration manager
 | 
	
		
			
				|  |  |              Environment.SetEnvironmentVariable("JELLYFIN_LOG_DIR", appPaths.LogDirectoryPath);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            // Create an instance of the application configuration to use for application startup
 | 
	
		
			
				|  |  |              await InitLoggingConfigFile(appPaths).ConfigureAwait(false);
 | 
	
		
			
				|  |  | -            IConfiguration startupConfig = CreateAppConfiguration(appPaths);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            // Create an instance of the application configuration to use for application startup
 | 
	
		
			
				|  |  | +            IConfiguration startupConfig = CreateAppConfiguration(options, appPaths);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              // Initialize logging framework
 | 
	
		
			
				|  |  |              InitializeLoggingFramework(startupConfig, appPaths);
 | 
	
	
		
			
				|  | @@ -183,15 +186,31 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |                  new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
 | 
	
		
			
				|  |  |                  GetImageEncoder(appPaths),
 | 
	
		
			
				|  |  |                  new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              try
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  | +                // If hosting the web client, validate the client content path
 | 
	
		
			
				|  |  | +                if (startupConfig.HostWebClient())
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    string webContentPath = DashboardService.GetDashboardUIPath(startupConfig, appHost.ServerConfigurationManager);
 | 
	
		
			
				|  |  | +                    if (!Directory.Exists(webContentPath) || Directory.GetFiles(webContentPath).Length == 0)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        throw new InvalidOperationException(
 | 
	
		
			
				|  |  | +                            "The server is expected to host the web client, but the provided content directory is either " +
 | 
	
		
			
				|  |  | +                            $"invalid or empty: {webContentPath}. If you do not want to host the web client with the " +
 | 
	
		
			
				|  |  | +                            "server, you may set the '--nowebclient' command line flag, or set" +
 | 
	
		
			
				|  |  | +                            $"'{MediaBrowser.Controller.Extensions.ConfigurationExtensions.HostWebClientKey}=false' in your config settings.");
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                  ServiceCollection serviceCollection = new ServiceCollection();
 | 
	
		
			
				|  |  |                  await appHost.InitAsync(serviceCollection, startupConfig).ConfigureAwait(false);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                var webHost = CreateWebHostBuilder(appHost, serviceCollection, appPaths).Build();
 | 
	
		
			
				|  |  | +                var webHost = CreateWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                // A bit hacky to re-use service provider since ASP.NET doesn't allow a custom service collection.
 | 
	
		
			
				|  |  | +                // Re-use the web host service provider in the app host since ASP.NET doesn't allow a custom service collection.
 | 
	
		
			
				|  |  |                  appHost.ServiceProvider = webHost.Services;
 | 
	
		
			
				|  |  | +                appHost.InitializeServices();
 | 
	
		
			
				|  |  |                  appHost.FindParts();
 | 
	
		
			
				|  |  |                  Migrations.MigrationRunner.Run(appHost, _loggerFactory);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -233,7 +252,12 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static IWebHostBuilder CreateWebHostBuilder(ApplicationHost appHost, IServiceCollection serviceCollection, IApplicationPaths appPaths)
 | 
	
		
			
				|  |  | +        private static IWebHostBuilder CreateWebHostBuilder(
 | 
	
		
			
				|  |  | +            ApplicationHost appHost,
 | 
	
		
			
				|  |  | +            IServiceCollection serviceCollection,
 | 
	
		
			
				|  |  | +            StartupOptions commandLineOpts,
 | 
	
		
			
				|  |  | +            IConfiguration startupConfig,
 | 
	
		
			
				|  |  | +            IApplicationPaths appPaths)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              return new WebHostBuilder()
 | 
	
		
			
				|  |  |                  .UseKestrel(options =>
 | 
	
	
		
			
				|  | @@ -273,9 +297,8 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  })
 | 
	
		
			
				|  |  | -                .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(appPaths))
 | 
	
		
			
				|  |  | +                .ConfigureAppConfiguration(config => config.ConfigureAppConfiguration(commandLineOpts, appPaths, startupConfig))
 | 
	
		
			
				|  |  |                  .UseSerilog()
 | 
	
		
			
				|  |  | -                .UseContentRoot(appHost.ContentRoot)
 | 
	
		
			
				|  |  |                  .ConfigureServices(services =>
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  |                      // Merge the external ServiceCollection into ASP.NET DI
 | 
	
	
		
			
				|  | @@ -398,9 +421,8 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |              // webDir
 | 
	
		
			
				|  |  |              // IF      --webdir
 | 
	
		
			
				|  |  |              // ELSE IF $JELLYFIN_WEB_DIR
 | 
	
		
			
				|  |  | -            // ELSE    use <bindir>/jellyfin-web
 | 
	
		
			
				|  |  | +            // ELSE    <bindir>/jellyfin-web
 | 
	
		
			
				|  |  |              var webDir = options.WebDir;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |              if (string.IsNullOrEmpty(webDir))
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  webDir = Environment.GetEnvironmentVariable("JELLYFIN_WEB_DIR");
 | 
	
	
		
			
				|  | @@ -471,21 +493,33 @@ namespace Jellyfin.Server
 | 
	
		
			
				|  |  |              await resource.CopyToAsync(dst).ConfigureAwait(false);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static IConfiguration CreateAppConfiguration(IApplicationPaths appPaths)
 | 
	
		
			
				|  |  | +        private static IConfiguration CreateAppConfiguration(StartupOptions commandLineOpts, IApplicationPaths appPaths)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              return new ConfigurationBuilder()
 | 
	
		
			
				|  |  | -                .ConfigureAppConfiguration(appPaths)
 | 
	
		
			
				|  |  | +                .ConfigureAppConfiguration(commandLineOpts, appPaths)
 | 
	
		
			
				|  |  |                  .Build();
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static IConfigurationBuilder ConfigureAppConfiguration(this IConfigurationBuilder config, IApplicationPaths appPaths)
 | 
	
		
			
				|  |  | +        private static IConfigurationBuilder ConfigureAppConfiguration(
 | 
	
		
			
				|  |  | +            this IConfigurationBuilder config,
 | 
	
		
			
				|  |  | +            StartupOptions commandLineOpts,
 | 
	
		
			
				|  |  | +            IApplicationPaths appPaths,
 | 
	
		
			
				|  |  | +            IConfiguration? startupConfig = null)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | +            // Use the swagger API page as the default redirect path if not hosting the web client
 | 
	
		
			
				|  |  | +            var inMemoryDefaultConfig = ConfigurationOptions.DefaultConfiguration;
 | 
	
		
			
				|  |  | +            if (startupConfig != null && !startupConfig.HostWebClient())
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                inMemoryDefaultConfig[HttpListenerHost.DefaultRedirectKey] = "swagger/index.html";
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              return config
 | 
	
		
			
				|  |  |                  .SetBasePath(appPaths.ConfigurationDirectoryPath)
 | 
	
		
			
				|  |  | -                .AddInMemoryCollection(ConfigurationOptions.Configuration)
 | 
	
		
			
				|  |  | +                .AddInMemoryCollection(inMemoryDefaultConfig)
 | 
	
		
			
				|  |  |                  .AddJsonFile(LoggingConfigFileDefault, optional: false, reloadOnChange: true)
 | 
	
		
			
				|  |  |                  .AddJsonFile(LoggingConfigFileSystem, optional: true, reloadOnChange: true)
 | 
	
		
			
				|  |  | -                .AddEnvironmentVariables("JELLYFIN_");
 | 
	
		
			
				|  |  | +                .AddEnvironmentVariables("JELLYFIN_")
 | 
	
		
			
				|  |  | +                .AddInMemoryCollection(commandLineOpts.ConvertToConfig());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          /// <summary>
 |