From 833447ded83c006c677814f2d0dc8980fe8fcd63 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Wed, 28 Apr 2021 23:40:22 +0200 Subject: [PATCH] Reworking the plugin interface and moving the database to an external dll --- Kyoo.Common/Controllers/IPlugin.cs | 44 +- Kyoo.Common/Controllers/ITaskManager.cs | 2 +- Kyoo.Common/Kyoo.Common.csproj | 1 + Kyoo.Common/Module.cs | 9 +- Kyoo.Postgresql/Kyoo.Postgresql.csproj | 18 + Kyoo.Postgresql/PostgresContext.cs | 76 ++ Kyoo.Postgresql/PostgresModule.cs | 49 ++ Kyoo.Tests/Library/TestContext.cs | 158 ++-- Kyoo.sln | 6 + .../Repositories/LibraryItemRepository.cs | 22 +- .../Repositories/PeopleRepository.cs | 6 +- .../Repositories/SeasonRepository.cs | 7 +- .../Repositories/ShowRepository.cs | 11 +- Kyoo/Controllers/TaskManager.cs | 8 +- Kyoo/CoreModule.cs | 62 +- Kyoo/Models/DatabaseContext.cs | 20 +- .../20210420221509_Initial.Designer.cs | 785 ------------------ .../Internal/20210420221509_Initial.cs | 607 -------------- .../Internal/DatabaseContextModelSnapshot.cs | 783 ----------------- Kyoo/Startup.cs | 48 +- Kyoo/Tasks/Crawler.cs | 3 +- 21 files changed, 365 insertions(+), 2360 deletions(-) create mode 100644 Kyoo.Postgresql/Kyoo.Postgresql.csproj create mode 100644 Kyoo.Postgresql/PostgresContext.cs create mode 100644 Kyoo.Postgresql/PostgresModule.cs delete mode 100644 Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.Designer.cs delete mode 100644 Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.cs delete mode 100644 Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs index a6949083..e4a058af 100644 --- a/Kyoo.Common/Controllers/IPlugin.cs +++ b/Kyoo.Common/Controllers/IPlugin.cs @@ -1,8 +1,14 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; +using Unity; + namespace Kyoo.Controllers { /// /// A common interface used to discord plugins /// + [UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)] public interface IPlugin { /// @@ -19,21 +25,35 @@ namespace Kyoo.Controllers /// The description of this plugin. This will be displayed on the "installed plugins" page. /// string Description { get; } - - + /// - /// A configure method that will be runned on plugin's startup. + /// A list of services that are provided by this service. This allow other plugins to declare dependencies. /// /// - /// You can have use any services as parameter, they will be injected from the service provider - /// You can add managed types or any type you like using the IUnityContainer like so: - /// - /// public static void Configure(IUnityContainer services) - /// { - /// services.AddTask<MyTask>() - /// } - /// + /// 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". /// - static void Configure() { } + string[] 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:" + /// + string[] 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...) + /// 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); } } \ No newline at end of file diff --git a/Kyoo.Common/Controllers/ITaskManager.cs b/Kyoo.Common/Controllers/ITaskManager.cs index 7f3b6013..1197f049 100644 --- a/Kyoo.Common/Controllers/ITaskManager.cs +++ b/Kyoo.Common/Controllers/ITaskManager.cs @@ -18,7 +18,7 @@ namespace Kyoo.Controllers /// 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. - void StartTask(string taskSlug, Dictionary arguments); + void StartTask(string taskSlug, Dictionary arguments = null); /// /// Get all currently running tasks diff --git a/Kyoo.Common/Kyoo.Common.csproj b/Kyoo.Common/Kyoo.Common.csproj index 3f4fdbba..b9417da8 100644 --- a/Kyoo.Common/Kyoo.Common.csproj +++ b/Kyoo.Common/Kyoo.Common.csproj @@ -23,6 +23,7 @@ + diff --git a/Kyoo.Common/Module.cs b/Kyoo.Common/Module.cs index 41b5859c..639e7c2a 100644 --- a/Kyoo.Common/Module.cs +++ b/Kyoo.Common/Module.cs @@ -1,3 +1,4 @@ +using System; using Kyoo.Controllers; using Unity; @@ -11,14 +12,14 @@ namespace Kyoo /// /// Register a new task to the container. /// - /// The container + /// The container /// The type of the task /// The initial container. - public static IUnityContainer AddTask(this IUnityContainer services) + public static IUnityContainer RegisterTask(this IUnityContainer container) where T : class, ITask { - services.RegisterSingleton(); - return services; + container.RegisterType(); + return container; } } } \ No newline at end of file diff --git a/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/Kyoo.Postgresql/Kyoo.Postgresql.csproj new file mode 100644 index 00000000..e0089c22 --- /dev/null +++ b/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -0,0 +1,18 @@ + + + + net5.0 + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/Kyoo.Postgresql/PostgresContext.cs b/Kyoo.Postgresql/PostgresContext.cs new file mode 100644 index 00000000..9d20cf53 --- /dev/null +++ b/Kyoo.Postgresql/PostgresContext.cs @@ -0,0 +1,76 @@ +using System; +using Kyoo.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Npgsql; + +namespace Kyoo.Postgresql +{ + /// + /// A postgresql implementation of . + /// + public class PostgresContext : DatabaseContext + { + /// + /// The connection string to use. + /// + private readonly string _connection; + + /// + /// Is this instance in debug mode? + /// + private readonly bool _debugMode; + + /// + /// A basic constructor that set default values (query tracker behaviors, mapping enums...) + /// + public PostgresContext() + { + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + } + + /// + /// A basic constructor that set default values (query tracker behaviors, mapping enums...) + /// + /// The connection string to use + /// Is this instance in debug mode? + public PostgresContext(string connection, bool debugMode) + { + _connection = connection; + _debugMode = debugMode; + } + + /// + /// Set connection information for this database context + /// + /// An option builder to fill. + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + optionsBuilder.UseNpgsql(_connection); + if (_debugMode) + optionsBuilder.EnableDetailedErrors() + .EnableSensitiveDataLogging(); + } + + /// + /// Set database parameters to support every types of Kyoo. + /// + /// The database's model builder. + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); + + base.OnModelCreating(modelBuilder); + } + + /// + protected override bool IsDuplicateException(Exception ex) + { + return ex.InnerException is PostgresException {SqlState: PostgresErrorCodes.UniqueViolation}; + } + } +} \ No newline at end of file diff --git a/Kyoo.Postgresql/PostgresModule.cs b/Kyoo.Postgresql/PostgresModule.cs new file mode 100644 index 00000000..23549460 --- /dev/null +++ b/Kyoo.Postgresql/PostgresModule.cs @@ -0,0 +1,49 @@ +using System; +using Kyoo.Controllers; +using Microsoft.AspNetCore.Builder; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Unity; +using Unity.Injection; +using Unity.Lifetime; +using Unity.Resolution; + +namespace Kyoo.Postgresql +{ + /// + /// A module to add postgresql capacity to the app. + /// + public class PostgresModule : IPlugin + { + /// + public string Slug => "postgresql"; + + /// + public string Name => "Postgresql"; + + /// + public string Description => "A database context for postgresql."; + + /// + public string[] Provides => new[] + { + $"{nameof(DatabaseContext)}:{nameof(PostgresContext)}" + }; + + /// + public string[] Requires => Array.Empty(); + + /// + public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode) + { + // options.UseNpgsql(_configuration.GetDatabaseConnection()); + // // // .EnableSensitiveDataLogging() + // // // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); + + container.RegisterFactory(_ => + { + return new PostgresContext(config.GetDatabaseConnection(), debugMode); + }); + } + } +} \ No newline at end of file diff --git a/Kyoo.Tests/Library/TestContext.cs b/Kyoo.Tests/Library/TestContext.cs index c9a83ad0..e3cabc03 100644 --- a/Kyoo.Tests/Library/TestContext.cs +++ b/Kyoo.Tests/Library/TestContext.cs @@ -1,79 +1,79 @@ -using Kyoo.Models; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; - -namespace Kyoo.Tests -{ - /// - /// Class responsible to fill and create in memory databases for unit tests. - /// - public class TestContext - { - /// - /// The context's options that specify to use an in memory Sqlite database. - /// - private readonly DbContextOptions _context; - - /// - /// Create a new database and fill it with informations. - /// - public TestContext() - { - SqliteConnection connection = new("DataSource=:memory:"); - connection.Open(); - - try - { - _context = new DbContextOptionsBuilder() - .UseSqlite(connection) - .Options; - FillDatabase(); - } - finally - { - connection.Close(); - } - } - - /// - /// Fill the database with pre defined values using a clean context. - /// - private void FillDatabase() - { - using DatabaseContext context = new(_context); - context.Shows.Add(new Show - { - ID = 67, - Slug = "anohana", - Title = "Anohana: The Flower We Saw That Day", - Aliases = new[] - { - "Ano Hi Mita Hana no Namae o Bokutachi wa Mada Shiranai.", - "AnoHana", - "We Still Don't Know the Name of the Flower We Saw That Day." - }, - Overview = "When Yadomi Jinta was a child, he was a central piece in a group of close friends. " + - "In time, however, these childhood friends drifted apart, and when they became high " + - "school students, they had long ceased to think of each other as friends.", - Status = Status.Finished, - TrailerUrl = null, - StartYear = 2011, - EndYear = 2011, - Poster = "poster", - Logo = "logo", - Backdrop = "backdrop", - IsMovie = false, - Studio = null - }); - } - - /// - /// Get a new databse context connected to a in memory Sqlite databse. - /// - /// A valid DatabaseContext - public DatabaseContext New() - { - return new(_context); - } - } -} \ No newline at end of file +// using Kyoo.Models; +// using Microsoft.Data.Sqlite; +// using Microsoft.EntityFrameworkCore; +// +// namespace Kyoo.Tests +// { +// /// +// /// Class responsible to fill and create in memory databases for unit tests. +// /// +// public class TestContext +// { +// /// +// /// The context's options that specify to use an in memory Sqlite database. +// /// +// private readonly DbContextOptions _context; +// +// /// +// /// Create a new database and fill it with information. +// /// +// public TestContext() +// { +// SqliteConnection connection = new("DataSource=:memory:"); +// connection.Open(); +// +// try +// { +// _context = new DbContextOptionsBuilder() +// .UseSqlite(connection) +// .Options; +// FillDatabase(); +// } +// finally +// { +// connection.Close(); +// } +// } +// +// /// +// /// Fill the database with pre defined values using a clean context. +// /// +// private void FillDatabase() +// { +// using DatabaseContext context = new(_context); +// context.Shows.Add(new Show +// { +// ID = 67, +// Slug = "anohana", +// Title = "Anohana: The Flower We Saw That Day", +// Aliases = new[] +// { +// "Ano Hi Mita Hana no Namae o Bokutachi wa Mada Shiranai.", +// "AnoHana", +// "We Still Don't Know the Name of the Flower We Saw That Day." +// }, +// Overview = "When Yadomi Jinta was a child, he was a central piece in a group of close friends. " + +// "In time, however, these childhood friends drifted apart, and when they became high " + +// "school students, they had long ceased to think of each other as friends.", +// Status = Status.Finished, +// TrailerUrl = null, +// StartYear = 2011, +// EndYear = 2011, +// Poster = "poster", +// Logo = "logo", +// Backdrop = "backdrop", +// IsMovie = false, +// Studio = null +// }); +// } +// +// /// +// /// Get a new database context connected to a in memory Sqlite database. +// /// +// /// A valid DatabaseContext +// public DatabaseContext New() +// { +// return new(_context); +// } +// } +// } \ No newline at end of file diff --git a/Kyoo.sln b/Kyoo.sln index 0eb53fe3..79ee6e7d 100644 --- a/Kyoo.sln +++ b/Kyoo.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.CommonAPI", "Kyoo.Comm EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "Kyoo.Tests\Kyoo.Tests.csproj", "{D179D5FF-9F75-4B27-8E27-0DBDF1806611}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -29,5 +31,9 @@ Global {D179D5FF-9F75-4B27-8E27-0DBDF1806611}.Debug|Any CPU.Build.0 = Debug|Any CPU {D179D5FF-9F75-4B27-8E27-0DBDF1806611}.Release|Any CPU.ActiveCfg = Release|Any CPU {D179D5FF-9F75-4B27-8E27-0DBDF1806611}.Release|Any CPU.Build.0 = Release|Any CPU + {3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs index 43afd407..c1db8e46 100644 --- a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Kyoo.Models; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Controllers { @@ -20,10 +19,6 @@ namespace Kyoo.Controllers /// private readonly DatabaseContext _database; /// - /// A provider repository to handle externalID creation and deletion - /// - private readonly IProviderRepository _providers; - /// /// A lazy loaded library repository to validate queries (check if a library does exist) /// private readonly Lazy _libraries; @@ -44,18 +39,19 @@ namespace Kyoo.Controllers /// Create a new . /// /// The databse instance - /// A provider repository - /// A service provider to lazilly request a library, show or collection repository. + /// A lazy loaded library repository + /// A lazy loaded show repository + /// A lazy loaded collection repository public LibraryItemRepository(DatabaseContext database, - IProviderRepository providers, - IServiceProvider services) + Lazy libraries, + Lazy shows, + Lazy collections) : base(database) { _database = database; - _providers = providers; - _libraries = new Lazy(services.GetRequiredService); - _shows = new Lazy(services.GetRequiredService); - _collections = new Lazy(services.GetRequiredService); + _libraries = libraries; + _shows = shows; + _collections = collections; } diff --git a/Kyoo/Controllers/Repositories/PeopleRepository.cs b/Kyoo/Controllers/Repositories/PeopleRepository.cs index 526a3286..6de72a4b 100644 --- a/Kyoo/Controllers/Repositories/PeopleRepository.cs +++ b/Kyoo/Controllers/Repositories/PeopleRepository.cs @@ -36,15 +36,15 @@ namespace Kyoo.Controllers /// /// The database handle /// A provider repository - /// A service provider to lazy load a show repository + /// A lazy loaded show repository public PeopleRepository(DatabaseContext database, IProviderRepository providers, - IServiceProvider services) + Lazy shows) : base(database) { _database = database; _providers = providers; - _shows = new Lazy(services.GetRequiredService); + _shows = shows; } diff --git a/Kyoo/Controllers/Repositories/SeasonRepository.cs b/Kyoo/Controllers/Repositories/SeasonRepository.cs index e35042ad..b0a61c90 100644 --- a/Kyoo/Controllers/Repositories/SeasonRepository.cs +++ b/Kyoo/Controllers/Repositories/SeasonRepository.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Kyoo.Models; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Controllers { @@ -44,17 +43,17 @@ namespace Kyoo.Controllers /// The database handle that will be used /// A provider repository /// A show repository - /// A service provider to lazilly request an episode repository. + /// A lazy loaded episode repository. public SeasonRepository(DatabaseContext database, IProviderRepository providers, IShowRepository shows, - IServiceProvider services) + Lazy episodes) : base(database) { _database = database; _providers = providers; _shows = shows; - _episodes = new Lazy(services.GetRequiredService); + _episodes = episodes; } diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index 1129cd07..07d2cafd 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -5,7 +5,6 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Kyoo.Models; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Controllers { @@ -54,13 +53,15 @@ namespace Kyoo.Controllers /// A people repository /// A genres repository /// A provider repository - /// A service provider to lazilly request a season and an episode repository + /// A lazy loaded season repository + /// A lazy loaded episode repository public ShowRepository(DatabaseContext database, IStudioRepository studios, IPeopleRepository people, IGenreRepository genres, IProviderRepository providers, - IServiceProvider services) + Lazy seasons, + Lazy episodes) : base(database) { _database = database; @@ -68,8 +69,8 @@ namespace Kyoo.Controllers _people = people; _genres = genres; _providers = providers; - _seasons = new Lazy(services.GetRequiredService); - _episodes = new Lazy(services.GetRequiredService); + _seasons = seasons; + _episodes = episodes; } diff --git a/Kyoo/Controllers/TaskManager.cs b/Kyoo/Controllers/TaskManager.cs index e93c050f..a625dcf2 100644 --- a/Kyoo/Controllers/TaskManager.cs +++ b/Kyoo/Controllers/TaskManager.cs @@ -62,10 +62,10 @@ namespace Kyoo.Controllers IConfiguration configuration, ILogger logger) { - _tasks = tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList(); _container = container; _configuration = configuration.GetSection("scheduledTasks"); _logger = logger; + _tasks = tasks.Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList(); } @@ -179,8 +179,10 @@ namespace Kyoo.Controllers } /// - public void StartTask(string taskSlug, Dictionary arguments) + public void StartTask(string taskSlug, Dictionary arguments = null) { + arguments ??= new Dictionary(); + int index = _tasks.FindIndex(x => x.task.Slug == taskSlug); if (index == -1) throw new ItemNotFound($"No task found with the slug {taskSlug}"); @@ -216,7 +218,7 @@ namespace Kyoo.Controllers /// public void ReloadTasks() { - _tasks = _container.ResolveAll().Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList(); + _tasks = _container.Resolve>().Select(x => (x, DateTime.Now + GetTaskDelay(x.Slug))).ToList(); EnqueueStartupTasks(); } } diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs index d194a267..26e12c80 100644 --- a/Kyoo/CoreModule.cs +++ b/Kyoo/CoreModule.cs @@ -1,10 +1,14 @@ using Kyoo.Controllers; +using Kyoo.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.Configuration; using Unity; +using Unity.Lifetime; namespace Kyoo { /// - /// The core module ccontaining default implementations + /// The core module containing default implementations /// public class CoreModule : IPlugin { @@ -17,10 +21,60 @@ namespace Kyoo /// public string Description => "The core module containing default implementations."; - /// - public static void Configure(IUnityContainer container) + /// + public string[] Provides => new[] { - container.AddTask(); + $"{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)}" + }; + + /// + public string[] Requires => new[] + { + "DatabaseContext:" + }; + + /// + public void Configure(IUnityContainer container, IConfiguration config, IApplicationBuilder app, bool debugMode) + { + 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()); + + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + container.RegisterType(new HierarchicalLifetimeManager()); + + container.RegisterTask(); } } } \ No newline at end of file diff --git a/Kyoo/Models/DatabaseContext.cs b/Kyoo/Models/DatabaseContext.cs index 577e9903..caf8933e 100644 --- a/Kyoo/Models/DatabaseContext.cs +++ b/Kyoo/Models/DatabaseContext.cs @@ -7,17 +7,17 @@ using Kyoo.Models; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.ChangeTracking; -using Npgsql; namespace Kyoo { /// /// The database handle used for all local repositories. + /// This is an abstract class. It is meant to be implemented by plugins. This allow the core to be database agnostic. /// /// /// It should not be used directly, to access the database use a or repositories. /// - public class DatabaseContext : DbContext + public abstract class DatabaseContext : DbContext { /// /// All libraries of Kyoo. See . @@ -89,10 +89,6 @@ namespace Kyoo /// public DatabaseContext() { - NpgsqlConnection.GlobalTypeMapper.MapEnum(); - NpgsqlConnection.GlobalTypeMapper.MapEnum(); - NpgsqlConnection.GlobalTypeMapper.MapEnum(); - ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; ChangeTracker.LazyLoadingEnabled = false; } @@ -100,7 +96,7 @@ namespace Kyoo /// /// Create a new . /// - /// Connection options to use (witch databse provider to use, connection strings...) + /// Connection options to use (witch database provider to use, connection strings...) public DatabaseContext(DbContextOptions options) : base(options) { @@ -116,10 +112,6 @@ namespace Kyoo { base.OnModelCreating(modelBuilder); - modelBuilder.HasPostgresEnum(); - modelBuilder.HasPostgresEnum(); - modelBuilder.HasPostgresEnum(); - modelBuilder.Entity() .Property(t => t.IsDefault) .ValueGeneratedNever(); @@ -467,13 +459,9 @@ namespace Kyoo /// /// Check if the exception is a duplicated exception. /// - /// WARNING: this only works for PostgreSQL /// The exception to check /// True if the exception is a duplicate exception. False otherwise - private static bool IsDuplicateException(Exception ex) - { - return ex.InnerException is PostgresException {SqlState: PostgresErrorCodes.UniqueViolation}; - } + protected abstract bool IsDuplicateException(Exception ex); /// /// Delete every changes that are on this context. diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.Designer.cs b/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.Designer.cs deleted file mode 100644 index c27925c9..00000000 --- a/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.Designer.cs +++ /dev/null @@ -1,785 +0,0 @@ -// -using System; -using Kyoo; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace Kyoo.Models.DatabaseMigrations.Internal -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20210420221509_Initial")] - partial class Initial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasPostgresEnum(null, "item_type", new[] { "show", "movie", "collection" }) - .HasPostgresEnum(null, "status", new[] { "finished", "airing", "planned", "unknown" }) - .HasPostgresEnum(null, "stream_type", new[] { "unknown", "video", "audio", "subtitle", "attachment" }) - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.3") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - modelBuilder.Entity("Kyoo.Models.Collection", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Collections"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("AbsoluteNumber") - .HasColumnType("integer"); - - b.Property("EpisodeNumber") - .HasColumnType("integer"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("ReleaseDate") - .HasColumnType("timestamp without time zone"); - - b.Property("Runtime") - .HasColumnType("integer"); - - b.Property("SeasonID") - .HasColumnType("integer"); - - b.Property("SeasonNumber") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Thumb") - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("SeasonID"); - - b.HasIndex("ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") - .IsUnique(); - - b.ToTable("Episodes"); - }); - - modelBuilder.Entity("Kyoo.Models.Genre", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Genres"); - }); - - modelBuilder.Entity("Kyoo.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Paths") - .HasColumnType("text[]"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Libraries"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.MetadataID", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("DataID") - .HasColumnType("text"); - - b.Property("EpisodeID") - .HasColumnType("integer"); - - b.Property("Link") - .HasColumnType("text"); - - b.Property("PeopleID") - .HasColumnType("integer"); - - b.Property("ProviderID") - .HasColumnType("integer"); - - b.Property("SeasonID") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("EpisodeID"); - - b.HasIndex("PeopleID"); - - b.HasIndex("ProviderID"); - - b.HasIndex("SeasonID"); - - b.HasIndex("ShowID"); - - b.ToTable("MetadataIds"); - }); - - modelBuilder.Entity("Kyoo.Models.People", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("People"); - }); - - modelBuilder.Entity("Kyoo.Models.PeopleRole", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("PeopleID") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("text"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("PeopleID"); - - b.HasIndex("ShowID"); - - b.ToTable("PeopleRoles"); - }); - - modelBuilder.Entity("Kyoo.Models.Provider", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("LogoExtension") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Providers"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("SeasonNumber") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("Year") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("ShowID", "SeasonNumber") - .IsUnique(); - - b.ToTable("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Aliases") - .HasColumnType("text[]"); - - b.Property("Backdrop") - .HasColumnType("text"); - - b.Property("EndYear") - .HasColumnType("integer"); - - b.Property("IsMovie") - .HasColumnType("boolean"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.Property("StartYear") - .HasColumnType("integer"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("StudioID") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("TrailerUrl") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.HasIndex("StudioID"); - - b.ToTable("Shows"); - }); - - modelBuilder.Entity("Kyoo.Models.Studio", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Studios"); - }); - - modelBuilder.Entity("Kyoo.Models.Track", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Codec") - .HasColumnType("text"); - - b.Property("EpisodeID") - .HasColumnType("integer"); - - b.Property("IsDefault") - .HasColumnType("boolean"); - - b.Property("IsExternal") - .HasColumnType("boolean"); - - b.Property("IsForced") - .HasColumnType("boolean"); - - b.Property("Language") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("TrackIndex") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("EpisodeID", "Type", "Language", "TrackIndex", "IsForced") - .IsUnique(); - - b.ToTable("Tracks"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.HasOne("Kyoo.Models.Season", "Season") - .WithMany("Episodes") - .HasForeignKey("SeasonID"); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("Episodes") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Collection", "First") - .WithMany("ShowLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Second") - .WithMany("CollectionLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("CollectionLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Collection", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("ProviderLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Provider", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("ShowLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Show", "First") - .WithMany("GenreLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Genre", "Second") - .WithMany("ShowLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.MetadataID", b => - { - b.HasOne("Kyoo.Models.Episode", "Episode") - .WithMany("ExternalIDs") - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.People", "People") - .WithMany("ExternalIDs") - .HasForeignKey("PeopleID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.Provider", "Provider") - .WithMany("MetadataLinks") - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Season", "Season") - .WithMany("ExternalIDs") - .HasForeignKey("SeasonID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("ExternalIDs") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Episode"); - - b.Navigation("People"); - - b.Navigation("Provider"); - - b.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.PeopleRole", b => - { - b.HasOne("Kyoo.Models.People", "People") - .WithMany("Roles") - .HasForeignKey("PeopleID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("People") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("People"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("Seasons") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.HasOne("Kyoo.Models.Studio", "Studio") - .WithMany("Shows") - .HasForeignKey("StudioID"); - - b.Navigation("Studio"); - }); - - modelBuilder.Entity("Kyoo.Models.Track", b => - { - b.HasOne("Kyoo.Models.Episode", "Episode") - .WithMany("Tracks") - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Episode"); - }); - - modelBuilder.Entity("Kyoo.Models.Collection", b => - { - b.Navigation("LibraryLinks"); - - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Tracks"); - }); - - modelBuilder.Entity("Kyoo.Models.Genre", b => - { - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Library", b => - { - b.Navigation("CollectionLinks"); - - b.Navigation("ProviderLinks"); - - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.People", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Roles"); - }); - - modelBuilder.Entity("Kyoo.Models.Provider", b => - { - b.Navigation("LibraryLinks"); - - b.Navigation("MetadataLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.Navigation("CollectionLinks"); - - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - - b.Navigation("GenreLinks"); - - b.Navigation("LibraryLinks"); - - b.Navigation("People"); - - b.Navigation("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Models.Studio", b => - { - b.Navigation("Shows"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.cs b/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.cs deleted file mode 100644 index 56051cb1..00000000 --- a/Kyoo/Models/DatabaseMigrations/Internal/20210420221509_Initial.cs +++ /dev/null @@ -1,607 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace Kyoo.Models.DatabaseMigrations.Internal -{ - public partial class Initial : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterDatabase() - .Annotation("Npgsql:Enum:item_type", "show,movie,collection") - .Annotation("Npgsql:Enum:status", "finished,airing,planned,unknown") - .Annotation("Npgsql:Enum:stream_type", "unknown,video,audio,subtitle,attachment"); - - migrationBuilder.CreateTable( - name: "Collections", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true), - Poster = table.Column(type: "text", nullable: true), - Overview = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Collections", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "Genres", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Genres", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "Libraries", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true), - Paths = table.Column(type: "text[]", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Libraries", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "People", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true), - Poster = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_People", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "Providers", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true), - Logo = table.Column(type: "text", nullable: true), - LogoExtension = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Providers", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "Studios", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Name = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Studios", x => x.ID); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - FirstID = table.Column(type: "integer", nullable: false), - SecondID = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => new { x.FirstID, x.SecondID }); - table.ForeignKey( - name: "FK_Link_Collections_SecondID", - column: x => x.SecondID, - principalTable: "Collections", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Link_Libraries_FirstID", - column: x => x.FirstID, - principalTable: "Libraries", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - FirstID = table.Column(type: "integer", nullable: false), - SecondID = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => new { x.FirstID, x.SecondID }); - table.ForeignKey( - name: "FK_Link_Libraries_FirstID", - column: x => x.FirstID, - principalTable: "Libraries", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Link_Providers_SecondID", - column: x => x.SecondID, - principalTable: "Providers", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Shows", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - Slug = table.Column(type: "text", nullable: false), - Title = table.Column(type: "text", nullable: true), - Aliases = table.Column(type: "text[]", nullable: true), - Path = table.Column(type: "text", nullable: true), - Overview = table.Column(type: "text", nullable: true), - Status = table.Column(type: "integer", nullable: true), - TrailerUrl = table.Column(type: "text", nullable: true), - StartYear = table.Column(type: "integer", nullable: true), - EndYear = table.Column(type: "integer", nullable: true), - Poster = table.Column(type: "text", nullable: true), - Logo = table.Column(type: "text", nullable: true), - Backdrop = table.Column(type: "text", nullable: true), - IsMovie = table.Column(type: "boolean", nullable: false), - StudioID = table.Column(type: "integer", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Shows", x => x.ID); - table.ForeignKey( - name: "FK_Shows_Studios_StudioID", - column: x => x.StudioID, - principalTable: "Studios", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - FirstID = table.Column(type: "integer", nullable: false), - SecondID = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => new { x.FirstID, x.SecondID }); - table.ForeignKey( - name: "FK_Link_Collections_FirstID", - column: x => x.FirstID, - principalTable: "Collections", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Link_Shows_SecondID", - column: x => x.SecondID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - FirstID = table.Column(type: "integer", nullable: false), - SecondID = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => new { x.FirstID, x.SecondID }); - table.ForeignKey( - name: "FK_Link_Libraries_FirstID", - column: x => x.FirstID, - principalTable: "Libraries", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Link_Shows_SecondID", - column: x => x.SecondID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Link", - columns: table => new - { - FirstID = table.Column(type: "integer", nullable: false), - SecondID = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Link", x => new { x.FirstID, x.SecondID }); - table.ForeignKey( - name: "FK_Link_Genres_SecondID", - column: x => x.SecondID, - principalTable: "Genres", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_Link_Shows_FirstID", - column: x => x.FirstID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "PeopleRoles", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - PeopleID = table.Column(type: "integer", nullable: false), - ShowID = table.Column(type: "integer", nullable: false), - Role = table.Column(type: "text", nullable: true), - Type = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_PeopleRoles", x => x.ID); - table.ForeignKey( - name: "FK_PeopleRoles_People_PeopleID", - column: x => x.PeopleID, - principalTable: "People", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_PeopleRoles_Shows_ShowID", - column: x => x.ShowID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Seasons", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ShowID = table.Column(type: "integer", nullable: false), - SeasonNumber = table.Column(type: "integer", nullable: false), - Title = table.Column(type: "text", nullable: true), - Overview = table.Column(type: "text", nullable: true), - Year = table.Column(type: "integer", nullable: true), - Poster = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_Seasons", x => x.ID); - table.ForeignKey( - name: "FK_Seasons_Shows_ShowID", - column: x => x.ShowID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Episodes", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ShowID = table.Column(type: "integer", nullable: false), - SeasonID = table.Column(type: "integer", nullable: true), - SeasonNumber = table.Column(type: "integer", nullable: false), - EpisodeNumber = table.Column(type: "integer", nullable: false), - AbsoluteNumber = table.Column(type: "integer", nullable: false), - Path = table.Column(type: "text", nullable: true), - Thumb = table.Column(type: "text", nullable: true), - Title = table.Column(type: "text", nullable: true), - Overview = table.Column(type: "text", nullable: true), - ReleaseDate = table.Column(type: "timestamp without time zone", nullable: true), - Runtime = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Episodes", x => x.ID); - table.ForeignKey( - name: "FK_Episodes_Seasons_SeasonID", - column: x => x.SeasonID, - principalTable: "Seasons", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_Episodes_Shows_ShowID", - column: x => x.ShowID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "MetadataIds", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - ProviderID = table.Column(type: "integer", nullable: false), - ShowID = table.Column(type: "integer", nullable: true), - EpisodeID = table.Column(type: "integer", nullable: true), - SeasonID = table.Column(type: "integer", nullable: true), - PeopleID = table.Column(type: "integer", nullable: true), - DataID = table.Column(type: "text", nullable: true), - Link = table.Column(type: "text", nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_MetadataIds", x => x.ID); - table.ForeignKey( - name: "FK_MetadataIds_Episodes_EpisodeID", - column: x => x.EpisodeID, - principalTable: "Episodes", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MetadataIds_People_PeopleID", - column: x => x.PeopleID, - principalTable: "People", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MetadataIds_Providers_ProviderID", - column: x => x.ProviderID, - principalTable: "Providers", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MetadataIds_Seasons_SeasonID", - column: x => x.SeasonID, - principalTable: "Seasons", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_MetadataIds_Shows_ShowID", - column: x => x.ShowID, - principalTable: "Shows", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "Tracks", - columns: table => new - { - ID = table.Column(type: "integer", nullable: false) - .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), - EpisodeID = table.Column(type: "integer", nullable: false), - TrackIndex = table.Column(type: "integer", nullable: false), - IsDefault = table.Column(type: "boolean", nullable: false), - IsForced = table.Column(type: "boolean", nullable: false), - IsExternal = table.Column(type: "boolean", nullable: false), - Title = table.Column(type: "text", nullable: true), - Language = table.Column(type: "text", nullable: true), - Codec = table.Column(type: "text", nullable: true), - Path = table.Column(type: "text", nullable: true), - Type = table.Column(type: "integer", nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_Tracks", x => x.ID); - table.ForeignKey( - name: "FK_Tracks_Episodes_EpisodeID", - column: x => x.EpisodeID, - principalTable: "Episodes", - principalColumn: "ID", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateIndex( - name: "IX_Collections_Slug", - table: "Collections", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Episodes_SeasonID", - table: "Episodes", - column: "SeasonID"); - - migrationBuilder.CreateIndex( - name: "IX_Episodes_ShowID_SeasonNumber_EpisodeNumber_AbsoluteNumber", - table: "Episodes", - columns: new[] { "ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Genres_Slug", - table: "Genres", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Libraries_Slug", - table: "Libraries", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Link_SecondID", - table: "Link", - column: "SecondID"); - - migrationBuilder.CreateIndex( - name: "IX_Link_SecondID", - table: "Link", - column: "SecondID"); - - migrationBuilder.CreateIndex( - name: "IX_Link_SecondID", - table: "Link", - column: "SecondID"); - - migrationBuilder.CreateIndex( - name: "IX_Link_SecondID", - table: "Link", - column: "SecondID"); - - migrationBuilder.CreateIndex( - name: "IX_Link_SecondID", - table: "Link", - column: "SecondID"); - - migrationBuilder.CreateIndex( - name: "IX_MetadataIds_EpisodeID", - table: "MetadataIds", - column: "EpisodeID"); - - migrationBuilder.CreateIndex( - name: "IX_MetadataIds_PeopleID", - table: "MetadataIds", - column: "PeopleID"); - - migrationBuilder.CreateIndex( - name: "IX_MetadataIds_ProviderID", - table: "MetadataIds", - column: "ProviderID"); - - migrationBuilder.CreateIndex( - name: "IX_MetadataIds_SeasonID", - table: "MetadataIds", - column: "SeasonID"); - - migrationBuilder.CreateIndex( - name: "IX_MetadataIds_ShowID", - table: "MetadataIds", - column: "ShowID"); - - migrationBuilder.CreateIndex( - name: "IX_People_Slug", - table: "People", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_PeopleRoles_PeopleID", - table: "PeopleRoles", - column: "PeopleID"); - - migrationBuilder.CreateIndex( - name: "IX_PeopleRoles_ShowID", - table: "PeopleRoles", - column: "ShowID"); - - migrationBuilder.CreateIndex( - name: "IX_Providers_Slug", - table: "Providers", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Seasons_ShowID_SeasonNumber", - table: "Seasons", - columns: new[] { "ShowID", "SeasonNumber" }, - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Shows_Slug", - table: "Shows", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Shows_StudioID", - table: "Shows", - column: "StudioID"); - - migrationBuilder.CreateIndex( - name: "IX_Studios_Slug", - table: "Studios", - column: "Slug", - unique: true); - - migrationBuilder.CreateIndex( - name: "IX_Tracks_EpisodeID_Type_Language_TrackIndex_IsForced", - table: "Tracks", - columns: new[] { "EpisodeID", "Type", "Language", "TrackIndex", "IsForced" }, - unique: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "Link"); - - migrationBuilder.DropTable( - name: "MetadataIds"); - - migrationBuilder.DropTable( - name: "PeopleRoles"); - - migrationBuilder.DropTable( - name: "Tracks"); - - migrationBuilder.DropTable( - name: "Collections"); - - migrationBuilder.DropTable( - name: "Libraries"); - - migrationBuilder.DropTable( - name: "Genres"); - - migrationBuilder.DropTable( - name: "Providers"); - - migrationBuilder.DropTable( - name: "People"); - - migrationBuilder.DropTable( - name: "Episodes"); - - migrationBuilder.DropTable( - name: "Seasons"); - - migrationBuilder.DropTable( - name: "Shows"); - - migrationBuilder.DropTable( - name: "Studios"); - } - } -} diff --git a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs b/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs deleted file mode 100644 index 11d6b186..00000000 --- a/Kyoo/Models/DatabaseMigrations/Internal/DatabaseContextModelSnapshot.cs +++ /dev/null @@ -1,783 +0,0 @@ -// -using System; -using Kyoo; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; - -namespace Kyoo.Models.DatabaseMigrations.Internal -{ - [DbContext(typeof(DatabaseContext))] - partial class DatabaseContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasPostgresEnum(null, "item_type", new[] { "show", "movie", "collection" }) - .HasPostgresEnum(null, "status", new[] { "finished", "airing", "planned", "unknown" }) - .HasPostgresEnum(null, "stream_type", new[] { "unknown", "video", "audio", "subtitle", "attachment" }) - .HasAnnotation("Relational:MaxIdentifierLength", 63) - .HasAnnotation("ProductVersion", "5.0.3") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - modelBuilder.Entity("Kyoo.Models.Collection", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Collections"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("AbsoluteNumber") - .HasColumnType("integer"); - - b.Property("EpisodeNumber") - .HasColumnType("integer"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("ReleaseDate") - .HasColumnType("timestamp without time zone"); - - b.Property("Runtime") - .HasColumnType("integer"); - - b.Property("SeasonID") - .HasColumnType("integer"); - - b.Property("SeasonNumber") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Thumb") - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("SeasonID"); - - b.HasIndex("ShowID", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") - .IsUnique(); - - b.ToTable("Episodes"); - }); - - modelBuilder.Entity("Kyoo.Models.Genre", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Genres"); - }); - - modelBuilder.Entity("Kyoo.Models.Library", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Paths") - .HasColumnType("text[]"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Libraries"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.Property("FirstID") - .HasColumnType("integer"); - - b.Property("SecondID") - .HasColumnType("integer"); - - b.HasKey("FirstID", "SecondID"); - - b.HasIndex("SecondID"); - - b.ToTable("Link"); - }); - - modelBuilder.Entity("Kyoo.Models.MetadataID", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("DataID") - .HasColumnType("text"); - - b.Property("EpisodeID") - .HasColumnType("integer"); - - b.Property("Link") - .HasColumnType("text"); - - b.Property("PeopleID") - .HasColumnType("integer"); - - b.Property("ProviderID") - .HasColumnType("integer"); - - b.Property("SeasonID") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("EpisodeID"); - - b.HasIndex("PeopleID"); - - b.HasIndex("ProviderID"); - - b.HasIndex("SeasonID"); - - b.HasIndex("ShowID"); - - b.ToTable("MetadataIds"); - }); - - modelBuilder.Entity("Kyoo.Models.People", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("People"); - }); - - modelBuilder.Entity("Kyoo.Models.PeopleRole", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("PeopleID") - .HasColumnType("integer"); - - b.Property("Role") - .HasColumnType("text"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("PeopleID"); - - b.HasIndex("ShowID"); - - b.ToTable("PeopleRoles"); - }); - - modelBuilder.Entity("Kyoo.Models.Provider", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("LogoExtension") - .HasColumnType("text"); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Providers"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("SeasonNumber") - .HasColumnType("integer"); - - b.Property("ShowID") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("Year") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("ShowID", "SeasonNumber") - .IsUnique(); - - b.ToTable("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Aliases") - .HasColumnType("text[]"); - - b.Property("Backdrop") - .HasColumnType("text"); - - b.Property("EndYear") - .HasColumnType("integer"); - - b.Property("IsMovie") - .HasColumnType("boolean"); - - b.Property("Logo") - .HasColumnType("text"); - - b.Property("Overview") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("Poster") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.Property("StartYear") - .HasColumnType("integer"); - - b.Property("Status") - .HasColumnType("integer"); - - b.Property("StudioID") - .HasColumnType("integer"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("TrailerUrl") - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.HasIndex("StudioID"); - - b.ToTable("Shows"); - }); - - modelBuilder.Entity("Kyoo.Models.Studio", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Name") - .HasColumnType("text"); - - b.Property("Slug") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("ID"); - - b.HasIndex("Slug") - .IsUnique(); - - b.ToTable("Studios"); - }); - - modelBuilder.Entity("Kyoo.Models.Track", b => - { - b.Property("ID") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); - - b.Property("Codec") - .HasColumnType("text"); - - b.Property("EpisodeID") - .HasColumnType("integer"); - - b.Property("IsDefault") - .HasColumnType("boolean"); - - b.Property("IsExternal") - .HasColumnType("boolean"); - - b.Property("IsForced") - .HasColumnType("boolean"); - - b.Property("Language") - .HasColumnType("text"); - - b.Property("Path") - .HasColumnType("text"); - - b.Property("Title") - .HasColumnType("text"); - - b.Property("TrackIndex") - .HasColumnType("integer"); - - b.Property("Type") - .HasColumnType("integer"); - - b.HasKey("ID"); - - b.HasIndex("EpisodeID", "Type", "Language", "TrackIndex", "IsForced") - .IsUnique(); - - b.ToTable("Tracks"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.HasOne("Kyoo.Models.Season", "Season") - .WithMany("Episodes") - .HasForeignKey("SeasonID"); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("Episodes") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Collection", "First") - .WithMany("ShowLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Second") - .WithMany("CollectionLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("CollectionLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Collection", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("ProviderLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Provider", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Library", "First") - .WithMany("ShowLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Second") - .WithMany("LibraryLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.Link", b => - { - b.HasOne("Kyoo.Models.Show", "First") - .WithMany("GenreLinks") - .HasForeignKey("FirstID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Genre", "Second") - .WithMany("ShowLinks") - .HasForeignKey("SecondID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("First"); - - b.Navigation("Second"); - }); - - modelBuilder.Entity("Kyoo.Models.MetadataID", b => - { - b.HasOne("Kyoo.Models.Episode", "Episode") - .WithMany("ExternalIDs") - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.People", "People") - .WithMany("ExternalIDs") - .HasForeignKey("PeopleID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.Provider", "Provider") - .WithMany("MetadataLinks") - .HasForeignKey("ProviderID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Season", "Season") - .WithMany("ExternalIDs") - .HasForeignKey("SeasonID") - .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("ExternalIDs") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade); - - b.Navigation("Episode"); - - b.Navigation("People"); - - b.Navigation("Provider"); - - b.Navigation("Season"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.PeopleRole", b => - { - b.HasOne("Kyoo.Models.People", "People") - .WithMany("Roles") - .HasForeignKey("PeopleID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("People") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("People"); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.HasOne("Kyoo.Models.Show", "Show") - .WithMany("Seasons") - .HasForeignKey("ShowID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Show"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.HasOne("Kyoo.Models.Studio", "Studio") - .WithMany("Shows") - .HasForeignKey("StudioID"); - - b.Navigation("Studio"); - }); - - modelBuilder.Entity("Kyoo.Models.Track", b => - { - b.HasOne("Kyoo.Models.Episode", "Episode") - .WithMany("Tracks") - .HasForeignKey("EpisodeID") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Episode"); - }); - - modelBuilder.Entity("Kyoo.Models.Collection", b => - { - b.Navigation("LibraryLinks"); - - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Episode", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Tracks"); - }); - - modelBuilder.Entity("Kyoo.Models.Genre", b => - { - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Library", b => - { - b.Navigation("CollectionLinks"); - - b.Navigation("ProviderLinks"); - - b.Navigation("ShowLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.People", b => - { - b.Navigation("ExternalIDs"); - - b.Navigation("Roles"); - }); - - modelBuilder.Entity("Kyoo.Models.Provider", b => - { - b.Navigation("LibraryLinks"); - - b.Navigation("MetadataLinks"); - }); - - modelBuilder.Entity("Kyoo.Models.Season", b => - { - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - }); - - modelBuilder.Entity("Kyoo.Models.Show", b => - { - b.Navigation("CollectionLinks"); - - b.Navigation("Episodes"); - - b.Navigation("ExternalIDs"); - - b.Navigation("GenreLinks"); - - b.Navigation("LibraryLinks"); - - b.Navigation("People"); - - b.Navigation("Seasons"); - }); - - modelBuilder.Entity("Kyoo.Models.Studio", b => - { - b.Navigation("Shows"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 5f259d24..e5493f92 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -21,6 +21,7 @@ using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Unity; +using Unity.Lifetime; namespace Kyoo { @@ -147,46 +148,11 @@ namespace Kyoo AllowedOrigins = { new Uri(publicUrl).GetLeftPart(UriPartial.Authority) } }); - - // TODO Add custom method to the service container and expose those methods to the plugin - // TODO Add for example a AddRepository that will automatically register the complex interface, the IRepository and the IBaseRepository - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddScoped(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); - services.AddHostedService(provider => (TaskManager)provider.GetService()); + services.AddScoped(); } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IUnityContainer container) + + public void Configure(IUnityContainer container, IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { @@ -249,8 +215,10 @@ namespace Kyoo spa.UseAngularCliServer("start"); }); - CoreModule.Configure(container); - container.Resolve().ReloadTasks(); + 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. } } } diff --git a/Kyoo/Tasks/Crawler.cs b/Kyoo/Tasks/Crawler.cs index d86f54d9..7fc5699c 100644 --- a/Kyoo/Tasks/Crawler.cs +++ b/Kyoo/Tasks/Crawler.cs @@ -7,11 +7,12 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using Kyoo.Controllers; using Kyoo.Models.Attributes; using Kyoo.Models.Exceptions; using Microsoft.Extensions.DependencyInjection; -namespace Kyoo.Controllers +namespace Kyoo.Tasks { public class Crawler : ITask {