diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index d15987de..6c100622 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -18,7 +18,7 @@ namespace Kyoo.Controllers /// Get the repository corresponding to the T item. /// /// The type you want - /// If the item is not found + /// If the item is not found /// The repository corresponding IRepository GetRepository() where T : class, IResource; @@ -82,7 +82,7 @@ namespace Kyoo.Controllers /// /// The id of the resource /// The type of the resource - /// If the item is not found + /// If the item is not found /// The resource found Task Get(int id) where T : class, IResource; @@ -91,7 +91,7 @@ namespace Kyoo.Controllers /// /// The slug of the resource /// The type of the resource - /// If the item is not found + /// If the item is not found /// The resource found Task Get(string slug) where T : class, IResource; @@ -100,7 +100,7 @@ namespace Kyoo.Controllers /// /// The filter function. /// The type of the resource - /// If the item is not found + /// If the item is not found /// The first resource found that match the where function Task Get(Expression> where) where T : class, IResource; @@ -109,7 +109,7 @@ namespace Kyoo.Controllers /// /// The id of the show /// The season's number - /// If the item is not found + /// If the item is not found /// The season found Task Get(int showID, int seasonNumber); @@ -118,7 +118,7 @@ namespace Kyoo.Controllers /// /// The slug of the show /// The season's number - /// If the item is not found + /// If the item is not found /// The season found Task Get(string showSlug, int seasonNumber); @@ -128,7 +128,7 @@ namespace Kyoo.Controllers /// The id of the show /// The season's number /// The episode's number - /// If the item is not found + /// If the item is not found /// The episode found Task Get(int showID, int seasonNumber, int episodeNumber); @@ -138,7 +138,7 @@ namespace Kyoo.Controllers /// The slug of the show /// The season's number /// The episode's number - /// If the item is not found + /// If the item is not found /// The episode found Task Get(string showSlug, int seasonNumber, int episodeNumber); @@ -147,7 +147,7 @@ namespace Kyoo.Controllers /// /// The slug of the track /// The type (Video, Audio or Subtitle) - /// If the item is not found + /// If the item is not found /// The tracl found Task Get(string slug, StreamType type = StreamType.Unknown); @@ -505,7 +505,7 @@ namespace Kyoo.Controllers /// The resourcce to edit, it's ID can't change. /// Should old properties of the resource be discarded or should null values considered as not changed? /// The type of resources - /// If the item is not found + /// If the item is not found /// The resource edited and completed by database's informations (related items & so on) Task Edit(T item, bool resetOld) where T : class, IResource; @@ -514,7 +514,7 @@ namespace Kyoo.Controllers /// /// The resource to delete /// The type of resource to delete - /// If the item is not found + /// If the item is not found Task Delete(T item) where T : class, IResource; /// @@ -522,7 +522,7 @@ namespace Kyoo.Controllers /// /// The id of the resource to delete /// The type of resource to delete - /// If the item is not found + /// If the item is not found Task Delete(int id) where T : class, IResource; /// @@ -530,7 +530,7 @@ namespace Kyoo.Controllers /// /// The slug of the resource to delete /// The type of resource to delete - /// If the item is not found + /// If the item is not found Task Delete(string slug) where T : class, IResource; } } diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs index e4a058af..c1652a4a 100644 --- a/Kyoo.Common/Controllers/IPlugin.cs +++ b/Kyoo.Common/Controllers/IPlugin.cs @@ -1,6 +1,6 @@ +using System; using JetBrains.Annotations; using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; using Unity; namespace Kyoo.Controllers @@ -8,6 +8,8 @@ namespace Kyoo.Controllers /// /// A common interface used to discord plugins /// + /// You can inject services in the IPlugin constructor. + /// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment. [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] public interface IPlugin { @@ -30,30 +32,33 @@ namespace Kyoo.Controllers /// A list of services that are provided by this service. This allow other plugins to declare dependencies. /// /// - /// The format should be the name of the interface ':' and the name of the implementation. - /// For a plugins that provide a new service named IService with a default implementation named Koala, that would - /// be "IService:Koala". + /// You should put directly the type that you will register in configure, Kyoo will detect by itself which + /// interfaces are implemented by your type. /// - string[] Provides { get; } + Type[] Provides { get; } /// /// A list of services that are required by this service. /// The Core will warn the user that this plugin can't be loaded if a required service is not found. /// /// - /// This is the same format as but you may leave a blank implementation's name if you don't need a special one. - /// For example, if you need a service named IService but you don't care what implementation it will be, you can use - /// "IService:" + /// Put here the most complete type that are needed for your plugin to work. If you need a LibraryManager, + /// put typeof(ILibraryManager). /// - string[] Requires { get; } + Type[] Requires { get; } /// /// A configure method that will be run on plugin's startup. /// /// A unity container to register new services. - /// The configuration, if you need values at config time (database connection strings...) + void Configure(IUnityContainer container); + + /// + /// 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. - /// True if the app should run in debug mode. - void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode); + void ConfigureAspNet(IApplicationBuilder app) {} + } } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/IPluginManager.cs b/Kyoo.Common/Controllers/IPluginManager.cs index 643cce7a..558f86bf 100644 --- a/Kyoo.Common/Controllers/IPluginManager.cs +++ b/Kyoo.Common/Controllers/IPluginManager.cs @@ -1,13 +1,39 @@ using System.Collections.Generic; -using Kyoo.Models; +using Kyoo.Models.Exceptions; namespace Kyoo.Controllers { + /// + /// A manager to load plugins and retrieve information from them. + /// public interface IPluginManager { + /// + /// Get a single plugin that match the type and name given. + /// + /// The name of the plugin + /// The type of the plugin + /// If no plugins match the query + /// A plugin that match the queries public T GetPlugin(string name); - public IEnumerable GetPlugins(); - public IEnumerable GetAllPlugins(); + + /// + /// Get all plugins of the given type. + /// + /// The type of plugins to get + /// A list of plugins matching the given type or an empty list of none match. + public ICollection GetPlugins(); + + /// + /// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted. + /// + /// All plugins currently loaded. + public ICollection GetAllPlugins(); + + /// + /// Load new plugins from the plugin directory. + /// + /// If a plugin can't be loaded because a dependency can't be resolved. public void ReloadPlugins(); } } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs index 2ed0b19a..bc5ed0bc 100644 --- a/Kyoo.Common/Controllers/IRepository.cs +++ b/Kyoo.Common/Controllers/IRepository.cs @@ -127,21 +127,21 @@ namespace Kyoo.Controllers /// Get a resource from it's ID. /// /// The id of the resource - /// If the item could not be found. + /// If the item could not be found. /// The resource found Task Get(int id); /// /// Get a resource from it's slug. /// /// The slug of the resource - /// If the item could not be found. + /// If the item could not be found. /// The resource found Task Get(string slug); /// /// Get the first resource that match the predicate. /// /// A predicate to filter the resource. - /// If the item could not be found. + /// If the item could not be found. /// The resource found Task Get(Expression> where); @@ -221,7 +221,7 @@ namespace Kyoo.Controllers /// /// The resourcce to edit, it's ID can't change. /// Should old properties of the resource be discarded or should null values considered as not changed? - /// If the item is not found + /// If the item is not found /// The resource edited and completed by database's informations (related items & so on) Task Edit([NotNull] T edited, bool resetOld); @@ -229,62 +229,62 @@ namespace Kyoo.Controllers /// Delete a resource by it's ID /// /// The ID of the resource - /// If the item is not found + /// If the item is not found Task Delete(int id); /// /// Delete a resource by it's slug /// /// The slug of the resource - /// If the item is not found + /// If the item is not found Task Delete(string slug); /// /// Delete a resource /// /// The resource to delete - /// If the item is not found + /// If the item is not found Task Delete([NotNull] T obj); /// /// Delete a list of resources. /// /// One or multiple resources to delete - /// If the item is not found + /// If the item is not found Task DeleteRange(params T[] objs) => DeleteRange(objs.AsEnumerable()); /// /// Delete a list of resources. /// /// An enumerable of resources to delete - /// If the item is not found + /// If the item is not found Task DeleteRange(IEnumerable objs); /// /// Delete a list of resources. /// /// One or multiple resources's id - /// If the item is not found + /// If the item is not found Task DeleteRange(params int[] ids) => DeleteRange(ids.AsEnumerable()); /// /// Delete a list of resources. /// /// An enumearble of resources's id - /// If the item is not found + /// If the item is not found Task DeleteRange(IEnumerable ids); /// /// Delete a list of resources. /// /// One or multiple resources's slug - /// If the item is not found + /// If the item is not found Task DeleteRange(params string[] slugs) => DeleteRange(slugs.AsEnumerable()); /// /// Delete a list of resources. /// /// An enumerable of resources's slug - /// If the item is not found + /// If the item is not found Task DeleteRange(IEnumerable slugs); /// /// Delete a list of resources. /// /// A predicate to filter resources to delete. Every resource that match this will be deleted. - /// If the item is not found + /// If the item is not found Task DeleteRange([NotNull] Expression> where); } @@ -306,7 +306,7 @@ namespace Kyoo.Controllers /// Get a show's slug from it's ID. /// /// The ID of the show - /// If a show with the given ID is not found. + /// If a show with the given ID is not found. /// The show's slug Task GetSlug(int showID); } @@ -321,7 +321,7 @@ namespace Kyoo.Controllers /// /// The id of the show /// The season's number - /// If the item is not found + /// If the item is not found /// The season found Task Get(int showID, int seasonNumber); @@ -330,7 +330,7 @@ namespace Kyoo.Controllers /// /// The slug of the show /// The season's number - /// If the item is not found + /// If the item is not found /// The season found Task Get(string showSlug, int seasonNumber); @@ -362,7 +362,7 @@ namespace Kyoo.Controllers /// The id of the show /// The season's number /// The episode's number - /// If the item is not found + /// If the item is not found /// The episode found Task Get(int showID, int seasonNumber, int episodeNumber); /// @@ -371,7 +371,7 @@ namespace Kyoo.Controllers /// The slug of the show /// The season's number /// The episode's number - /// If the item is not found + /// If the item is not found /// The episode found Task Get(string showSlug, int seasonNumber, int episodeNumber); @@ -397,7 +397,7 @@ namespace Kyoo.Controllers /// /// The id of the show /// The episode's absolute number (The episode number does not reset to 1 after the end of a season. - /// If the item is not found + /// If the item is not found /// The episode found Task GetAbsolute(int showID, int absoluteNumber); /// @@ -405,7 +405,7 @@ namespace Kyoo.Controllers /// /// The slug of the show /// The episode's absolute number (The episode number does not reset to 1 after the end of a season. - /// If the item is not found + /// If the item is not found /// The episode found Task GetAbsolute(string showSlug, int absoluteNumber); } @@ -420,7 +420,7 @@ namespace Kyoo.Controllers /// /// The slug of the track /// The type (Video, Audio or Subtitle) - /// If the item is not found + /// If the item is not found /// The tracl found Task Get(string slug, StreamType type = StreamType.Unknown); diff --git a/Kyoo.Common/Controllers/ITaskManager.cs b/Kyoo.Common/Controllers/ITaskManager.cs index 1197f049..5a0710c6 100644 --- a/Kyoo.Common/Controllers/ITaskManager.cs +++ b/Kyoo.Common/Controllers/ITaskManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using Kyoo.Models; using Kyoo.Models.Exceptions; namespace Kyoo.Controllers @@ -17,7 +16,7 @@ namespace Kyoo.Controllers /// The slug of the task to run /// A list of arguments to pass to the task. An automatic conversion will be made if arguments to not fit. /// If the number of arguments is invalid or if an argument can't be converted. - /// The task could not be found. + /// The task could not be found. void StartTask(string taskSlug, Dictionary arguments = null); /// @@ -27,7 +26,7 @@ namespace Kyoo.Controllers ICollection GetRunningTasks(); /// - /// Get all availables tasks + /// Get all available tasks /// /// A list of every tasks that this instance know. ICollection GetAllTasks(); diff --git a/Kyoo.Common/Controllers/IThumbnailsManager.cs b/Kyoo.Common/Controllers/IThumbnailsManager.cs index 2282981a..ee31498a 100644 --- a/Kyoo.Common/Controllers/IThumbnailsManager.cs +++ b/Kyoo.Common/Controllers/IThumbnailsManager.cs @@ -1,5 +1,4 @@ using Kyoo.Models; -using System.Collections.Generic; using System.Threading.Tasks; using JetBrains.Annotations; diff --git a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs index 2fb16735..dcf35813 100644 --- a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs +++ b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs @@ -66,7 +66,7 @@ namespace Kyoo.Controllers { if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository ret) return ret; - throw new ItemNotFound(); + throw new ItemNotFoundException(); } /// diff --git a/Kyoo.Common/Models/Exceptions/DuplicatedItemException.cs b/Kyoo.Common/Models/Exceptions/DuplicatedItemException.cs index 19be8a04..eb85432f 100644 --- a/Kyoo.Common/Models/Exceptions/DuplicatedItemException.cs +++ b/Kyoo.Common/Models/Exceptions/DuplicatedItemException.cs @@ -2,18 +2,25 @@ using System; namespace Kyoo.Models.Exceptions { + /// + /// An exception raised when an item already exists in the database. + /// + [Serializable] public class DuplicatedItemException : Exception { - public override string Message { get; } - + /// + /// Create a new with the default message. + /// public DuplicatedItemException() - { - Message = "Already exists in the databse."; - } + : base("Already exists in the database.") + { } + /// + /// Create a new with a custom message. + /// + /// The message to use public DuplicatedItemException(string message) - { - Message = message; - } + : base(message) + { } } } \ No newline at end of file diff --git a/Kyoo.Common/Models/Exceptions/ItemNotFound.cs b/Kyoo.Common/Models/Exceptions/ItemNotFound.cs deleted file mode 100644 index f23cf363..00000000 --- a/Kyoo.Common/Models/Exceptions/ItemNotFound.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Kyoo.Models.Exceptions -{ - public class ItemNotFound : Exception - { - public override string Message { get; } - - public ItemNotFound() {} - - public ItemNotFound(string message) - { - Message = message; - } - } -} \ No newline at end of file diff --git a/Kyoo.Common/Models/Exceptions/ItemNotFoundException.cs b/Kyoo.Common/Models/Exceptions/ItemNotFoundException.cs new file mode 100644 index 00000000..a04b60a1 --- /dev/null +++ b/Kyoo.Common/Models/Exceptions/ItemNotFoundException.cs @@ -0,0 +1,24 @@ +using System; + +namespace Kyoo.Models.Exceptions +{ + /// + /// An exception raised when an item could not be found. + /// + [Serializable] + public class ItemNotFoundException : Exception + { + /// + /// Create a default with no message. + /// + public ItemNotFoundException() {} + + /// + /// Create a new with a message + /// + /// The message of the exception + public ItemNotFoundException(string message) + : base(message) + { } + } +} \ No newline at end of file diff --git a/Kyoo.Common/Models/Exceptions/MissingDependencyException.cs b/Kyoo.Common/Models/Exceptions/MissingDependencyException.cs new file mode 100644 index 00000000..ec459faf --- /dev/null +++ b/Kyoo.Common/Models/Exceptions/MissingDependencyException.cs @@ -0,0 +1,20 @@ +using System; + +namespace Kyoo.Models.Exceptions +{ + /// + /// An exception raised when a plugin requires dependencies that can't be found with the current configuration. + /// + [Serializable] + public class MissingDependencyException : Exception + { + /// + /// Create a new with a custom message + /// + /// The name of the plugin that can't be loaded. + /// The name of the missing dependency. + public MissingDependencyException(string plugin, string dependency) + : base($"No {dependency} are available in kyoo but the plugin {plugin} requires it.") + {} + } +} \ No newline at end of file diff --git a/Kyoo.CommonAPI/CrudApi.cs b/Kyoo.CommonAPI/CrudApi.cs index 50dcb588..27ddf66b 100644 --- a/Kyoo.CommonAPI/CrudApi.cs +++ b/Kyoo.CommonAPI/CrudApi.cs @@ -33,7 +33,7 @@ namespace Kyoo.CommonApi { return await _repository.Get(id); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -47,7 +47,7 @@ namespace Kyoo.CommonApi { return await _repository.Get(slug); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -129,7 +129,7 @@ namespace Kyoo.CommonApi resource.ID = old.ID; return await _repository.Edit(resource, resetOld); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -144,7 +144,7 @@ namespace Kyoo.CommonApi { return await _repository.Edit(resource, resetOld); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -160,7 +160,7 @@ namespace Kyoo.CommonApi resource.ID = old.ID; return await _repository.Edit(resource, resetOld); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -174,7 +174,7 @@ namespace Kyoo.CommonApi { await _repository.Delete(id); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -190,7 +190,7 @@ namespace Kyoo.CommonApi { await _repository.Delete(slug); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -205,7 +205,7 @@ namespace Kyoo.CommonApi { await _repository.DeleteRange(ApiHelper.ParseWhere(where)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Models/DatabaseContext.cs b/Kyoo.CommonAPI/DatabaseContext.cs similarity index 100% rename from Kyoo/Models/DatabaseContext.cs rename to Kyoo.CommonAPI/DatabaseContext.cs diff --git a/Kyoo/Extensions.cs b/Kyoo.CommonAPI/Extensions.cs similarity index 87% rename from Kyoo/Extensions.cs rename to Kyoo.CommonAPI/Extensions.cs index 70a100d2..dfb2d4d8 100644 --- a/Kyoo/Extensions.cs +++ b/Kyoo.CommonAPI/Extensions.cs @@ -9,14 +9,15 @@ namespace Kyoo public static class Extensions { /// - /// Get a connection string from the Configuration's section "Databse" + /// Get a connection string from the Configuration's section "Database" /// /// The IConfiguration instance to load. + /// The database's name. /// A parsed connection string - public static string GetDatabaseConnection(this IConfiguration config) + public static string GetDatabaseConnection(this IConfiguration config, string database) { DbConnectionStringBuilder builder = new(); - IConfigurationSection section = config.GetSection("Database"); + IConfigurationSection section = config.GetSection("Database").GetSection(database); foreach (IConfigurationSection child in section.GetChildren()) builder[child.Key] = child.Value; return builder.ConnectionString; diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs index c1e14a6e..32b47bd2 100644 --- a/Kyoo.CommonAPI/LocalRepository.cs +++ b/Kyoo.CommonAPI/LocalRepository.cs @@ -46,13 +46,13 @@ namespace Kyoo.Controllers /// Get a resource from it's ID and make the instance track it. /// /// The ID of the resource - /// If the item is not found + /// If the item is not found /// The tracked resource with the given ID protected virtual async Task GetWithTracking(int id) { T ret = await Database.Set().AsTracking().FirstOrDefaultAsync(x => x.ID == id); if (ret == null) - throw new ItemNotFound($"No {typeof(T).Name} found with the id {id}"); + throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}"); return ret; } @@ -61,7 +61,7 @@ namespace Kyoo.Controllers { T ret = await GetOrDefault(id); if (ret == null) - throw new ItemNotFound($"No {typeof(T).Name} found with the id {id}"); + throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}"); return ret; } @@ -70,7 +70,7 @@ namespace Kyoo.Controllers { T ret = await GetOrDefault(slug); if (ret == null) - throw new ItemNotFound($"No {typeof(T).Name} found with the slug {slug}"); + throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}"); return ret; } @@ -79,7 +79,7 @@ namespace Kyoo.Controllers { T ret = await GetOrDefault(where); if (ret == null) - throw new ItemNotFound($"No {typeof(T).Name} found with the given predicate."); + throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate."); return ret; } diff --git a/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/Kyoo.Postgresql/Kyoo.Postgresql.csproj index e0089c22..5e4d8678 100644 --- a/Kyoo.Postgresql/Kyoo.Postgresql.csproj +++ b/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -2,10 +2,18 @@ net5.0 + $(SolutionDir)/Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/postgresql + false + false + false + + SDG + Zoe Roux + https://github.com/AnonymusRaccoon/Kyoo + default - @@ -15,4 +23,15 @@ + + + + all + false + + + all + false + + diff --git a/Kyoo.Postgresql/PostgresContext.cs b/Kyoo.Postgresql/PostgresContext.cs index 9d20cf53..7ee49adb 100644 --- a/Kyoo.Postgresql/PostgresContext.cs +++ b/Kyoo.Postgresql/PostgresContext.cs @@ -1,7 +1,6 @@ using System; using Kyoo.Models; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Logging; using Npgsql; namespace Kyoo.Postgresql diff --git a/Kyoo.Postgresql/PostgresModule.cs b/Kyoo.Postgresql/PostgresModule.cs index 23549460..c83df51d 100644 --- a/Kyoo.Postgresql/PostgresModule.cs +++ b/Kyoo.Postgresql/PostgresModule.cs @@ -1,12 +1,9 @@ using System; using Kyoo.Controllers; -using Microsoft.AspNetCore.Builder; -using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Unity; -using Unity.Injection; -using Unity.Lifetime; -using Unity.Resolution; namespace Kyoo.Postgresql { @@ -25,25 +22,42 @@ namespace Kyoo.Postgresql public string Description => "A database context for postgresql."; /// - public string[] Provides => new[] + public Type[] Provides => new[] { - $"{nameof(DatabaseContext)}:{nameof(PostgresContext)}" + typeof(PostgresContext) }; /// - public string[] Requires => Array.Empty(); + public Type[] Requires => Array.Empty(); - /// - public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode) + + /// + /// The configuration to use. The database connection string is pulled from it. + /// + private readonly IConfiguration _configuration; + + /// + /// The host environment to check if the app is in debug mode. + /// + private readonly IWebHostEnvironment _environment; + + /// + /// Create a new postgres module instance and use the given configuration and environment. + /// + /// The configuration to use + /// The environment that will be used (if the env is in development mode, more information will be displayed on errors. + public PostgresModule(IConfiguration configuration, IWebHostEnvironment env) { - // options.UseNpgsql(_configuration.GetDatabaseConnection()); - // // // .EnableSensitiveDataLogging() - // // // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); - - container.RegisterFactory(_ => - { - return new PostgresContext(config.GetDatabaseConnection(), debugMode); - }); + _configuration = configuration; + _environment = env; + } + + /// + public void Configure(IUnityContainer container) + { + container.RegisterFactory(_ => new PostgresContext( + _configuration.GetDatabaseConnection("postgres"), + _environment.IsDevelopment())); } } } \ No newline at end of file diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index 5026e7c3..8b9e9ca2 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -4,100 +4,152 @@ using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Loader; -using Kyoo.Models; +using Kyoo.Models.Exceptions; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Unity; namespace Kyoo.Controllers { - public class PluginDependencyLoader : AssemblyLoadContext - { - private readonly AssemblyDependencyResolver _resolver; - - public PluginDependencyLoader(string pluginPath) - { - _resolver = new AssemblyDependencyResolver(pluginPath); - } - - protected override Assembly Load(AssemblyName assemblyName) - { - string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); - if (assemblyPath != null) - return LoadFromAssemblyPath(assemblyPath); - return base.Load(assemblyName); - } - - protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) - { - string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); - if (libraryPath != null) - return LoadUnmanagedDllFromPath(libraryPath); - return base.LoadUnmanagedDll(unmanagedDllName); - } - } - + /// + /// An implementation of . + /// This is used to load plugins and retrieve information from them. + /// public class PluginManager : IPluginManager { - private readonly IServiceProvider _provider; + /// + /// The unity container. It is given to the Configure method of plugins. + /// + private readonly IUnityContainer _container; + /// + /// The configuration to get the plugin's directory. + /// private readonly IConfiguration _config; - private List _plugins; + /// + /// The logger used by this class. + /// + private readonly ILogger _logger; + + /// + /// The list of plugins that are currently loaded. + /// + private readonly List _plugins = new(); - public PluginManager(IServiceProvider provider, IConfiguration config) + /// + /// Create a new instance. + /// + /// A unity container to allow plugins to register new entries + /// The configuration instance, to get the plugin's directory path. + /// The logger used by this class. + public PluginManager(IUnityContainer container, + IConfiguration config, + ILogger logger) { - _provider = provider; + _container = container; _config = config; + _logger = logger; } + + /// public T GetPlugin(string name) { return (T)_plugins?.FirstOrDefault(x => x.Name == name && x is T); } - public IEnumerable GetPlugins() + /// + public ICollection GetPlugins() { - return _plugins?.OfType() ?? new List(); + return _plugins?.OfType().ToArray(); } - public IEnumerable GetAllPlugins() + /// + public ICollection GetAllPlugins() { - return _plugins ?? new List(); + return _plugins; } + /// public void ReloadPlugins() { string pluginFolder = _config.GetValue("plugins"); if (!Directory.Exists(pluginFolder)) Directory.CreateDirectory(pluginFolder); - string[] pluginsPaths = Directory.GetFiles(pluginFolder); - _plugins = pluginsPaths.SelectMany(path => + _logger.LogTrace("Loading new plugins..."); + string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories); + ICollection newPlugins = pluginsPaths.SelectMany(path => { path = Path.GetFullPath(path); try { PluginDependencyLoader loader = new(path); - Assembly ass = loader.LoadFromAssemblyPath(path); - return ass.GetTypes() + Assembly assembly = loader.LoadFromAssemblyPath(path); + return assembly.GetTypes() .Where(x => typeof(IPlugin).IsAssignableFrom(x)) - .Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)); + .Where(x => _plugins.All(y => y.GetType() != x)) + .Select(x => (IPlugin)_container.Resolve(x)); } catch (Exception ex) { - Console.Error.WriteLine($"\nError loading the plugin at {path}.\n{ex.GetType().Name}: {ex.Message}\n"); + _logger.LogError(ex, "Could not load the plugin at {Path}", path); return Array.Empty(); } - }).ToList(); - - if (!_plugins.Any()) + }).ToArray(); + _plugins.AddRange(newPlugins); + + ICollection available = _plugins.SelectMany(x => x.Provides).ToArray(); + foreach (IPlugin plugin in newPlugins) { - Console.WriteLine("\nNo plugin enabled.\n"); - return; + Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x))); + if (missing != null) + throw new MissingDependencyException(plugin.Name, missing.Name); + plugin.Configure(_container); } - Console.WriteLine("\nPlugin enabled:"); - foreach (IPlugin plugin in _plugins) - Console.WriteLine($"\t{plugin.Name}"); - Console.WriteLine(); + if (!_plugins.Any()) + _logger.LogInformation("No plugin enabled"); + else + _logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name)); + } + + + /// + /// A custom to load plugin's dependency if they are on the same folder. + /// + private class PluginDependencyLoader : AssemblyLoadContext + { + /// + /// The basic resolver that will be used to load dlls. + /// + private readonly AssemblyDependencyResolver _resolver; + + /// + /// Create a new for the given path. + /// + /// The path of the plugin and it's dependencies + public PluginDependencyLoader(string pluginPath) + { + _resolver = new AssemblyDependencyResolver(pluginPath); + } + + /// + protected override Assembly Load(AssemblyName assemblyName) + { + string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + return LoadFromAssemblyPath(assemblyPath); + return base.Load(assemblyName); + } + + /// + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); + if (libraryPath != null) + return LoadUnmanagedDllFromPath(libraryPath); + return base.LoadUnmanagedDll(unmanagedDllName); + } } } } \ No newline at end of file diff --git a/Kyoo/Controllers/Repositories/EpisodeRepository.cs b/Kyoo/Controllers/Repositories/EpisodeRepository.cs index 1af6c485..75583392 100644 --- a/Kyoo/Controllers/Repositories/EpisodeRepository.cs +++ b/Kyoo/Controllers/Repositories/EpisodeRepository.cs @@ -108,7 +108,7 @@ namespace Kyoo.Controllers { Episode ret = await GetOrDefault(showID, seasonNumber, episodeNumber); if (ret == null) - throw new ItemNotFound($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}."); + throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}."); return ret; } @@ -117,7 +117,7 @@ namespace Kyoo.Controllers { Episode ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber); if (ret == null) - throw new ItemNotFound($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}."); + throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}."); return ret; } diff --git a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs index c1db8e46..05a9f6ab 100644 --- a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs @@ -154,7 +154,7 @@ namespace Kyoo.Controllers sort, limit); if (!items.Any() && await _libraries.Value.GetOrDefault(id) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); return items; } @@ -169,7 +169,7 @@ namespace Kyoo.Controllers sort, limit); if (!items.Any() && await _libraries.Value.GetOrDefault(slug) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); return items; } } diff --git a/Kyoo/Controllers/Repositories/PeopleRepository.cs b/Kyoo/Controllers/Repositories/PeopleRepository.cs index 6de72a4b..a3b20e38 100644 --- a/Kyoo/Controllers/Repositories/PeopleRepository.cs +++ b/Kyoo/Controllers/Repositories/PeopleRepository.cs @@ -131,7 +131,7 @@ namespace Kyoo.Controllers sort, limit); if (!people.Any() && await _shows.Value.Get(showID) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); foreach (PeopleRole role in people) role.ForPeople = true; return people; @@ -153,7 +153,7 @@ namespace Kyoo.Controllers sort, limit); if (!people.Any() && await _shows.Value.Get(showSlug) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); foreach (PeopleRole role in people) role.ForPeople = true; return people; @@ -174,7 +174,7 @@ namespace Kyoo.Controllers sort, limit); if (!roles.Any() && await Get(id) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); return roles; } @@ -193,7 +193,7 @@ namespace Kyoo.Controllers sort, limit); if (!roles.Any() && await Get(slug) == null) - throw new ItemNotFound(); + throw new ItemNotFoundException(); return roles; } } diff --git a/Kyoo/Controllers/Repositories/SeasonRepository.cs b/Kyoo/Controllers/Repositories/SeasonRepository.cs index b0a61c90..e86a812b 100644 --- a/Kyoo/Controllers/Repositories/SeasonRepository.cs +++ b/Kyoo/Controllers/Repositories/SeasonRepository.cs @@ -88,7 +88,7 @@ namespace Kyoo.Controllers { Season ret = await GetOrDefault(showID, seasonNumber); if (ret == null) - throw new ItemNotFound($"No season {seasonNumber} found for the show {showID}"); + throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}"); ret.ShowSlug = await _shows.GetSlug(showID); return ret; } @@ -98,7 +98,7 @@ namespace Kyoo.Controllers { Season ret = await GetOrDefault(showSlug, seasonNumber); if (ret == null) - throw new ItemNotFound($"No season {seasonNumber} found for the show {showSlug}"); + throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showSlug}"); ret.ShowSlug = showSlug; return ret; } diff --git a/Kyoo/Controllers/Repositories/TrackRepository.cs b/Kyoo/Controllers/Repositories/TrackRepository.cs index 55ddb427..4ce6da29 100644 --- a/Kyoo/Controllers/Repositories/TrackRepository.cs +++ b/Kyoo/Controllers/Repositories/TrackRepository.cs @@ -46,7 +46,7 @@ namespace Kyoo.Controllers { Track ret = await GetOrDefault(slug, type); if (ret == null) - throw new ItemNotFound($"No track found with the slug {slug} and the type {type}."); + throw new ItemNotFoundException($"No track found with the slug {slug} and the type {type}."); return ret; } diff --git a/Kyoo/Controllers/TaskManager.cs b/Kyoo/Controllers/TaskManager.cs index a625dcf2..6f9c184b 100644 --- a/Kyoo/Controllers/TaskManager.cs +++ b/Kyoo/Controllers/TaskManager.cs @@ -185,7 +185,7 @@ namespace Kyoo.Controllers int index = _tasks.FindIndex(x => x.task.Slug == taskSlug); if (index == -1) - throw new ItemNotFound($"No task found with the slug {taskSlug}"); + throw new ItemNotFoundException($"No task found with the slug {taskSlug}"); _queuedTasks.Enqueue((_tasks[index].task, arguments)); _tasks[index] = (_tasks[index].task, DateTime.Now + GetTaskDelay(taskSlug)); } diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs index 26e12c80..ac8b6fbe 100644 --- a/Kyoo/CoreModule.cs +++ b/Kyoo/CoreModule.cs @@ -1,7 +1,6 @@ +using System; using Kyoo.Controllers; using Kyoo.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.Configuration; using Unity; using Unity.Lifetime; @@ -22,42 +21,40 @@ namespace Kyoo public string Description => "The core module containing default implementations."; /// - public string[] Provides => new[] + public Type[] Provides => new[] { - $"{nameof(IFileManager)}:file", - $"{nameof(ITranscoder)}:{nameof(Transcoder)}", - $"{nameof(IThumbnailsManager)}:{nameof(ThumbnailsManager)}", - $"{nameof(IProviderManager)}:{nameof(ProviderManager)}", - $"{nameof(IPluginManager)}:{nameof(PluginManager)}", - $"{nameof(ITaskManager)}:{nameof(TaskManager)}", - $"{nameof(ILibraryManager)}:{nameof(LibraryManager)}", - $"{nameof(ILibraryRepository)}:{nameof(LibraryRepository)}", - $"{nameof(ILibraryItemRepository)}:{nameof(LibraryItemRepository)}", - $"{nameof(ICollectionRepository)}:{nameof(CollectionRepository)}", - $"{nameof(IShowRepository)}:{nameof(ShowRepository)}", - $"{nameof(ISeasonRepository)}:{nameof(SeasonRepository)}", - $"{nameof(IEpisodeRepository)}:{nameof(EpisodeRepository)}", - $"{nameof(ITrackRepository)}:{nameof(TrackRepository)}", - $"{nameof(IPeopleRepository)}:{nameof(PeopleRepository)}", - $"{nameof(IStudioRepository)}:{nameof(StudioRepository)}", - $"{nameof(IGenreRepository)}:{nameof(GenreRepository)}", - $"{nameof(IProviderRepository)}:{nameof(ProviderRepository)}" + typeof(FileManager), + typeof(Transcoder), + typeof(ThumbnailsManager), + typeof(ProviderManager), + typeof(TaskManager), + typeof(LibraryManager), + typeof(LibraryRepository), + typeof(LibraryItemRepository), + typeof(CollectionRepository), + typeof(ShowRepository), + typeof(SeasonRepository), + typeof(EpisodeRepository), + typeof(TrackRepository), + typeof(PeopleRepository), + typeof(StudioRepository), + typeof(GenreRepository), + typeof(ProviderRepository), }; /// - public string[] Requires => new[] + public Type[] Requires => new[] { - "DatabaseContext:" + typeof(DatabaseContext) }; /// - public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode) + public void Configure(IUnityContainer container) { container.RegisterType(new SingletonLifetimeManager()); container.RegisterType(new SingletonLifetimeManager()); container.RegisterType(new SingletonLifetimeManager()); container.RegisterType(new SingletonLifetimeManager()); - container.RegisterType(new SingletonLifetimeManager()); container.RegisterType(new SingletonLifetimeManager()); container.RegisterType(new HierarchicalLifetimeManager()); diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj index 92c27dba..740ae0c8 100644 --- a/Kyoo/Kyoo.csproj +++ b/Kyoo/Kyoo.csproj @@ -5,9 +5,9 @@ true Latest false - ../Kyoo.WebApp/ - ../Kyoo.WebLogin/ - ../Kyoo.Transcoder/ + $(SolutionDir)/Kyoo.WebApp/ + $(SolutionDir)/Kyoo.WebLogin/ + $(SolutionDir)/Kyoo.Transcoder/ $(DefaultItemExcludes);$(SpaRoot)node_modules/** diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index ee13bcdb..1dda599d 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -66,7 +66,7 @@ namespace Kyoo } /// - /// Createa a web host + /// Create a a web host /// /// Command line parameters that can be handled by kestrel /// A new web host instance diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index e5493f92..3a25f1d6 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -61,16 +61,9 @@ namespace Kyoo }); services.AddHttpClient(); - services.AddDbContext(options => - { - options.UseNpgsql(_configuration.GetDatabaseConnection()); - // .EnableSensitiveDataLogging() - // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); - }, ServiceLifetime.Transient); - services.AddDbContext(options => { - options.UseNpgsql(_configuration.GetDatabaseConnection()); + options.UseNpgsql(_configuration.GetDatabaseConnection("postgres")); }); string assemblyName = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; @@ -94,13 +87,13 @@ namespace Kyoo .AddConfigurationStore(options => { options.ConfigureDbContext = builder => - builder.UseNpgsql(_configuration.GetDatabaseConnection(), + builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"), sql => sql.MigrationsAssembly(assemblyName)); }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => - builder.UseNpgsql(_configuration.GetDatabaseConnection(), + builder.UseNpgsql(_configuration.GetDatabaseConnection("postgres"), sql => sql.MigrationsAssembly(assemblyName)); options.EnableTokenCleanup = true; }) @@ -147,9 +140,6 @@ namespace Kyoo { AllowedOrigins = { new Uri(publicUrl).GetLeftPart(UriPartial.Authority) } }); - - - services.AddScoped(); } public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env) @@ -214,11 +204,14 @@ namespace Kyoo if (env.IsDevelopment()) spa.UseAngularCliServer("start"); }); + + container.RegisterType(new SingletonLifetimeManager()); + IPluginManager pluginManager = new PluginManager(container, _configuration, new Logger(_loggerFactory)); + pluginManager.ReloadPlugins(); - new CoreModule().Configure(container, _configuration, app, env.IsDevelopment()); - container.RegisterFactory(c => c.Resolve(), new SingletonLifetimeManager()); // TODO the reload should re inject components from the constructor. // TODO fin a way to inject tasks without a IUnityContainer. + container.RegisterFactory(c => c.Resolve(), new SingletonLifetimeManager()); } } } diff --git a/Kyoo/Tasks/Crawler.cs b/Kyoo/Tasks/Crawler.cs index 7fc5699c..32ea147c 100644 --- a/Kyoo/Tasks/Crawler.cs +++ b/Kyoo/Tasks/Crawler.cs @@ -177,7 +177,7 @@ namespace Kyoo.Tasks await libraryManager.Create(track); Console.WriteLine($"Registering subtitle at: {path}."); } - catch (ItemNotFound) + catch (ItemNotFoundException) { await Console.Error.WriteLineAsync($"No episode found for subtitle at: ${path}."); } @@ -317,7 +317,7 @@ namespace Kyoo.Tasks season.Show = show; return season; } - catch (ItemNotFound) + catch (ItemNotFoundException) { Season season = await MetadataProvider.GetSeason(show, seasonNumber, library); await libraryManager.CreateIfNotExists(season); diff --git a/Kyoo/Views/EpisodeApi.cs b/Kyoo/Views/EpisodeApi.cs index 8dd28956..a77f408e 100644 --- a/Kyoo/Views/EpisodeApi.cs +++ b/Kyoo/Views/EpisodeApi.cs @@ -68,7 +68,7 @@ namespace Kyoo.Api { return await _libraryManager.Get(showSlug, seasonNumber); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -82,7 +82,7 @@ namespace Kyoo.Api { return await _libraryManager.Get(showID, seasonNumber); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -183,7 +183,7 @@ namespace Kyoo.Api Episode episode = await _libraryManager.Get(id); return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -198,7 +198,7 @@ namespace Kyoo.Api Episode episode = await _libraryManager.Get(slug); return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/LibraryItemApi.cs b/Kyoo/Views/LibraryItemApi.cs index 9f97a275..5c36cbc2 100644 --- a/Kyoo/Views/LibraryItemApi.cs +++ b/Kyoo/Views/LibraryItemApi.cs @@ -47,7 +47,7 @@ namespace Kyoo.Api Request.Query.ToDictionary(x => x.Key, x => x.Value.ToString(), StringComparer.InvariantCultureIgnoreCase), limit); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/PeopleApi.cs b/Kyoo/Views/PeopleApi.cs index 8f80b6f2..ed68dea3 100644 --- a/Kyoo/Views/PeopleApi.cs +++ b/Kyoo/Views/PeopleApi.cs @@ -48,7 +48,7 @@ namespace Kyoo.Api return Page(resources, limit); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -76,7 +76,7 @@ namespace Kyoo.Api return Page(resources, limit); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/ShowApi.cs b/Kyoo/Views/ShowApi.cs index de623916..7b2a8868 100644 --- a/Kyoo/Views/ShowApi.cs +++ b/Kyoo/Views/ShowApi.cs @@ -247,7 +247,7 @@ namespace Kyoo.Api { return await _libraryManager.Get(x => x.Shows.Any(y => y.ID == showID)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -261,7 +261,7 @@ namespace Kyoo.Api { return await _libraryManager.Get(x => x.Shows.Any(y => y.Slug == slug)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -384,7 +384,7 @@ namespace Kyoo.Api .ToDictionary(Path.GetFileNameWithoutExtension, x => $"{BaseURL}/api/shows/{slug}/fonts/{Path.GetFileName(x)}"); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -401,7 +401,7 @@ namespace Kyoo.Api string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments", slug); return _files.FileResult(path); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -416,7 +416,7 @@ namespace Kyoo.Api Show show = await _libraryManager.Get(slug); return _files.FileResult(await _thumbs.GetShowPoster(show)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -431,7 +431,7 @@ namespace Kyoo.Api Show show = await _libraryManager.Get(slug); return _files.FileResult(await _thumbs.GetShowLogo(show)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -446,7 +446,7 @@ namespace Kyoo.Api Show show = await _libraryManager.Get(slug); return _files.FileResult(await _thumbs.GetShowBackdrop(show)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/TaskApi.cs b/Kyoo/Views/TaskApi.cs index 56b37b3d..1efb3cad 100644 --- a/Kyoo/Views/TaskApi.cs +++ b/Kyoo/Views/TaskApi.cs @@ -36,7 +36,7 @@ namespace Kyoo.Api _taskManager.StartTask(taskSlug, args); return Ok(); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/TrackApi.cs b/Kyoo/Views/TrackApi.cs index 79bced62..77125bdc 100644 --- a/Kyoo/Views/TrackApi.cs +++ b/Kyoo/Views/TrackApi.cs @@ -31,7 +31,7 @@ namespace Kyoo.Api { return await _libraryManager.Get(x => x.Tracks.Any(y => y.ID == id)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -47,7 +47,7 @@ namespace Kyoo.Api // TODO Implement something like this (a dotnet-ef's QueryCompilationContext): https://stackoverflow.com/questions/62687811/how-can-i-convert-a-custom-function-to-a-sql-expression-for-entity-framework-cor return await _libraryManager.Get(x => x.Tracks.Any(y => y.Slug == slug)); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/VideoApi.cs b/Kyoo/Views/VideoApi.cs index 13c53e40..498a93a2 100644 --- a/Kyoo/Views/VideoApi.cs +++ b/Kyoo/Views/VideoApi.cs @@ -52,7 +52,7 @@ namespace Kyoo.Api Episode episode = await _libraryManager.Get(slug); return _files.FileResult(episode.Path, true); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -71,7 +71,7 @@ namespace Kyoo.Api return StatusCode(500); return _files.FileResult(path, true); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } @@ -90,7 +90,7 @@ namespace Kyoo.Api return StatusCode(500); return _files.FileResult(path, true); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/Views/WatchApi.cs b/Kyoo/Views/WatchApi.cs index cd9327ae..7418a6ae 100644 --- a/Kyoo/Views/WatchApi.cs +++ b/Kyoo/Views/WatchApi.cs @@ -27,7 +27,7 @@ namespace Kyoo.Api Episode item = await _libraryManager.Get(slug); return await WatchItem.FromEpisode(item, _libraryManager); } - catch (ItemNotFound) + catch (ItemNotFoundException) { return NotFound(); } diff --git a/Kyoo/settings.json b/Kyoo/settings.json index ef2aeb46..1622fe15 100644 --- a/Kyoo/settings.json +++ b/Kyoo/settings.json @@ -3,14 +3,16 @@ "public_url": "http://localhost:5000/", "database": { - "server": "127.0.0.1", - "port": "5432", - "database": "kyooDB", - "user ID": "kyoo", - "password": "kyooPassword", - "pooling": "true", - "maxPoolSize": "95", - "timeout": "30" + "postgres": { + "server": "127.0.0.1", + "port": "5432", + "database": "kyooDB", + "user ID": "kyoo", + "password": "kyooPassword", + "pooling": "true", + "maxPoolSize": "95", + "timeout": "30" + } }, "logging": {