mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Reworking the plugin manager
This commit is contained in:
parent
833447ded8
commit
79995ea191
@ -18,7 +18,7 @@ namespace Kyoo.Controllers
|
||||
/// Get the repository corresponding to the T item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type you want</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The repository corresponding</returns>
|
||||
IRepository<T> GetRepository<T>() where T : class, IResource;
|
||||
|
||||
@ -82,7 +82,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get<T>(int id) where T : class, IResource;
|
||||
|
||||
@ -91,7 +91,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get<T>(string slug) where T : class, IResource;
|
||||
|
||||
@ -100,7 +100,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="where">The filter function.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
Task<T> Get<T>(Expression<Func<T, bool>> where) where T : class, IResource;
|
||||
|
||||
@ -109,7 +109,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
@ -118,7 +118,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
@ -128,7 +128,7 @@ namespace Kyoo.Controllers
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
@ -138,7 +138,7 @@ namespace Kyoo.Controllers
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
@ -147,7 +147,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the track</param>
|
||||
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The tracl found</returns>
|
||||
Task<Track> Get(string slug, StreamType type = StreamType.Unknown);
|
||||
|
||||
@ -505,7 +505,7 @@ namespace Kyoo.Controllers
|
||||
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
|
||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
||||
Task<T> Edit<T>(T item, bool resetOld) where T : class, IResource;
|
||||
|
||||
@ -514,7 +514,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="item">The resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete<T>(T item) where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -522,7 +522,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete<T>(int id) where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
@ -530,7 +530,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete<T>(string slug) where T : class, IResource;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
/// <summary>
|
||||
/// A common interface used to discord plugins
|
||||
/// </summary>
|
||||
/// <remarks>You can inject services in the IPlugin constructor.
|
||||
/// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment.</remarks>
|
||||
[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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
string[] Provides { get; }
|
||||
Type[] Provides { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the same format as <see cref="Provides"/> 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).
|
||||
/// </remarks>
|
||||
string[] Requires { get; }
|
||||
Type[] Requires { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// </summary>
|
||||
/// <param name="container">A unity container to register new services.</param>
|
||||
/// <param name="config">The configuration, if you need values at config time (database connection strings...)</param>
|
||||
void Configure(IUnityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// <param name="app">The Asp.Net application builder. On most case it is not needed but you can use it to add asp net functionalities.</param>
|
||||
/// <param name="debugMode">True if the app should run in debug mode.</param>
|
||||
void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode);
|
||||
void ConfigureAspNet(IApplicationBuilder app) {}
|
||||
|
||||
}
|
||||
}
|
@ -1,13 +1,39 @@
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Models;
|
||||
using Kyoo.Models.Exceptions;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// A manager to load plugins and retrieve information from them.
|
||||
/// </summary>
|
||||
public interface IPluginManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a single plugin that match the type and name given.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the plugin</param>
|
||||
/// <typeparam name="T">The type of the plugin</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If no plugins match the query</exception>
|
||||
/// <returns>A plugin that match the queries</returns>
|
||||
public T GetPlugin<T>(string name);
|
||||
public IEnumerable<T> GetPlugins<T>();
|
||||
public IEnumerable<IPlugin> GetAllPlugins();
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of plugins to get</typeparam>
|
||||
/// <returns>A list of plugins matching the given type or an empty list of none match.</returns>
|
||||
public ICollection<T> GetPlugins<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted.
|
||||
/// </summary>
|
||||
/// <returns>All plugins currently loaded.</returns>
|
||||
public ICollection<IPlugin> GetAllPlugins();
|
||||
|
||||
/// <summary>
|
||||
/// Load new plugins from the plugin directory.
|
||||
/// </summary>
|
||||
/// <exception cref="MissingDependencyException">If a plugin can't be loaded because a dependency can't be resolved.</exception>
|
||||
public void ReloadPlugins();
|
||||
}
|
||||
}
|
@ -127,21 +127,21 @@ namespace Kyoo.Controllers
|
||||
/// Get a resource from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <exception cref="ItemNotFound">If the item could not be found.</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(int id);
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFound">If the item could not be found.</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(string slug);
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <exception cref="ItemNotFound">If the item could not be found.</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(Expression<Func<T, bool>> where);
|
||||
|
||||
@ -221,7 +221,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="edited">The resourcce to edit, it's ID can't change.</param>
|
||||
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
|
||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||
|
||||
@ -229,62 +229,62 @@ namespace Kyoo.Controllers
|
||||
/// Delete a resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete(int id);
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete(string slug);
|
||||
/// <summary>
|
||||
/// Delete a resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete([NotNull] T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="objs">One or multiple resources to delete</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(params T[] objs) => DeleteRange(objs.AsEnumerable());
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="objs">An enumerable of resources to delete</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(IEnumerable<T> objs);
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="ids">One or multiple resources's id</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(params int[] ids) => DeleteRange(ids.AsEnumerable());
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="ids">An enumearble of resources's id</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(IEnumerable<int> ids);
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="slugs">One or multiple resources's slug</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(params string[] slugs) => DeleteRange(slugs.AsEnumerable());
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="slugs">An enumerable of resources's slug</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange(IEnumerable<string> slugs);
|
||||
/// <summary>
|
||||
/// Delete a list of resources.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task DeleteRange([NotNull] Expression<Func<T, bool>> where);
|
||||
}
|
||||
|
||||
@ -306,7 +306,7 @@ namespace Kyoo.Controllers
|
||||
/// Get a show's slug from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <exception cref="ItemNotFound">If a show with the given ID is not found.</exception>
|
||||
/// <exception cref="ItemNotFoundException">If a show with the given ID is not found.</exception>
|
||||
/// <returns>The show's slug</returns>
|
||||
Task<string> GetSlug(int showID);
|
||||
}
|
||||
@ -321,7 +321,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
@ -330,7 +330,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
@ -362,7 +362,7 @@ namespace Kyoo.Controllers
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
/// <summary>
|
||||
@ -371,7 +371,7 @@ namespace Kyoo.Controllers
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
@ -397,7 +397,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
||||
/// <summary>
|
||||
@ -405,7 +405,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||
}
|
||||
@ -420,7 +420,7 @@ namespace Kyoo.Controllers
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the track</param>
|
||||
/// <param name="type">The type (Video, Audio or Subtitle)</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The tracl found</returns>
|
||||
Task<Track> Get(string slug, StreamType type = StreamType.Unknown);
|
||||
|
||||
|
@ -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
|
||||
/// <param name="taskSlug">The slug of the task to run</param>
|
||||
/// <param name="arguments">A list of arguments to pass to the task. An automatic conversion will be made if arguments to not fit.</param>
|
||||
/// <exception cref="ArgumentException">If the number of arguments is invalid or if an argument can't be converted.</exception>
|
||||
/// <exception cref="ItemNotFound">The task could not be found.</exception>
|
||||
/// <exception cref="ItemNotFoundException">The task could not be found.</exception>
|
||||
void StartTask(string taskSlug, Dictionary<string, object> arguments = null);
|
||||
|
||||
/// <summary>
|
||||
@ -27,7 +26,7 @@ namespace Kyoo.Controllers
|
||||
ICollection<ITask> GetRunningTasks();
|
||||
|
||||
/// <summary>
|
||||
/// Get all availables tasks
|
||||
/// Get all available tasks
|
||||
/// </summary>
|
||||
/// <returns>A list of every tasks that this instance know.</returns>
|
||||
ICollection<ITask> GetAllTasks();
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Kyoo.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository<T> ret)
|
||||
return ret;
|
||||
throw new ItemNotFound();
|
||||
throw new ItemNotFoundException();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -2,18 +2,25 @@ using System;
|
||||
|
||||
namespace Kyoo.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an item already exists in the database.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DuplicatedItemException : Exception
|
||||
{
|
||||
public override string Message { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with the default message.
|
||||
/// </summary>
|
||||
public DuplicatedItemException()
|
||||
{
|
||||
Message = "Already exists in the databse.";
|
||||
}
|
||||
: base("Already exists in the database.")
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use</param>
|
||||
public DuplicatedItemException(string message)
|
||||
{
|
||||
Message = message;
|
||||
}
|
||||
: base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
24
Kyoo.Common/Models/Exceptions/ItemNotFoundException.cs
Normal file
24
Kyoo.Common/Models/Exceptions/ItemNotFoundException.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when an item could not be found.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ItemNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a default <see cref="ItemNotFoundException"/> with no message.
|
||||
/// </summary>
|
||||
public ItemNotFoundException() {}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ItemNotFoundException"/> with a message
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the exception</param>
|
||||
public ItemNotFoundException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
20
Kyoo.Common/Models/Exceptions/MissingDependencyException.cs
Normal file
20
Kyoo.Common/Models/Exceptions/MissingDependencyException.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Models.Exceptions
|
||||
{
|
||||
/// <summary>
|
||||
/// An exception raised when a plugin requires dependencies that can't be found with the current configuration.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class MissingDependencyException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new <see cref="MissingDependencyException"/> with a custom message
|
||||
/// </summary>
|
||||
/// <param name="plugin">The name of the plugin that can't be loaded.</param>
|
||||
/// <param name="dependency">The name of the missing dependency.</param>
|
||||
public MissingDependencyException(string plugin, string dependency)
|
||||
: base($"No {dependency} are available in kyoo but the plugin {plugin} requires it.")
|
||||
{}
|
||||
}
|
||||
}
|
@ -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<T>(where));
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -9,14 +9,15 @@ namespace Kyoo
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a connection string from the Configuration's section "Databse"
|
||||
/// Get a connection string from the Configuration's section "Database"
|
||||
/// </summary>
|
||||
/// <param name="config">The IConfiguration instance to load.</param>
|
||||
/// <param name="database">The database's name.</param>
|
||||
/// <returns>A parsed connection string</returns>
|
||||
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;
|
@ -46,13 +46,13 @@ namespace Kyoo.Controllers
|
||||
/// Get a resource from it's ID and make the <see cref="Database"/> instance track it.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFound">If the item is not found</exception>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The tracked resource with the given ID</returns>
|
||||
protected virtual async Task<T> GetWithTracking(int id)
|
||||
{
|
||||
T ret = await Database.Set<T>().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;
|
||||
}
|
||||
|
||||
|
@ -2,10 +2,18 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutputPath>$(SolutionDir)/Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/postgresql</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
|
||||
|
||||
<Company>SDG</Company>
|
||||
<Authors>Zoe Roux</Authors>
|
||||
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
|
||||
<LangVersion>default</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Kyoo/Kyoo.csproj" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="5.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
|
||||
@ -15,4 +23,15 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using Kyoo.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Npgsql;
|
||||
|
||||
namespace Kyoo.Postgresql
|
||||
|
@ -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.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public string[] Provides => new[]
|
||||
public Type[] Provides => new[]
|
||||
{
|
||||
$"{nameof(DatabaseContext)}:{nameof(PostgresContext)}"
|
||||
typeof(PostgresContext)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public string[] Requires => Array.Empty<string>();
|
||||
public Type[] Requires => Array.Empty<Type>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode)
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use. The database connection string is pulled from it.
|
||||
/// </summary>
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
/// <summary>
|
||||
/// The host environment to check if the app is in debug mode.
|
||||
/// </summary>
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new postgres module instance and use the given configuration and environment.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration to use</param>
|
||||
/// <param name="env">The environment that will be used (if the env is in development mode, more information will be displayed on errors.</param>
|
||||
public PostgresModule(IConfiguration configuration, IWebHostEnvironment env)
|
||||
{
|
||||
// options.UseNpgsql(_configuration.GetDatabaseConnection());
|
||||
// // // .EnableSensitiveDataLogging()
|
||||
// // // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
|
||||
|
||||
container.RegisterFactory<DatabaseContext>(_ =>
|
||||
{
|
||||
return new PostgresContext(config.GetDatabaseConnection(), debugMode);
|
||||
});
|
||||
_configuration = configuration;
|
||||
_environment = env;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IUnityContainer container)
|
||||
{
|
||||
container.RegisterFactory<DatabaseContext>(_ => new PostgresContext(
|
||||
_configuration.GetDatabaseConnection("postgres"),
|
||||
_environment.IsDevelopment()));
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IPluginManager"/>.
|
||||
/// This is used to load plugins and retrieve information from them.
|
||||
/// </summary>
|
||||
public class PluginManager : IPluginManager
|
||||
{
|
||||
private readonly IServiceProvider _provider;
|
||||
/// <summary>
|
||||
/// The unity container. It is given to the Configure method of plugins.
|
||||
/// </summary>
|
||||
private readonly IUnityContainer _container;
|
||||
/// <summary>
|
||||
/// The configuration to get the plugin's directory.
|
||||
/// </summary>
|
||||
private readonly IConfiguration _config;
|
||||
private List<IPlugin> _plugins;
|
||||
/// <summary>
|
||||
/// The logger used by this class.
|
||||
/// </summary>
|
||||
private readonly ILogger<PluginManager> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// The list of plugins that are currently loaded.
|
||||
/// </summary>
|
||||
private readonly List<IPlugin> _plugins = new();
|
||||
|
||||
public PluginManager(IServiceProvider provider, IConfiguration config)
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PluginManager"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="container">A unity container to allow plugins to register new entries</param>
|
||||
/// <param name="config">The configuration instance, to get the plugin's directory path.</param>
|
||||
/// <param name="logger">The logger used by this class.</param>
|
||||
public PluginManager(IUnityContainer container,
|
||||
IConfiguration config,
|
||||
ILogger<PluginManager> logger)
|
||||
{
|
||||
_provider = provider;
|
||||
_container = container;
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public T GetPlugin<T>(string name)
|
||||
{
|
||||
return (T)_plugins?.FirstOrDefault(x => x.Name == name && x is T);
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetPlugins<T>()
|
||||
/// <inheritdoc />
|
||||
public ICollection<T> GetPlugins<T>()
|
||||
{
|
||||
return _plugins?.OfType<T>() ?? new List<T>();
|
||||
return _plugins?.OfType<T>().ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<IPlugin> GetAllPlugins()
|
||||
/// <inheritdoc />
|
||||
public ICollection<IPlugin> GetAllPlugins()
|
||||
{
|
||||
return _plugins ?? new List<IPlugin>();
|
||||
return _plugins;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReloadPlugins()
|
||||
{
|
||||
string pluginFolder = _config.GetValue<string>("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<IPlugin> 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<IPlugin>();
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
if (!_plugins.Any())
|
||||
}).ToArray();
|
||||
_plugins.AddRange(newPlugins);
|
||||
|
||||
ICollection<Type> 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));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A custom <see cref="AssemblyLoadContext"/> to load plugin's dependency if they are on the same folder.
|
||||
/// </summary>
|
||||
private class PluginDependencyLoader : AssemblyLoadContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The basic resolver that will be used to load dlls.
|
||||
/// </summary>
|
||||
private readonly AssemblyDependencyResolver _resolver;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PluginDependencyLoader"/> for the given path.
|
||||
/// </summary>
|
||||
/// <param name="pluginPath">The path of the plugin and it's dependencies</param>
|
||||
public PluginDependencyLoader(string pluginPath)
|
||||
{
|
||||
_resolver = new AssemblyDependencyResolver(pluginPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Assembly Load(AssemblyName assemblyName)
|
||||
{
|
||||
string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
|
||||
if (assemblyPath != null)
|
||||
return LoadFromAssemblyPath(assemblyPath);
|
||||
return base.Load(assemblyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
|
||||
{
|
||||
string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
|
||||
if (libraryPath != null)
|
||||
return LoadUnmanagedDllFromPath(libraryPath);
|
||||
return base.LoadUnmanagedDll(unmanagedDllName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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.";
|
||||
|
||||
/// <inheritdoc />
|
||||
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),
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public string[] Requires => new[]
|
||||
public Type[] Requires => new[]
|
||||
{
|
||||
"DatabaseContext:"
|
||||
typeof(DatabaseContext)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode)
|
||||
public void Configure(IUnityContainer container)
|
||||
{
|
||||
container.RegisterType<IFileManager, FileManager>(new SingletonLifetimeManager());
|
||||
container.RegisterType<ITranscoder, Transcoder>(new SingletonLifetimeManager());
|
||||
container.RegisterType<IThumbnailsManager, ThumbnailsManager>(new SingletonLifetimeManager());
|
||||
container.RegisterType<IProviderManager, ProviderManager>(new SingletonLifetimeManager());
|
||||
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
|
||||
container.RegisterType<ITaskManager, TaskManager>(new SingletonLifetimeManager());
|
||||
|
||||
container.RegisterType<ILibraryManager, LibraryManager>(new HierarchicalLifetimeManager());
|
||||
|
@ -5,9 +5,9 @@
|
||||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
|
||||
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
|
||||
<IsPackable>false</IsPackable>
|
||||
<SpaRoot>../Kyoo.WebApp/</SpaRoot>
|
||||
<LoginRoot>../Kyoo.WebLogin/</LoginRoot>
|
||||
<TranscoderRoot>../Kyoo.Transcoder/</TranscoderRoot>
|
||||
<SpaRoot>$(SolutionDir)/Kyoo.WebApp/</SpaRoot>
|
||||
<LoginRoot>$(SolutionDir)/Kyoo.WebLogin/</LoginRoot>
|
||||
<TranscoderRoot>$(SolutionDir)/Kyoo.Transcoder/</TranscoderRoot>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules/**</DefaultItemExcludes>
|
||||
|
||||
<!-- Set this to true if you enable server-side prerendering -->
|
||||
|
@ -66,7 +66,7 @@ namespace Kyoo
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Createa a web host
|
||||
/// Create a a web host
|
||||
/// </summary>
|
||||
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
||||
/// <returns>A new web host instance</returns>
|
||||
|
@ -61,16 +61,9 @@ namespace Kyoo
|
||||
});
|
||||
services.AddHttpClient();
|
||||
|
||||
services.AddDbContext<DatabaseContext>(options =>
|
||||
{
|
||||
options.UseNpgsql(_configuration.GetDatabaseConnection());
|
||||
// .EnableSensitiveDataLogging()
|
||||
// .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
|
||||
}, ServiceLifetime.Transient);
|
||||
|
||||
services.AddDbContext<IdentityDatabase>(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<DbContext, DatabaseContext>();
|
||||
}
|
||||
|
||||
public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env)
|
||||
@ -214,11 +204,14 @@ namespace Kyoo
|
||||
if (env.IsDevelopment())
|
||||
spa.UseAngularCliServer("start");
|
||||
});
|
||||
|
||||
container.RegisterType<IPluginManager, PluginManager>(new SingletonLifetimeManager());
|
||||
IPluginManager pluginManager = new PluginManager(container, _configuration, new Logger<PluginManager>(_loggerFactory));
|
||||
pluginManager.ReloadPlugins();
|
||||
|
||||
new CoreModule().Configure(container, _configuration, app, env.IsDevelopment());
|
||||
container.RegisterFactory<IHostedService>(c => c.Resolve<ITaskManager>(), new SingletonLifetimeManager());
|
||||
// TODO the reload should re inject components from the constructor.
|
||||
// TODO fin a way to inject tasks without a IUnityContainer.
|
||||
container.RegisterFactory<IHostedService>(c => c.Resolve<ITaskManager>(), new SingletonLifetimeManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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<Episode>(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<Episode>(slug);
|
||||
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -247,7 +247,7 @@ namespace Kyoo.Api
|
||||
{
|
||||
return await _libraryManager.Get<Studio>(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<Studio>(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<Show>(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<Show>(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<Show>(slug);
|
||||
return _files.FileResult(await _thumbs.GetShowBackdrop(show));
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Api
|
||||
_taskManager.StartTask(taskSlug, args);
|
||||
return Ok();
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ namespace Kyoo.Api
|
||||
{
|
||||
return await _libraryManager.Get<Episode>(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<Episode>(x => x.Tracks.Any(y => y.Slug == slug));
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace Kyoo.Api
|
||||
Episode episode = await _libraryManager.Get<Episode>(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();
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace Kyoo.Api
|
||||
Episode item = await _libraryManager.Get<Episode>(slug);
|
||||
return await WatchItem.FromEpisode(item, _libraryManager);
|
||||
}
|
||||
catch (ItemNotFound)
|
||||
catch (ItemNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
@ -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": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user