diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs index 8e3ea475..085fc2dd 100644 --- a/Kyoo.Authentication/AuthenticationModule.cs +++ b/Kyoo.Authentication/AuthenticationModule.cs @@ -9,7 +9,6 @@ using IdentityServer4.Services; using Kyoo.Authentication.Models; using Kyoo.Authentication.Views; using Kyoo.Controllers; -using Kyoo.Models.Attributes; using Kyoo.Models.Permissions; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -38,6 +37,12 @@ namespace Kyoo.Authentication /// public string Description => "Enable OpenID authentication for Kyoo."; + /// + public Dictionary Configuration => new() + { + { AuthenticationOption.Path, typeof(AuthenticationOption) } + }; + /// /// The configuration to use. @@ -53,11 +58,6 @@ namespace Kyoo.Authentication /// The environment information to check if the app runs in debug mode /// private readonly IWebHostEnvironment _environment; - - /// - /// The configuration manager used to register typed/untyped implementations. - /// - [Injected] public IConfigurationManager ConfigurationManager { private get; set; } /// @@ -88,10 +88,6 @@ namespace Kyoo.Authentication // TODO handle direct-videos with bearers (probably add a cookie and a app.Use to translate that for videos) // TODO Check if tokens should be stored. - - services.Configure(_configuration.GetSection(PermissionOption.Path)); - services.Configure(_configuration.GetSection(CertificateOption.Path)); - services.Configure(_configuration.GetSection(AuthenticationOption.Path)); List clients = new(); _configuration.GetSection("authentication:clients").Bind(clients); @@ -129,37 +125,43 @@ namespace Kyoo.Authentication } /// - public void ConfigureAspNet(IApplicationBuilder app) + public IEnumerable ConfigureSteps => new IStartupAction[] { - ConfigurationManager.AddTyped(AuthenticationOption.Path); - - app.UseCookiePolicy(new CookiePolicyOptions + SA.New(app => { - MinimumSameSitePolicy = SameSiteMode.Strict - }); - app.UseAuthentication(); - app.Use((ctx, next) => + PhysicalFileProvider provider = new(Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, + "login")); + app.UseDefaultFiles(new DefaultFilesOptions + { + RequestPath = new PathString("/login"), + FileProvider = provider, + RedirectToAppendTrailingSlash = true + }); + app.UseStaticFiles(new StaticFileOptions + { + RequestPath = new PathString("/login"), + FileProvider = provider + }); + }, SA.StaticFiles), + SA.New(app => { - ctx.SetIdentityServerOrigin(_configuration.GetPublicUrl()); - return next(); - }); - app.UseIdentityServer(); - app.UseAuthorization(); - - PhysicalFileProvider provider = new(Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, - "login")); - app.UseDefaultFiles(new DefaultFilesOptions + app.UseCookiePolicy(new CookiePolicyOptions + { + MinimumSameSitePolicy = SameSiteMode.Strict + }); + app.UseAuthentication(); + }, SA.Authentication), + SA.New(app => { - RequestPath = new PathString("/login"), - FileProvider = provider, - RedirectToAppendTrailingSlash = true - }); - app.UseStaticFiles(new StaticFileOptions - { - RequestPath = new PathString("/login"), - FileProvider = provider - }); - } + app.Use((ctx, next) => + { + ctx.SetIdentityServerOrigin(_configuration.GetPublicUrl()); + return next(); + }); + app.UseIdentityServer(); + }, SA.Endpoint), + SA.New(app => app.UseAuthorization(), SA.Authorization) + }; } } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs index 06670ff3..817435f1 100644 --- a/Kyoo.Common/Controllers/IPlugin.cs +++ b/Kyoo.Common/Controllers/IPlugin.cs @@ -1,7 +1,7 @@ using System; +using System.Collections.Generic; using Autofac; using JetBrains.Annotations; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Controllers @@ -41,8 +41,26 @@ namespace Kyoo.Controllers /// By default, a plugin is always enabled. This method can be overriden to change this behavior. /// virtual bool Enabled => true; + + /// + /// A list of types that will be available via the IOptions interfaces and will be listed inside + /// an IConfiguration. If a field should be loosely typed, or null + /// can be specified. + /// + /// + /// All use of the configuration must be specified here and not registered elsewhere, if a type is registered + /// elsewhere the configuration won't be editable via the and all values + /// will be discarded on edit. + /// + Dictionary Configuration { get; } /// + /// An optional configuration step to allow a plugin to change asp net configurations. + /// + /// + virtual IEnumerable ConfigureSteps => ArraySegment.Empty; + + /// /// A configure method that will be run on plugin's startup. /// /// The autofac service container to register services. @@ -61,20 +79,6 @@ namespace Kyoo.Controllers { // Skipped } - - - /// - /// An optional configuration step to allow a plugin to change asp net configurations. - /// WARNING: This is only called on Kyoo's startup so you must restart the app to apply this changes. - /// - /// - /// The Asp.Net application builder. On most case it is not needed but you can use it to - /// add asp net functionalities. - /// - void ConfigureAspNet(IApplicationBuilder app) - { - // Skipped - } /// /// An optional function to execute and initialize your plugin. diff --git a/Kyoo.Common/Controllers/IPluginManager.cs b/Kyoo.Common/Controllers/IPluginManager.cs index de439cc2..294aabb2 100644 --- a/Kyoo.Common/Controllers/IPluginManager.cs +++ b/Kyoo.Common/Controllers/IPluginManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using Autofac; using Kyoo.Models.Exceptions; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Controllers @@ -63,11 +62,5 @@ namespace Kyoo.Controllers /// /// The service collection to populate public void ConfigureServices(IServiceCollection services); - - /// - /// Configure an asp net application applying plugins policies. - /// - /// The asp net application to configure - public void ConfigureAspnet(IApplicationBuilder app); } } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/ITask.cs b/Kyoo.Common/Controllers/ITask.cs index 4d764fc7..0810b6bf 100644 --- a/Kyoo.Common/Controllers/ITask.cs +++ b/Kyoo.Common/Controllers/ITask.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using Kyoo.Models; -using Kyoo.Models.Attributes; using Kyoo.Models.Exceptions; namespace Kyoo.Controllers @@ -182,11 +181,6 @@ namespace Kyoo.Controllers /// A token to request the task's cancellation. /// If this task is not cancelled quickly, it might be killed by the runner. /// - /// - /// Your task can have any service as a public field and use the , - /// they will be set to an available service from the service container before calling this method. - /// They also will be removed after this method return (or throw) to prevent dangling services. - /// /// /// An exception meaning that the task has failed for handled reasons like invalid arguments, /// invalid environment, missing plugins or failures not related to a default in the code. diff --git a/Kyoo.Common/Controllers/StartupAction.cs b/Kyoo.Common/Controllers/StartupAction.cs new file mode 100644 index 00000000..3d9891a0 --- /dev/null +++ b/Kyoo.Common/Controllers/StartupAction.cs @@ -0,0 +1,221 @@ +using System; +using Microsoft.Extensions.DependencyInjection; + +namespace Kyoo.Controllers +{ + /// + /// A list of constant priorities used for 's . + /// It also contains helper methods for creating new . + /// + public static class SA + { + public const int Before = 5000; + public const int Routing = 4000; + public const int StaticFiles = 3000; + public const int Authentication = 2000; + public const int Authorization = 1000; + public const int Endpoint = 0; + public const int After = -1000; + + /// + /// Create a new . + /// + /// The action to run + /// The priority of the new action + /// A new + public static StartupAction New(Action action, int priority) + => new(action, priority); + + /// + /// Create a new . + /// + /// The action to run + /// The priority of the new action + /// A dependency that this action will use. + /// A new + public static StartupAction New(Action action, int priority) + => new(action, priority); + + /// + /// Create a new . + /// + /// The action to run + /// The priority of the new action + /// A dependency that this action will use. + /// A second dependency that this action will use. + /// A new + public static StartupAction New(Action action, int priority) + => new(action, priority); + + /// + /// Create a new . + /// + /// The action to run + /// The priority of the new action + /// A dependency that this action will use. + /// A second dependency that this action will use. + /// A third dependency that this action will use. + /// A new + public static StartupAction New(Action action, int priority) + => new(action, priority); + } + + + /// + /// An action executed on kyoo's startup to initialize the asp-net container. + /// + /// + /// This is the base interface, see for a simpler use of this. + /// + public interface IStartupAction + { + /// + /// The priority of this action. The actions will be executed on descending priority order. + /// If two actions have the same priority, their order is undefined. + /// + int Priority { get; } + + /// + /// Run this action to configure the container, a service provider containing all services can be used. + /// + /// The service provider containing all services can be used. + void Run(IServiceProvider provider); + } + + /// + /// A with no dependencies. + /// + public class StartupAction : IStartupAction + { + /// + /// The action to execute at startup. + /// + private readonly Action _action; + + /// + public int Priority { get; } + + /// + /// Create a new . + /// + /// The action to execute on startup. + /// The priority of this action (see ). + public StartupAction(Action action, int priority) + { + _action = action; + Priority = priority; + } + + /// + public void Run(IServiceProvider provider) + { + _action.Invoke(); + } + } + + /// + /// A with one dependencies. + /// + /// The dependency to use. + public class StartupAction : IStartupAction + { + /// + /// The action to execute at startup. + /// + private readonly Action _action; + + /// + public int Priority { get; } + + /// + /// Create a new . + /// + /// The action to execute on startup. + /// The priority of this action (see ). + public StartupAction(Action action, int priority) + { + _action = action; + Priority = priority; + } + + /// + public void Run(IServiceProvider provider) + { + _action.Invoke(provider.GetRequiredService()); + } + } + + /// + /// A with two dependencies. + /// + /// The dependency to use. + /// The second dependency to use. + public class StartupAction : IStartupAction + { + /// + /// The action to execute at startup. + /// + private readonly Action _action; + + /// + public int Priority { get; } + + /// + /// Create a new . + /// + /// The action to execute on startup. + /// The priority of this action (see ). + public StartupAction(Action action, int priority) + { + _action = action; + Priority = priority; + } + + /// + public void Run(IServiceProvider provider) + { + _action.Invoke( + provider.GetRequiredService(), + provider.GetRequiredService() + ); + } + } + + /// + /// A with three dependencies. + /// + /// The dependency to use. + /// The second dependency to use. + /// The third dependency to use. + public class StartupAction : IStartupAction + { + /// + /// The action to execute at startup. + /// + private readonly Action _action; + + /// + public int Priority { get; } + + /// + /// Create a new . + /// + /// The action to execute on startup. + /// The priority of this action (see ). + public StartupAction(Action action, int priority) + { + _action = action; + Priority = priority; + } + + /// + public void Run(IServiceProvider provider) + { + _action.Invoke( + provider.GetRequiredService(), + provider.GetRequiredService(), + provider.GetRequiredService() + ); + } + } +} \ No newline at end of file diff --git a/Kyoo.Common/Models/Attributes/InjectedAttribute.cs b/Kyoo.Common/Models/Attributes/InjectedAttribute.cs deleted file mode 100644 index d517300f..00000000 --- a/Kyoo.Common/Models/Attributes/InjectedAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using JetBrains.Annotations; -using Kyoo.Controllers; - -namespace Kyoo.Models.Attributes -{ - /// - /// An attribute to inform that the service will be injected automatically by a service provider. - /// - /// - /// It should only be used on and it will be injected before - /// calling . - /// - [AttributeUsage(AttributeTargets.Property)] - [MeansImplicitUse(ImplicitUseKindFlags.Assign)] - public class InjectedAttribute : Attribute { } -} \ No newline at end of file diff --git a/Kyoo.Postgresql/PostgresModule.cs b/Kyoo.Postgresql/PostgresModule.cs index bbebf946..372d3e86 100644 --- a/Kyoo.Postgresql/PostgresModule.cs +++ b/Kyoo.Postgresql/PostgresModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -22,6 +23,9 @@ namespace Kyoo.Postgresql /// public string Description => "A database context for postgresql."; + + /// + public Dictionary Configuration => new(); /// public bool Enabled => _configuration.GetSelectedDatabase() == "postgres"; diff --git a/Kyoo.SqLite/SqLiteModule.cs b/Kyoo.SqLite/SqLiteModule.cs index 45dca0f2..e1c05632 100644 --- a/Kyoo.SqLite/SqLiteModule.cs +++ b/Kyoo.SqLite/SqLiteModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; @@ -22,6 +23,9 @@ namespace Kyoo.SqLite /// public string Description => "A database context for sqlite."; + /// + public Dictionary Configuration => new(); + /// public bool Enabled => _configuration.GetSelectedDatabase() == "sqlite"; diff --git a/Kyoo.TheMovieDb/PluginTmdb.cs b/Kyoo.TheMovieDb/PluginTmdb.cs index c1d6d494..21990d3c 100644 --- a/Kyoo.TheMovieDb/PluginTmdb.cs +++ b/Kyoo.TheMovieDb/PluginTmdb.cs @@ -1,10 +1,8 @@ +using System; +using System.Collections.Generic; using Autofac; using Kyoo.Controllers; -using Kyoo.Models.Attributes; using Kyoo.TheMovieDb.Models; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; namespace Kyoo.TheMovieDb { @@ -21,45 +19,17 @@ namespace Kyoo.TheMovieDb /// public string Description => "A metadata provider for TheMovieDB."; - - - /// - /// The configuration to use. - /// - private readonly IConfiguration _configuration; - /// - /// The configuration manager used to register typed/untyped implementations. - /// - [Injected] public IConfigurationManager ConfigurationManager { private get; set; } - - - /// - /// Create a new tmdb module instance and use the given configuration. - /// - /// The configuration to use - public PluginTmdb(IConfiguration configuration) + /// + public Dictionary Configuration => new() { - _configuration = configuration; - } - - + { TheMovieDbOptions.Path, typeof(TheMovieDbOptions) } + }; + /// public void Configure(ContainerBuilder builder) { builder.RegisterProvider(); } - - /// - public void Configure(IServiceCollection services) - { - services.Configure(_configuration.GetSection(TheMovieDbOptions.Path)); - } - - /// - public void ConfigureAspNet(IApplicationBuilder app) - { - ConfigurationManager.AddTyped(TheMovieDbOptions.Path); - } } } \ No newline at end of file diff --git a/Kyoo.TheTvdb/PluginTvdb.cs b/Kyoo.TheTvdb/PluginTvdb.cs index 74f9483d..2b598807 100644 --- a/Kyoo.TheTvdb/PluginTvdb.cs +++ b/Kyoo.TheTvdb/PluginTvdb.cs @@ -1,10 +1,8 @@ +using System; +using System.Collections.Generic; using Autofac; using Kyoo.Controllers; -using Kyoo.Models.Attributes; using Kyoo.TheTvdb.Models; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; using TvDbSharper; namespace Kyoo.TheTvdb @@ -23,44 +21,17 @@ namespace Kyoo.TheTvdb /// public string Description => "A metadata provider for The TVDB."; - /// - /// The configuration to use. - /// - private readonly IConfiguration _configuration; - - /// - /// The configuration manager used to register typed/untyped implementations. - /// - [Injected] public IConfigurationManager ConfigurationManager { private get; set; } - - - /// - /// Create a new tvdb module instance and use the given configuration. - /// - /// The configuration to use - public PluginTvdb(IConfiguration configuration) + /// + public Dictionary Configuration => new() { - _configuration = configuration; - } - - + { TvdbOption.Path, typeof(TvdbOption) } + }; + /// public void Configure(ContainerBuilder builder) { builder.RegisterType().As(); builder.RegisterProvider(); } - - /// - public void Configure(IServiceCollection services) - { - services.Configure(_configuration.GetSection(TvdbOption.Path)); - } - - /// - public void ConfigureAspNet(IApplicationBuilder app) - { - ConfigurationManager.AddTyped(TvdbOption.Path); - } } } \ No newline at end of file diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index f4d91b81..04dacccc 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -6,7 +6,6 @@ using System.Reflection; using System.Runtime.Loader; using Autofac; using Kyoo.Models.Options; -using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -148,18 +147,6 @@ namespace Kyoo.Controllers plugin.Configure(services); } - /// - public void ConfigureAspnet(IApplicationBuilder app) - { - foreach (IPlugin plugin in _plugins) - { - using IServiceScope scope = _provider.CreateScope(); - Helper.InjectServices(plugin, x => scope.ServiceProvider.GetRequiredService(x)); - plugin.ConfigureAspNet(app); - Helper.InjectServices(plugin, _ => null); - } - } - /// /// A custom to load plugin's dependency if they are on the same folder. /// diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs index 5fe9e977..6c049aee 100644 --- a/Kyoo/CoreModule.cs +++ b/Kyoo/CoreModule.cs @@ -1,10 +1,10 @@ using System; +using System.Collections.Generic; using System.IO; using Autofac; using Autofac.Core; using Autofac.Core.Registration; using Kyoo.Controllers; -using Kyoo.Models.Attributes; using Kyoo.Models.Options; using Kyoo.Models.Permissions; using Kyoo.Tasks; @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; +using Microsoft.Extensions.Hosting; namespace Kyoo { @@ -30,18 +31,23 @@ namespace Kyoo /// public string Description => "The core module containing default implementations."; + /// + public Dictionary Configuration => new() + { + { BasicOptions.Path, typeof(BasicOptions) }, + { TaskOptions.Path, typeof(TaskOptions) }, + { MediaOptions.Path, typeof(MediaOptions) }, + { "database", null }, + { "logging", null } + }; + /// /// The configuration to use. /// private readonly IConfiguration _configuration; - - /// - /// The configuration manager used to register typed/untyped implementations. - /// - [Injected] public IConfigurationManager ConfigurationManager { private get; set; } - + /// /// Create a new core module instance and use the given configuration. /// @@ -99,10 +105,6 @@ namespace Kyoo { string publicUrl = _configuration.GetPublicUrl(); - services.Configure(_configuration.GetSection(BasicOptions.Path)); - services.Configure(_configuration.GetSection(TaskOptions.Path)); - services.Configure(_configuration.GetSection(MediaOptions.Path)); - services.AddControllers() .AddNewtonsoftJson(x => { @@ -114,26 +116,30 @@ namespace Kyoo } /// - public void ConfigureAspNet(IApplicationBuilder app) + public IEnumerable ConfigureSteps => new IStartupAction[] { - ConfigurationManager.AddTyped(BasicOptions.Path); - ConfigurationManager.AddTyped(TaskOptions.Path); - ConfigurationManager.AddTyped(MediaOptions.Path); - ConfigurationManager.AddUntyped("database"); - ConfigurationManager.AddUntyped("logging"); - - FileExtensionContentTypeProvider contentTypeProvider = new(); - contentTypeProvider.Mappings[".data"] = "application/octet-stream"; - app.UseStaticFiles(new StaticFileOptions + SA.New((app, env) => { - ContentTypeProvider = contentTypeProvider, - FileProvider = new PhysicalFileProvider(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot")) - }); - - app.UseEndpoints(endpoints => + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + else + { + app.UseExceptionHandler("/error"); + app.UseHsts(); + } + }, SA.Before), + SA.New(app => app.UseRouting(), SA.Routing), + SA.New(app => { - endpoints.MapControllers(); - }); - } + FileExtensionContentTypeProvider contentTypeProvider = new(); + contentTypeProvider.Mappings[".data"] = "application/octet-stream"; + app.UseStaticFiles(new StaticFileOptions + { + ContentTypeProvider = contentTypeProvider, + FileProvider = new PhysicalFileProvider(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot")) + }); + }, SA.StaticFiles), + SA.New(app => app.UseEndpoints(x => x.MapControllers()), SA.Endpoint) + }; } } \ No newline at end of file diff --git a/Kyoo/Helper.cs b/Kyoo/Helper.cs index 244f6eec..ad8a6dfb 100644 --- a/Kyoo/Helper.cs +++ b/Kyoo/Helper.cs @@ -1,32 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Reflection; using System.Threading.Tasks; -using JetBrains.Annotations; -using Kyoo.Models.Attributes; using Newtonsoft.Json; namespace Kyoo { public static class Helper { - /// - /// Inject services into the marked properties of the given object. - /// - /// The object to inject - /// The function used to retrieve services. (The function is called immediately) - public static void InjectServices(object obj, [InstantHandle] Func retrieve) - { - IEnumerable properties = obj.GetType().GetProperties() - .Where(x => x.GetCustomAttribute() != null) - .Where(x => x.CanWrite); - - foreach (PropertyInfo property in properties) - property.SetValue(obj, retrieve(property.PropertyType)); - } - /// /// An helper method to get json content from an http server. This is a temporary thing and will probably be /// replaced by a call to the function of the same name in the System.Net.Http.Json namespace when .net6 diff --git a/Kyoo/PluginsStartup.cs b/Kyoo/PluginsStartup.cs index e279cb57..33305f6e 100644 --- a/Kyoo/PluginsStartup.cs +++ b/Kyoo/PluginsStartup.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Autofac; using Autofac.Extras.AttributeMetadata; using Kyoo.Authentication; @@ -90,18 +91,9 @@ namespace Kyoo /// The host environment (is the app in development mode?) public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider) { - if (env.IsDevelopment()) - app.UseDeveloperExceptionPage(); - else - { - app.UseExceptionHandler("/error"); - app.UseHsts(); - } - if (!env.IsDevelopment()) app.UseSpaStaticFiles(); - - app.UseRouting(); + app.Use((ctx, next) => { ctx.Response.Headers.Remove("X-Powered-By"); @@ -116,9 +108,11 @@ namespace Kyoo }); app.UseResponseCompression(); - if (_plugins is PluginManager manager) - manager.SetProvider(provider); - _plugins.ConfigureAspnet(app); + IEnumerable steps = _plugins.GetAllPlugins() + .SelectMany(x => x.ConfigureSteps) + .OrderByDescending(x => x.Priority); + foreach (IStartupAction step in steps) + step.Run(provider); app.UseSpa(spa => { diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index 064cb6e7..cd16ca95 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -28,8 +28,8 @@ namespace Kyoo [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse")] public static async Task Main(string[] args) { - if (!File.Exists("./settings.json")) - File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json"); + if (!File.Exists(JsonConfigPath)) + File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, JsonConfigPath), JsonConfigPath); IHostBuilder builder = CreateWebHostBuilder(args); @@ -77,7 +77,8 @@ namespace Kyoo /// The modified configuration builder private static IConfigurationBuilder SetupConfig(IConfigurationBuilder builder, string[] args) { - return builder.AddJsonFile(JsonConfigPath, false, true) + return builder.SetBasePath(Environment.CurrentDirectory) + .AddJsonFile(JsonConfigPath, false, true) .AddEnvironmentVariables() .AddCommandLine(args); }