mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Plugins: Removing provide and require
This commit is contained in:
parent
6d1e1261f8
commit
2e0c96b228
@ -37,20 +37,8 @@ namespace Kyoo.Authentication
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "Enable OpenID authentication for Kyoo.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => ArraySegment<Type>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => new []
|
||||
{
|
||||
typeof(IUserRepository)
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
@ -88,7 +76,7 @@ namespace Kyoo.Authentication
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
string publicUrl = _configuration.GetPublicUrl();
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
@ -34,29 +32,15 @@ namespace Kyoo.Controllers
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of services that are provided by this service. This allow other plugins to declare dependencies
|
||||
/// <c>true</c> if the plugin should be enabled, <c>false</c> otherwise.
|
||||
/// If a plugin is not enabled, no configure method will be called.
|
||||
/// This allow one to enable a plugin if a specific configuration value is set or if the environment contains
|
||||
/// the right settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You should put the type's interface that will be register in configure.
|
||||
/// By default, a plugin is always enabled. This method can be overriden to change this behavior.
|
||||
/// </remarks>
|
||||
ICollection<Type> Provides { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of types that will be provided only if a condition is met. The condition can be an arbitrary method or
|
||||
/// a condition based on other type availability. For more information, see <see cref="ConditionalProvides"/>.
|
||||
/// </summary>
|
||||
ICollection<ConditionalProvide> ConditionalProvides { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of services that are required by this plugin.
|
||||
/// You can put services that you provide conditionally here if you want.
|
||||
/// Kyoo will warn the user that this plugin can't be loaded if a required service is not found.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Put here the most complete type that are needed for your plugin to work. If you need a LibraryManager,
|
||||
/// put typeof(ILibraryManager).
|
||||
/// </remarks>
|
||||
ICollection<Type> Requires { get; }
|
||||
virtual bool Enabled => true;
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
@ -69,14 +53,11 @@ namespace Kyoo.Controllers
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// This is available for libraries that build upon a <see cref="IServiceCollection"/>, for more precise
|
||||
/// configuration use <see cref="Configure(Autofac.ContainerBuilder)"/>.
|
||||
/// </summary>
|
||||
/// <param name="services">A service container to register new services.</param>
|
||||
/// <param name="availableTypes">The list of types that are available for this instance. This can be used
|
||||
/// for conditional type. See <see cref="ProviderCondition.Has(System.Type,System.Collections.Generic.ICollection{System.Type})"/>
|
||||
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>>
|
||||
/// You can't simply check on the service collection because some dependencies might be registered after your plugin.
|
||||
/// </param>
|
||||
void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
void Configure(IServiceCollection services)
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
@ -105,143 +86,4 @@ namespace Kyoo.Controllers
|
||||
// Skipped
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A type that will only be provided if a special condition is met. To check that your condition is met,
|
||||
/// you can check the <see cref="ProviderCondition"/> class.
|
||||
/// </summary>
|
||||
public class ConditionalProvide : Tuple<Type, ProviderCondition>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the type that may be provided
|
||||
/// </summary>
|
||||
public Type Type => Item1;
|
||||
|
||||
/// <summary>
|
||||
/// Get the condition.
|
||||
/// </summary>
|
||||
public ProviderCondition Condition => Item2;
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ConditionalProvide"/> from a type and a condition.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to provide</param>
|
||||
/// <param name="condition">The condition</param>
|
||||
public ConditionalProvide(Type type, ProviderCondition condition)
|
||||
: base(type, condition)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="ConditionalProvide"/> from a tuple of (Type, ProviderCondition).
|
||||
/// </summary>
|
||||
/// <param name="tuple">The tuple to convert</param>
|
||||
public ConditionalProvide((Type type, ProviderCondition condition) tuple)
|
||||
: base(tuple.type, tuple.condition)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly convert a tuple to a <see cref="ConditionalProvide"/>.
|
||||
/// </summary>
|
||||
/// <param name="tuple">The tuple to convert</param>
|
||||
/// <returns>A new <see cref="ConditionalProvide"/> based on the given tuple.</returns>
|
||||
public static implicit operator ConditionalProvide((Type, Type) tuple) => new (tuple);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A condition for a conditional type.
|
||||
/// </summary>
|
||||
public class ProviderCondition
|
||||
{
|
||||
/// <summary>
|
||||
/// The condition as a method. If true is returned, the type will be provided.
|
||||
/// </summary>
|
||||
public Func<bool> Condition { get; } = () => true;
|
||||
/// <summary>
|
||||
/// The list of types that this method needs.
|
||||
/// </summary>
|
||||
public ICollection<Type> Needed { get; } = ArraySegment<Type>.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ProviderCondition"/> from a raw function.
|
||||
/// </summary>
|
||||
/// <param name="condition">The predicate that will be used as condition</param>
|
||||
public ProviderCondition(Func<bool> condition)
|
||||
{
|
||||
Condition = condition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ProviderCondition"/> from a type. This allow you to inform that a type will
|
||||
/// only be available if a dependency is met.
|
||||
/// </summary>
|
||||
/// <param name="needed">The type that you need</param>
|
||||
public ProviderCondition(Type needed)
|
||||
{
|
||||
Needed = new[] {needed};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ProviderCondition"/> from a list of type. This allow you to inform that a type will
|
||||
/// only be available if a list of dependencies are met.
|
||||
/// </summary>
|
||||
/// <param name="needed">The types that you need</param>
|
||||
public ProviderCondition(ICollection<Type> needed)
|
||||
{
|
||||
Needed = needed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ProviderCondition"/> with a list of types as dependencies and a predicate
|
||||
/// for arbitrary conditions.
|
||||
/// </summary>
|
||||
/// <param name="needed">The list of dependencies</param>
|
||||
/// <param name="condition">An arbitrary condition</param>
|
||||
public ProviderCondition(ICollection<Type> needed, Func<bool> condition)
|
||||
{
|
||||
Needed = needed;
|
||||
Condition = condition;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly convert a type to a <see cref="ProviderCondition"/>.
|
||||
/// </summary>
|
||||
/// <param name="type">The type dependency</param>
|
||||
/// <returns>A <see cref="ProviderCondition"/> that will return true if the given type is available.</returns>
|
||||
public static implicit operator ProviderCondition(Type type) => new(type);
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly convert a list of type to a <see cref="ProviderCondition"/>.
|
||||
/// </summary>
|
||||
/// <param name="types">The list of type dependencies</param>
|
||||
/// <returns>A <see cref="ProviderCondition"/> that will return true if the given types are available.</returns>
|
||||
public static implicit operator ProviderCondition(Type[] types) => new(types);
|
||||
|
||||
/// <inheritdoc cref="op_Implicit(System.Type[])"/>
|
||||
public static implicit operator ProviderCondition(List<Type> types) => new(types);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if a type is available.
|
||||
/// </summary>
|
||||
/// <param name="needed">The type to check</param>
|
||||
/// <param name="available">The list of types</param>
|
||||
/// <returns>True if the dependency is met, false otherwise</returns>
|
||||
public static bool Has(Type needed, ICollection<Type> available)
|
||||
{
|
||||
return available.Contains(needed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check if a list of type are available.
|
||||
/// </summary>
|
||||
/// <param name="needed">The list of types to check</param>
|
||||
/// <param name="available">The list of types</param>
|
||||
/// <returns>True if the dependencies are met, false otherwise</returns>
|
||||
public static bool Has(ICollection<Type> needed, ICollection<Type> available)
|
||||
{
|
||||
return needed.All(x => Has(x, available));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -24,19 +23,6 @@ namespace Kyoo.Postgresql
|
||||
/// <inheritdoc />
|
||||
public string Description => "A database context for postgresql.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => new[]
|
||||
{
|
||||
typeof(DatabaseContext)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use. The database connection string is pulled from it.
|
||||
/// </summary>
|
||||
@ -59,7 +45,7 @@ namespace Kyoo.Postgresql
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
services.AddDbContext<DatabaseContext, PostgresContext>(x =>
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -23,19 +22,7 @@ namespace Kyoo.SqLite
|
||||
/// <inheritdoc />
|
||||
public string Description => "A database context for sqlite.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => new[]
|
||||
{
|
||||
typeof(DatabaseContext)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use. The database connection string is pulled from it.
|
||||
/// </summary>
|
||||
@ -59,7 +46,7 @@ namespace Kyoo.SqLite
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
services.AddDbContext<DatabaseContext, SqLiteContext>(x =>
|
||||
{
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Autofac;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models.Attributes;
|
||||
@ -23,20 +21,8 @@ namespace Kyoo.TheMovieDb
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "A metadata provider for TheMovieDB.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => new []
|
||||
{
|
||||
typeof(IMetadataProvider)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
@ -65,7 +51,7 @@ namespace Kyoo.TheMovieDb
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
services.Configure<TheMovieDbOptions>(_configuration.GetSection(TheMovieDbOptions.Path));
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Autofac;
|
||||
using Kyoo.Controllers;
|
||||
using Kyoo.Models.Attributes;
|
||||
@ -24,20 +22,7 @@ namespace Kyoo.TheTvdb
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "A metadata provider for The TVDB.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => new []
|
||||
{
|
||||
typeof(IMetadataProvider)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
@ -67,7 +52,7 @@ namespace Kyoo.TheTvdb
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
services.Configure<TvdbOption>(_configuration.GetSection(TvdbOption.Path));
|
||||
}
|
||||
|
@ -112,22 +112,11 @@ namespace Kyoo.Controllers
|
||||
|
||||
_logger.LogTrace("Loading new plugins...");
|
||||
string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories);
|
||||
plugins = plugins.Concat(pluginsPaths.SelectMany(LoadPlugin))
|
||||
_plugins.AddRange(plugins
|
||||
.Concat(pluginsPaths.SelectMany(LoadPlugin))
|
||||
.GroupBy(x => x.Name)
|
||||
.Select(x => x.First())
|
||||
.ToList();
|
||||
|
||||
ICollection<Type> available = GetProvidedTypes(plugins);
|
||||
_plugins.AddRange(plugins.Where(plugin =>
|
||||
{
|
||||
Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x)));
|
||||
if (missing == null)
|
||||
return true;
|
||||
|
||||
_logger.LogCritical("No {Dependency} available in Kyoo but the plugin {Plugin} requires it",
|
||||
missing.Name, plugin.Name);
|
||||
return false;
|
||||
}));
|
||||
);
|
||||
|
||||
if (!_plugins.Any())
|
||||
_logger.LogInformation("No plugin enabled");
|
||||
@ -138,7 +127,10 @@ namespace Kyoo.Controllers
|
||||
/// <inheritdoc />
|
||||
public void LoadPlugins(params Type[] plugins)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
LoadPlugins(plugins
|
||||
.Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x))
|
||||
.ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -151,9 +143,8 @@ namespace Kyoo.Controllers
|
||||
/// <inheritdoc />
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
ICollection<Type> available = GetProvidedTypes(_plugins);
|
||||
foreach (IPlugin plugin in _plugins)
|
||||
plugin.Configure(services, available);
|
||||
plugin.Configure(services);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -168,53 +159,6 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the list of types provided by the currently loaded plugins.
|
||||
/// </summary>
|
||||
/// <param name="plugins">The list of plugins that will be used as a plugin pool to get provided types.</param>
|
||||
/// <returns>The list of types available.</returns>
|
||||
private ICollection<Type> GetProvidedTypes(ICollection<IPlugin> plugins)
|
||||
{
|
||||
List<Type> available = plugins.SelectMany(x => x.Provides).ToList();
|
||||
List<ConditionalProvide> conditionals = plugins
|
||||
.SelectMany(x => x.ConditionalProvides)
|
||||
.Where(x => x.Condition.Condition())
|
||||
.ToList();
|
||||
|
||||
bool IsAvailable(ConditionalProvide conditional, bool log = false)
|
||||
{
|
||||
if (!conditional.Condition.Condition())
|
||||
return false;
|
||||
|
||||
ICollection<Type> needed = conditional.Condition.Needed
|
||||
.Where(y => !available.Contains(y))
|
||||
.ToList();
|
||||
// TODO handle circular dependencies, actually it might stack overflow.
|
||||
needed = needed.Where(x => !conditionals
|
||||
.Where(y => y.Type == x)
|
||||
.Any(y => IsAvailable(y)))
|
||||
.ToList();
|
||||
if (!needed.Any())
|
||||
return true;
|
||||
if (log && available.All(x => x != conditional.Type))
|
||||
{
|
||||
_logger.LogWarning("The type {Type} is not available, {Dependencies} could not be met",
|
||||
conditional.Type.Name,
|
||||
needed.Select(x => x.Name));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
|
||||
foreach (ConditionalProvide conditional in conditionals)
|
||||
{
|
||||
if (IsAvailable(conditional, true))
|
||||
available.Add(conditional.Type);
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A custom <see cref="AssemblyLoadContext"/> to load plugin's dependency if they are on the same folder.
|
||||
/// </summary>
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
@ -31,53 +30,7 @@ namespace Kyoo
|
||||
/// <inheritdoc />
|
||||
public string Description => "The core module containing default implementations.";
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Provides => new[]
|
||||
{
|
||||
typeof(IFileSystem),
|
||||
typeof(ITranscoder),
|
||||
typeof(IThumbnailsManager),
|
||||
typeof(IMetadataProvider),
|
||||
typeof(ITaskManager),
|
||||
typeof(ILibraryManager),
|
||||
typeof(IIdentifier),
|
||||
typeof(AProviderComposite)
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<ConditionalProvide> ConditionalProvides => new ConditionalProvide[]
|
||||
{
|
||||
(typeof(ILibraryRepository), typeof(DatabaseContext)),
|
||||
(typeof(ILibraryItemRepository), typeof(DatabaseContext)),
|
||||
(typeof(ICollectionRepository), typeof(DatabaseContext)),
|
||||
(typeof(IShowRepository), typeof(DatabaseContext)),
|
||||
(typeof(ISeasonRepository), typeof(DatabaseContext)),
|
||||
(typeof(IEpisodeRepository), typeof(DatabaseContext)),
|
||||
(typeof(ITrackRepository), typeof(DatabaseContext)),
|
||||
(typeof(IPeopleRepository), typeof(DatabaseContext)),
|
||||
(typeof(IStudioRepository), typeof(DatabaseContext)),
|
||||
(typeof(IGenreRepository), typeof(DatabaseContext)),
|
||||
(typeof(IProviderRepository), typeof(DatabaseContext)),
|
||||
(typeof(IUserRepository), typeof(DatabaseContext))
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<Type> Requires => new []
|
||||
{
|
||||
typeof(ILibraryRepository),
|
||||
typeof(ILibraryItemRepository),
|
||||
typeof(ICollectionRepository),
|
||||
typeof(IShowRepository),
|
||||
typeof(ISeasonRepository),
|
||||
typeof(IEpisodeRepository),
|
||||
typeof(ITrackRepository),
|
||||
typeof(IPeopleRepository),
|
||||
typeof(IStudioRepository),
|
||||
typeof(IGenreRepository),
|
||||
typeof(IProviderRepository)
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration to use.
|
||||
/// </summary>
|
||||
@ -142,7 +95,7 @@ namespace Kyoo
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
string publicUrl = _configuration.GetPublicUrl();
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace Kyoo
|
||||
typeof(CoreModule),
|
||||
typeof(AuthenticationModule),
|
||||
typeof(PostgresModule),
|
||||
typeof(SqLiteModule),
|
||||
// typeof(SqLiteModule),
|
||||
typeof(PluginTvdb),
|
||||
typeof(PluginTmdb)
|
||||
);
|
||||
|
@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using Kyoo.Controllers;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
Loading…
x
Reference in New Issue
Block a user