From 13ad35a9ac8430b3436682864d6480cc4e80e1c1 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 02:17:31 +0200 Subject: [PATCH 1/9] Add tv specifics genres --- back/src/Kyoo.Abstractions/Models/Genre.cs | 6 ++++ .../implementations/themoviedatabase.py | 31 +++++++++++++------ scanner/providers/types/genre.py | 6 ++++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/back/src/Kyoo.Abstractions/Models/Genre.cs b/back/src/Kyoo.Abstractions/Models/Genre.cs index fa2af8cb..e2e4f6a9 100644 --- a/back/src/Kyoo.Abstractions/Models/Genre.cs +++ b/back/src/Kyoo.Abstractions/Models/Genre.cs @@ -41,4 +41,10 @@ public enum Genre Thriller, War, Western, + Kids, + News, + Reality, + Soap, + Talk, + Politics, } diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index 27d33bd9..3b86e3ab 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -56,12 +56,31 @@ class TheMovieDatabase(Provider): 53: Genre.THRILLER, 10752: Genre.WAR, 37: Genre.WESTERN, + 10759: [Genre.ACTION, Genre.ADVENTURE], + 10762: Genre.KIDS, + 10763: Genre.NEWS, + 10764: Genre.REALITY, + 10765: [Genre.SCIENCE_FICTION, Genre.FANTASY], + 10766: Genre.SOAP, + 10767: Genre.TALK, + 10768: [Genre.WAR, Genre.POLITICS], } @property def name(self) -> str: return "themoviedatabase" + def process_genres(self, genres) -> list[Genre]: + def flatten(x: Genre | list[Genre]) -> list[Genre]: + if isinstance(x, list): + return [j for i in x for j in flatten(i)] + return [x] + return flatten([ + self.genre_map[x["id"]] + for x in genres + if x["id"] in self.genre_map + ]) + def get_languages(self, *args): return self._languages + list(args) @@ -154,11 +173,7 @@ class TheMovieDatabase(Provider): rating=round(float(movie["vote_average"]) * 10), runtime=int(movie["runtime"]) if movie["runtime"] is not None else None, studios=[self.to_studio(x) for x in movie["production_companies"]], - genres=[ - self.genre_map[x["id"]] - for x in movie["genres"] - if x["id"] in self.genre_map - ], + genres=self.process_genres(movie["genres"]), external_id=( { self.name: MetadataID( @@ -260,11 +275,7 @@ class TheMovieDatabase(Provider): else ShowStatus.FINISHED, rating=round(float(show["vote_average"]) * 10), studios=[self.to_studio(x) for x in show["production_companies"]], - genres=[ - self.genre_map[x["id"]] - for x in show["genres"] - if x["id"] in self.genre_map - ], + genres=self.process_genres(show["genres"]), external_id={ self.name: MetadataID( show["id"], f"https://www.themoviedb.org/tv/{show['id']}" diff --git a/scanner/providers/types/genre.py b/scanner/providers/types/genre.py index 287c07a4..d596a2f2 100644 --- a/scanner/providers/types/genre.py +++ b/scanner/providers/types/genre.py @@ -20,6 +20,12 @@ class Genre(str, Enum): THRILLER = "Thriller" WAR = "War" WESTERN = "Western" + KIDS = "Kids" + NEWS = "News" + REALITY = "Reality" + SOAP = "Soap" + TALK = "Talk" + POLITICS = "Politics" def to_kyoo(self): return self.value From 9bd1e50de3ada1d18a70cc91857dc1aa44c4cd7f Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 04:25:58 +0200 Subject: [PATCH 2/9] Delete usless plugin/startup handling --- back/Dockerfile | 1 - back/Dockerfile.dev | 1 - back/Dockerfile.migrations | 1 - back/Kyoo.sln | 6 - back/ef.rsp | 2 - back/src/Directory.Build.props | 1 + .../Kyoo.Abstractions/Controllers/IPlugin.cs | 65 ---- .../Controllers/IPluginManager.cs | 69 ---- .../Controllers/StartupAction.cs | 270 --------------- .../Kyoo.Abstractions.csproj | 1 - .../AuthenticationModule.cs | 78 ++--- .../Kyoo.Authentication.csproj | 5 +- .../Kyoo.Core/Controllers/LibraryManager.cs | 6 +- .../Controllers/ThumbnailsManager.cs | 2 +- back/src/Kyoo.Core/CoreModule.cs | 131 ++----- .../Kyoo.Core/Extensions/ServiceExtensions.cs | 86 +++++ back/src/Kyoo.Core/Kyoo.Core.csproj | 13 +- back/src/Kyoo.Core/Program.cs | 109 ++++++ back/src/Kyoo.Host/Application.cs | 195 ----------- .../src/Kyoo.Host/Contollers/PluginManager.cs | 92 ----- back/src/Kyoo.Host/HostModule.cs | 60 ---- back/src/Kyoo.Host/Kyoo.Host.csproj | 33 -- back/src/Kyoo.Host/PluginsStartup.cs | 195 ----------- back/src/Kyoo.Host/Program.cs | 48 --- .../Kyoo.Meilisearch/Kyoo.Meilisearch.csproj | 1 - .../src/Kyoo.Meilisearch/MeilisearchModule.cs | 22 +- .../Kyoo.Postgresql/Kyoo.Postgresql.csproj | 1 - .../Migrations/20240324174638_UseDateOnly.cs | 325 +++++++++--------- back/src/Kyoo.Postgresql/PostgresContext.cs | 22 -- back/src/Kyoo.Postgresql/PostgresModule.cs | 35 +- back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj | 1 - back/src/Kyoo.RabbitMq/RabbitMqModule.cs | 41 +-- back/src/Kyoo.Swagger/Kyoo.Swagger.csproj | 1 + back/src/Kyoo.Swagger/SwaggerModule.cs | 43 +-- 34 files changed, 478 insertions(+), 1484 deletions(-) delete mode 100644 back/src/Kyoo.Abstractions/Controllers/IPlugin.cs delete mode 100644 back/src/Kyoo.Abstractions/Controllers/IPluginManager.cs delete mode 100644 back/src/Kyoo.Abstractions/Controllers/StartupAction.cs create mode 100644 back/src/Kyoo.Core/Extensions/ServiceExtensions.cs create mode 100644 back/src/Kyoo.Core/Program.cs delete mode 100644 back/src/Kyoo.Host/Application.cs delete mode 100644 back/src/Kyoo.Host/Contollers/PluginManager.cs delete mode 100644 back/src/Kyoo.Host/HostModule.cs delete mode 100644 back/src/Kyoo.Host/Kyoo.Host.csproj delete mode 100644 back/src/Kyoo.Host/PluginsStartup.cs delete mode 100644 back/src/Kyoo.Host/Program.cs diff --git a/back/Dockerfile b/back/Dockerfile index 29cccc4d..4412eefa 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -8,7 +8,6 @@ COPY src/Directory.Build.props src/Directory.Build.props COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj -COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj diff --git a/back/Dockerfile.dev b/back/Dockerfile.dev index 19be75df..2081618b 100644 --- a/back/Dockerfile.dev +++ b/back/Dockerfile.dev @@ -8,7 +8,6 @@ COPY src/Directory.Build.props src/Directory.Build.props COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj -COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj diff --git a/back/Dockerfile.migrations b/back/Dockerfile.migrations index 4018eb9f..ca2fa1a1 100644 --- a/back/Dockerfile.migrations +++ b/back/Dockerfile.migrations @@ -11,7 +11,6 @@ COPY src/Directory.Build.props src/Directory.Build.props COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj -COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj diff --git a/back/Kyoo.sln b/back/Kyoo.sln index d8aac686..1c1c9fd5 100644 --- a/back/Kyoo.sln +++ b/back/Kyoo.sln @@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host", "src\Kyoo.Host\Kyoo.Host.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.RabbitMq", "src\Kyoo.RabbitMq\Kyoo.RabbitMq.csproj", "{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}" @@ -54,10 +52,6 @@ Global {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.Build.0 = Debug|Any CPU {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.ActiveCfg = Release|Any CPU {7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.Build.0 = Release|Any CPU - {0938459E-2E2B-457F-8120-7D8CA93866A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0938459E-2E2B-457F-8120-7D8CA93866A6}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0938459E-2E2B-457F-8120-7D8CA93866A6}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0938459E-2E2B-457F-8120-7D8CA93866A6}.Release|Any CPU.Build.0 = Release|Any CPU {F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.Build.0 = Debug|Any CPU {F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/back/ef.rsp b/back/ef.rsp index fda0e4f6..4023d566 100644 --- a/back/ef.rsp +++ b/back/ef.rsp @@ -1,4 +1,2 @@ --project src/Kyoo.Postgresql/Kyoo.Postgresql.csproj ---msbuildprojectextensionspath -out/obj/Kyoo.Postgresql diff --git a/back/src/Directory.Build.props b/back/src/Directory.Build.props index 081a7d9b..7175735b 100644 --- a/back/src/Directory.Build.props +++ b/back/src/Directory.Build.props @@ -2,6 +2,7 @@ net8.0 default + enable Kyoo Kyoo Copyright (c) Kyoo diff --git a/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs b/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs deleted file mode 100644 index a227f6e9..00000000 --- a/back/src/Kyoo.Abstractions/Controllers/IPlugin.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.Collections.Generic; -using Autofac; -using Microsoft.Extensions.DependencyInjection; - -namespace Kyoo.Abstractions.Controllers; - -/// -/// A common interface used to discord plugins -/// -/// -/// You can inject services in the IPlugin constructor. -/// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment. -/// -public interface IPlugin -{ - /// - /// The name of the plugin - /// - string Name { get; } - - /// - /// An optional configuration step to allow a plugin to change asp net configurations. - /// - /// - IEnumerable ConfigureSteps => ArraySegment.Empty; - - /// - /// A configure method that will be run on plugin's startup. - /// - /// The autofac service container to register services. - void Configure(ContainerBuilder builder) - { - // Skipped - } - - /// - /// A configure method that will be run on plugin's startup. - /// This is available for libraries that build upon a , for more precise - /// configuration use . - /// - /// A service container to register new services. - void Configure(IServiceCollection services) - { - // Skipped - } -} diff --git a/back/src/Kyoo.Abstractions/Controllers/IPluginManager.cs b/back/src/Kyoo.Abstractions/Controllers/IPluginManager.cs deleted file mode 100644 index 4998588c..00000000 --- a/back/src/Kyoo.Abstractions/Controllers/IPluginManager.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.Collections.Generic; -using Kyoo.Abstractions.Models.Exceptions; - -namespace Kyoo.Abstractions.Controllers; - -/// -/// A manager to load plugins and retrieve information from them. -/// -public interface IPluginManager -{ - /// - /// Get a single plugin that match the type and name given. - /// - /// The name of the plugin - /// The type of the plugin - /// If no plugins match the query - /// A plugin that match the queries - public T GetPlugin(string name); - - /// - /// Get all plugins of the given type. - /// - /// The type of plugins to get - /// A list of plugins matching the given type or an empty list of none match. - public ICollection GetPlugins(); - - /// - /// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted. - /// - /// All plugins currently loaded. - public ICollection GetAllPlugins(); - - /// - /// Load plugins and their dependencies from the plugin directory. - /// - /// - /// An initial plugin list to use. - /// You should not try to put plugins from the plugins directory here as they will get automatically loaded. - /// - public void LoadPlugins(ICollection plugins); - - /// - /// Load plugins and their dependencies from the plugin directory. - /// - /// - /// An initial plugin list to use. - /// You should not try to put plugins from the plugins directory here as they will get automatically loaded. - /// - public void LoadPlugins(params Type[] plugins); -} diff --git a/back/src/Kyoo.Abstractions/Controllers/StartupAction.cs b/back/src/Kyoo.Abstractions/Controllers/StartupAction.cs deleted file mode 100644 index 944b899d..00000000 --- a/back/src/Kyoo.Abstractions/Controllers/StartupAction.cs +++ /dev/null @@ -1,270 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using Microsoft.Extensions.DependencyInjection; - -namespace Kyoo.Abstractions.Controllers; - -/// -/// A list of constant priorities used for 's . -/// It also contains helper methods for creating new . -/// -public static class SA -{ - /// - /// The highest predefined priority existing for . - /// - public const int Before = 5000; - - /// - /// Items defining routing (see IApplicationBuilder.UseRouting use this priority. - /// - public const int Routing = 4000; - - /// - /// Actions defining new static files router use this priority. - /// - public const int StaticFiles = 3000; - - /// - /// Actions calling IApplicationBuilder.UseAuthentication use this priority. - /// - public const int Authentication = 2000; - - /// - /// Actions calling IApplicationBuilder.UseAuthorization use this priority. - /// - public const int Authorization = 1000; - - /// - /// Action adding endpoint should use this priority (with a negative modificator if there is a catchall). - /// - public const int Endpoint = 0; - - /// - /// The lowest predefined priority existing for . - /// It should run after all other actions. - /// - public const int After = -1000; - - /// - /// Create a new . - /// - /// The action to run - /// The priority of the new action - /// A new - public static StartupAction New(Action action, int priority) => new(action, priority); - - /// - /// Create a new . - /// - /// The action to run - /// The priority of the new action - /// A dependency that this action will use. - /// A new - public static StartupAction New(Action action, int priority) - where T : notnull => new(action, priority); - - /// - /// Create a new . - /// - /// The action to run - /// The priority of the new action - /// A dependency that this action will use. - /// A second dependency that this action will use. - /// A new - public static StartupAction New(Action action, int priority) - where T : notnull - where T2 : notnull => new(action, priority); - - /// - /// Create a new . - /// - /// The action to run - /// The priority of the new action - /// A dependency that this action will use. - /// A second dependency that this action will use. - /// A third dependency that this action will use. - /// A new - public static StartupAction New(Action action, int priority) - where T : notnull - where T2 : notnull - where T3 : notnull => new(action, priority); - - /// - /// A with no dependencies. - /// - public class StartupAction : IStartupAction - { - /// - /// The action to execute at startup. - /// - private readonly Action _action; - - /// - public int Priority { get; } - - /// - /// Create a new . - /// - /// The action to execute on startup. - /// The priority of this action (see ). - public StartupAction(Action action, int priority) - { - _action = action; - Priority = priority; - } - - /// - public void Run(IServiceProvider provider) - { - _action.Invoke(); - } - } - - /// - /// A with one dependencies. - /// - /// The dependency to use. - public class StartupAction : IStartupAction - where T : notnull - { - /// - /// The action to execute at startup. - /// - private readonly Action _action; - - /// - public int Priority { get; } - - /// - /// Create a new . - /// - /// The action to execute on startup. - /// The priority of this action (see ). - public StartupAction(Action action, int priority) - { - _action = action; - Priority = priority; - } - - /// - public void Run(IServiceProvider provider) - { - _action.Invoke(provider.GetRequiredService()); - } - } - - /// - /// A with two dependencies. - /// - /// The dependency to use. - /// The second dependency to use. - public class StartupAction : IStartupAction - where T : notnull - where T2 : notnull - { - /// - /// The action to execute at startup. - /// - private readonly Action _action; - - /// - public int Priority { get; } - - /// - /// Create a new . - /// - /// The action to execute on startup. - /// The priority of this action (see ). - public StartupAction(Action action, int priority) - { - _action = action; - Priority = priority; - } - - /// - public void Run(IServiceProvider provider) - { - _action.Invoke(provider.GetRequiredService(), provider.GetRequiredService()); - } - } - - /// - /// A with three dependencies. - /// - /// The dependency to use. - /// The second dependency to use. - /// The third dependency to use. - public class StartupAction : IStartupAction - where T : notnull - where T2 : notnull - where T3 : notnull - { - /// - /// The action to execute at startup. - /// - private readonly Action _action; - - /// - public int Priority { get; } - - /// - /// Create a new . - /// - /// The action to execute on startup. - /// The priority of this action (see ). - public StartupAction(Action action, int priority) - { - _action = action; - Priority = priority; - } - - /// - public void Run(IServiceProvider provider) - { - _action.Invoke( - provider.GetRequiredService(), - provider.GetRequiredService(), - provider.GetRequiredService() - ); - } - } -} - -/// -/// An action executed on kyoo's startup to initialize the asp-net container. -/// -/// -/// This is the base interface, see for a simpler use of this. -/// -public interface IStartupAction -{ - /// - /// The priority of this action. The actions will be executed on descending priority order. - /// If two actions have the same priority, their order is undefined. - /// - int Priority { get; } - - /// - /// Run this action to configure the container, a service provider containing all services can be used. - /// - /// The service provider containing all services can be used. - void Run(IServiceProvider provider); -} diff --git a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj index cd68fd32..9a05d140 100644 --- a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj +++ b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj @@ -3,7 +3,6 @@ Kyoo.Abstractions Base package to create plugins for Kyoo. Kyoo.Abstractions - enable diff --git a/back/src/Kyoo.Authentication/AuthenticationModule.cs b/back/src/Kyoo.Authentication/AuthenticationModule.cs index f500cd42..fb9bb1f1 100644 --- a/back/src/Kyoo.Authentication/AuthenticationModule.cs +++ b/back/src/Kyoo.Authentication/AuthenticationModule.cs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -28,62 +27,41 @@ using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Primitives; using Microsoft.IdentityModel.Tokens; +using Serilog; namespace Kyoo.Authentication; -/// -/// A module that enable OpenID authentication for Kyoo. -/// -/// -/// Create a new authentication module instance and use the given configuration. -/// -public class AuthenticationModule( - IConfiguration configuration, - ILogger logger -) : IPlugin +public static class AuthenticationModule { - /// - public string Name => "Authentication"; - - /// - /// The configuration to use. - /// - private readonly IConfiguration _configuration = configuration; - - /// - public void Configure(ContainerBuilder builder) + public static void ConfigureAuthentication(this WebApplicationBuilder builder) { - builder.RegisterType().As().SingleInstance(); - builder.RegisterType().As().SingleInstance(); - } - - /// - public void Configure(IServiceCollection services) - { - string secret = _configuration.GetValue( + string secret = builder.Configuration.GetValue( "AUTHENTICATION_SECRET", AuthenticationOption.DefaultSecret )!; PermissionOption options = new() { - Default = _configuration - .GetValue("UNLOGGED_PERMISSIONS", "")! + Default = builder + .Configuration.GetValue("UNLOGGED_PERMISSIONS", "")! .Split(',') .Where(x => x.Length > 0) .ToArray(), - NewUser = _configuration - .GetValue("DEFAULT_PERMISSIONS", "overall.read,overall.play")! + NewUser = builder + .Configuration.GetValue("DEFAULT_PERMISSIONS", "overall.read,overall.play")! .Split(','), - RequireVerification = _configuration.GetValue("REQUIRE_ACCOUNT_VERIFICATION", true), + RequireVerification = builder.Configuration.GetValue( + "REQUIRE_ACCOUNT_VERIFICATION", + true + ), PublicUrl = - _configuration.GetValue("PUBLIC_URL") ?? "http://localhost:8901", - ApiKeys = _configuration.GetValue("KYOO_APIKEYS", string.Empty)!.Split(','), - OIDC = _configuration - .AsEnumerable() + builder.Configuration.GetValue("PUBLIC_URL") + ?? "http://localhost:8901", + ApiKeys = builder.Configuration.GetValue("KYOO_APIKEYS", string.Empty)!.Split(','), + OIDC = builder + .Configuration.AsEnumerable() .Where((pair) => pair.Key.StartsWith("OIDC_")) .Aggregate( new Dictionary(), @@ -93,7 +71,7 @@ public class AuthenticationModule( return acc; if (val.Key.Split("_") is not ["OIDC", string provider, string key]) { - logger.LogError("Invalid oidc config value: {Key}", val.Key); + Log.Error("Invalid oidc config value: {Key}", val.Key); return acc; } provider = provider.ToLowerInvariant(); @@ -129,20 +107,20 @@ public class AuthenticationModule( acc[provider].LogoUrl = val.Value; break; default: - logger.LogError("Invalid oidc config value: {Key}", key); + Log.Error("Invalid oidc config value: {Key}", key); return acc; } return acc; } ), }; - services.AddSingleton(options); - services.AddSingleton( + builder.Services.AddSingleton(options); + builder.Services.AddSingleton( new AuthenticationOption() { Secret = secret, Permissions = options, } ); - services - .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + builder + .Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Events = new() @@ -171,12 +149,8 @@ public class AuthenticationModule( IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)) }; }); - } - /// - public IEnumerable ConfigureSteps => - new IStartupAction[] - { - SA.New(app => app.UseAuthentication(), SA.Authentication), - }; + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + } } diff --git a/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj b/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj index 7d4e1a32..b390fba7 100644 --- a/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj +++ b/back/src/Kyoo.Authentication/Kyoo.Authentication.csproj @@ -1,12 +1,9 @@ - - enable - - + diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs index a3236e9d..c0763b19 100644 --- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs +++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs @@ -53,8 +53,8 @@ public class LibraryManager : ILibraryManager Studios = studioRepository; Users = userRepository; - _repositories = new IBaseRepository[] - { + _repositories = + [ LibraryItems, News, Collections, @@ -64,7 +64,7 @@ public class LibraryManager : ILibraryManager Episodes, Studios, Users - }; + ]; } /// diff --git a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs index 70caee44..207d9718 100644 --- a/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs +++ b/back/src/Kyoo.Core/Controllers/ThumbnailsManager.cs @@ -42,7 +42,7 @@ public class ThumbnailsManager( Lazy> users ) : IThumbnailsManager { - private static readonly Dictionary> _downloading = new(); + private static readonly Dictionary> _downloading = []; private static async Task _WriteTo(SKBitmap bitmap, string path, int quality) { diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index 8d683b80..a72dab49 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -17,29 +17,15 @@ // along with Kyoo. If not, see . using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json; -using System.Text.Json.Serialization; -using AspNetCore.Proxy; -using Autofac; -using Kyoo.Abstractions; using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models.Utils; -using Kyoo.Core.Api; +using Kyoo.Abstractions.Models; using Kyoo.Core.Controllers; -using Kyoo.Utils; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Core; -/// -/// The core module containing default implementations -/// -public class CoreModule : IPlugin +public static class CoreModule { /// /// A service provider to access services in static context (in events for example). @@ -47,102 +33,31 @@ public class CoreModule : IPlugin /// Don't forget to create a scope. public static IServiceProvider Services { get; set; } - /// - public string Name => "Core"; - - /// - public void Configure(ContainerBuilder builder) + public static void AddRepository(this IServiceCollection services) + where T:IResource + where TRepo : class, IRepository { - builder - .RegisterType() - .As() - .InstancePerLifetimeScope(); - builder.RegisterType().As().InstancePerLifetimeScope(); - - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository().As(); - builder.RegisterRepository(); - builder - .RegisterType() - .As() - .AsSelf() - .InstancePerLifetimeScope(); - builder - .RegisterType() - .As() - .AsSelf() - .InstancePerLifetimeScope(); - builder.RegisterType().InstancePerLifetimeScope(); + services.AddScoped(); + services.AddScoped>(x => x.GetRequiredService()); } - /// - public void Configure(IServiceCollection services) + public static void ConfigureKyoo(this WebApplicationBuilder builder) { - services.AddHttpContextAccessor(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); - services - .AddMvcCore(options => - { - options.Filters.Add(); - options.ModelBinderProviders.Insert(0, new SortBinder.Provider()); - options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider()); - options.ModelBinderProviders.Insert(0, new FilterBinder.Provider()); - }) - .AddJsonOptions(x => - { - x.JsonSerializerOptions.TypeInfoResolver = new JsonKindResolver() - { - Modifiers = { IncludeBinder.HandleLoadableFields } - }; - x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); - x.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; - }) - .AddDataAnnotations() - .AddControllersAsServices() - .AddApiExplorer() - .ConfigureApiBehaviorOptions(options => - { - options.SuppressMapClientErrors = true; - options.InvalidModelStateResponseFactory = ctx => - { - string[] errors = ctx - .ModelState.SelectMany(x => x.Value!.Errors) - .Select(x => x.ErrorMessage) - .ToArray(); - return new BadRequestObjectResult(new RequestError(errors)); - }; - }); - - services.Configure(x => - { - x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint)); - }); - - services.AddResponseCompression(x => - { - x.EnableForHttps = true; - }); - - services.AddProxies(); - services.AddHttpClient(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddRepository(); + builder.Services.AddScoped(x => x.GetRequiredService()); + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddScoped(); } - - /// - public IEnumerable ConfigureSteps => - new IStartupAction[] - { - SA.New(app => app.UseHsts(), SA.Before), - SA.New(app => app.UseResponseCompression(), SA.Routing + 1), - SA.New(app => app.UseRouting(), SA.Routing), - SA.New( - app => app.UseEndpoints(x => x.MapControllers()), - SA.Endpoint - ) - }; } diff --git a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs new file mode 100644 index 00000000..9bed18bf --- /dev/null +++ b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs @@ -0,0 +1,86 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using AspNetCore.Proxy; +using Kyoo.Abstractions.Models.Utils; +using Kyoo.Core.Api; +using Kyoo.Core.Controllers; +using Kyoo.Utils; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; + +namespace Kyoo.Core.Extensions; + +public static class ServiceExtensions +{ + public static void ConfigureMvc(this IServiceCollection services) + { + services.AddHttpContextAccessor(); + + services + .AddMvcCore(options => + { + options.Filters.Add(); + options.ModelBinderProviders.Insert(0, new SortBinder.Provider()); + options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider()); + options.ModelBinderProviders.Insert(0, new FilterBinder.Provider()); + }) + .AddJsonOptions(x => + { + x.JsonSerializerOptions.TypeInfoResolver = new JsonKindResolver() + { + Modifiers = { IncludeBinder.HandleLoadableFields } + }; + x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + x.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }) + .AddDataAnnotations() + .AddControllersAsServices() + .AddApiExplorer() + .ConfigureApiBehaviorOptions(options => + { + options.SuppressMapClientErrors = true; + options.InvalidModelStateResponseFactory = ctx => + { + string[] errors = ctx + .ModelState.SelectMany(x => x.Value!.Errors) + .Select(x => x.ErrorMessage) + .ToArray(); + return new BadRequestObjectResult(new RequestError(errors)); + }; + }); + + services.Configure(x => + { + x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint)); + }); + + services.AddResponseCompression(x => + { + x.EnableForHttps = true; + }); + + services.AddProxies(); + services.AddHttpClient(); + } +} diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj index 67b5c30d..49be7338 100644 --- a/back/src/Kyoo.Core/Kyoo.Core.csproj +++ b/back/src/Kyoo.Core/Kyoo.Core.csproj @@ -2,7 +2,10 @@ Kyoo.Core Kyoo.Core - enable + Exe + + 50 @@ -12,6 +15,11 @@ + + + + + @@ -19,6 +27,9 @@ + + + diff --git a/back/src/Kyoo.Core/Program.cs b/back/src/Kyoo.Core/Program.cs new file mode 100644 index 00000000..3ea03994 --- /dev/null +++ b/back/src/Kyoo.Core/Program.cs @@ -0,0 +1,109 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System; +using System.IO; +using Kyoo.Authentication; +using Kyoo.Core; +using Kyoo.Core.Extensions; +using Kyoo.Meiliseach; +using Kyoo.Postgresql; +using Kyoo.RabbitMq; +using Kyoo.Swagger; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Events; +using Serilog.Templates; +using Serilog.Templates.Themes; + +#if DEBUG +const string EnvironmentName = "Development"; +#else + const string EnvironmentName = "Production"; +#endif + +WebApplicationBuilder builder = WebApplication.CreateBuilder( + new WebApplicationOptions() + { + Args = args, + EnvironmentName = EnvironmentName, + ApplicationName = "Kyoo", + ContentRootPath = AppDomain.CurrentDomain.BaseDirectory, + } +); +builder.WebHost.UseKestrel(opt => +{ + opt.AddServerHeader = false; +}); + +const string template = + "[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 25} " + + "({@i:D10})] {@m}{#if not EndsWith(@m, '\n')}\n{#end}{@x}"; +Log.Logger = new LoggerConfiguration() + .MinimumLevel.Warning() + .MinimumLevel.Override("Kyoo", LogEventLevel.Verbose) + .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Verbose) + .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Fatal) + .WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code)) + .Enrich.WithThreadId() + .Enrich.FromLogContext() + .CreateLogger(); +AppDomain.CurrentDomain.ProcessExit += (_, _) => Log.CloseAndFlush(); +AppDomain.CurrentDomain.UnhandledException += (_, ex) => + Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception"); +builder.Host.UseSerilog(); + + +// Set current directory, used by thumbnails for example. +string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); +if (!Directory.Exists(path)) + Directory.CreateDirectory(path); +Environment.CurrentDirectory = path; +Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); + +builder.Services.ConfigureMvc(); +builder.Services.ConfigureOpenApi(); +builder.ConfigureKyoo(); +builder.ConfigureAuthentication(); +builder.ConfigurePostgres(); +builder.ConfigureMeilisearch(); + +WebApplication app = builder.Build(); +CoreModule.Services = app.Services; + +app.UseHsts(); +app.UseKyooOpenApi(); +app.UseResponseCompression(); +app.UseRouting(); +app.UseAuthentication(); +app.MapControllers(); + +// Activate services that always run in the background +app.Services.GetRequiredService(); +app.Services.GetRequiredService(); + +await using (AsyncServiceScope scope = app.Services.CreateAsyncScope()) +{ + await MeilisearchModule.Initialize(scope.ServiceProvider); +} + +app.Run(Environment.GetEnvironmentVariable("KYOO_BIND_URL") ?? "http://*:5000"); diff --git a/back/src/Kyoo.Host/Application.cs b/back/src/Kyoo.Host/Application.cs deleted file mode 100644 index 0d090919..00000000 --- a/back/src/Kyoo.Host/Application.cs +++ /dev/null @@ -1,195 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.IO; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Autofac; -using Autofac.Extensions.DependencyInjection; -using Kyoo.Core; -using Kyoo.Meiliseach; -using Kyoo.Postgresql; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Serilog; -using Serilog.Events; -using Serilog.Templates; -using Serilog.Templates.Themes; -using ILogger = Serilog.ILogger; - -namespace Kyoo.Host; - -/// -/// Hosts of kyoo (main functions) generally only create a new -/// and return . -/// -public class Application -{ - /// - /// The environment in witch Kyoo will run (ether "Production" or "Development"). - /// - private readonly string _environment; - - /// - /// The logger used for startup and error messages. - /// - private ILogger _logger; - - /// - /// Create a new that will use the specified environment. - /// - /// The environment to run in. - public Application(string environment) - { - _environment = environment; - } - - /// - /// Start the application with the given console args. - /// This is generally called from the Main entrypoint of Kyoo. - /// - /// The console arguments to use for kyoo. - /// A task representing the whole process - public Task Start(string[] args) - { - return Start(args, _ => { }); - } - - /// - /// Start the application with the given console args. - /// This is generally called from the Main entrypoint of Kyoo. - /// - /// The console arguments to use for kyoo. - /// A custom action to configure the container before the start - /// A task representing the whole process - public async Task Start(string[] args, Action configure) - { - IConfiguration parsed = _SetupConfig(new ConfigurationBuilder(), args).Build(); - string path = Path.GetFullPath(parsed.GetValue("DATADIR", "/kyoo")); - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - Environment.CurrentDirectory = path; - - LoggerConfiguration config = new(); - _ConfigureLogging(config); - Log.Logger = config.CreateBootstrapLogger(); - _logger = Log.Logger.ForContext(); - - AppDomain.CurrentDomain.ProcessExit += (_, _) => Log.CloseAndFlush(); - AppDomain.CurrentDomain.UnhandledException += (_, ex) => - Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception"); - - IHost host = _CreateWebHostBuilder(args).ConfigureContainer(configure).Build(); - - await using (AsyncServiceScope scope = host.Services.CreateAsyncScope()) - { - await MeilisearchModule.Initialize(scope.ServiceProvider); - } - - await _StartWithHost(host); - } - - /// - /// Start the given host and log failing exceptions. - /// - /// The host to start. - /// A token to allow one to stop the host. - private async Task _StartWithHost(IHost host, CancellationToken cancellationToken = default) - { - try - { - CoreModule.Services = host.Services; - _logger.Information( - "Version: {Version}", - Assembly.GetExecutingAssembly().GetName().Version.ToString(3) - ); - _logger.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); - await host.RunAsync(cancellationToken); - } - catch (Exception ex) - { - _logger.Fatal(ex, "Unhandled exception"); - } - } - - /// - /// Create a a web host - /// - /// Command line parameters that can be handled by kestrel - /// A new web host instance - private IHostBuilder _CreateWebHostBuilder(string[] args) - { - return new HostBuilder() - .UseServiceProviderFactory(new AutofacServiceProviderFactory()) - .UseContentRoot(AppDomain.CurrentDomain.BaseDirectory) - .UseEnvironment(_environment) - .ConfigureAppConfiguration(x => _SetupConfig(x, args)) - .UseSerilog((host, services, builder) => _ConfigureLogging(builder)) - .ConfigureServices(x => x.AddRouting()) - .ConfigureWebHost(x => - x.UseKestrel(options => - { - options.AddServerHeader = false; - }) - .UseIIS() - .UseIISIntegration() - .UseUrls(Environment.GetEnvironmentVariable("KYOO_BIND_URL") ?? "http://*:5000") - .UseStartup(host => - PluginsStartup.FromWebHost(host, new LoggerFactory().AddSerilog()) - ) - ); - } - - /// - /// Register settings.json, environment variables and command lines arguments as configuration. - /// - /// The configuration builder to use - /// The command line arguments - /// The modified configuration builder - private IConfigurationBuilder _SetupConfig(IConfigurationBuilder builder, string[] args) - { - return builder - .AddEnvironmentVariables() - .AddEnvironmentVariables("KYOO_") - .AddCommandLine(args); - } - - /// - /// Configure the logging. - /// - /// The logger builder to configure. - private void _ConfigureLogging(LoggerConfiguration builder) - { - const string template = - "[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 25} " - + "({@i:D10})] {@m}{#if not EndsWith(@m, '\n')}\n{#end}{@x}"; - builder - .MinimumLevel.Warning() - .MinimumLevel.Override("Kyoo", LogEventLevel.Verbose) - .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Verbose) - .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Fatal) - .WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code)) - .Enrich.WithThreadId() - .Enrich.FromLogContext(); - } -} diff --git a/back/src/Kyoo.Host/Contollers/PluginManager.cs b/back/src/Kyoo.Host/Contollers/PluginManager.cs deleted file mode 100644 index fcaa2d9d..00000000 --- a/back/src/Kyoo.Host/Contollers/PluginManager.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.Collections.Generic; -using System.Linq; -using Kyoo.Abstractions.Controllers; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace Kyoo.Host.Controllers; - -/// -/// An implementation of . -/// This is used to load plugins and retrieve information from them. -/// -public class PluginManager : IPluginManager -{ - /// - /// The service provider. It allow plugin's activation. - /// - private readonly IServiceProvider _provider; - - /// - /// The logger used by this class. - /// - private readonly ILogger _logger; - - /// - /// The list of plugins that are currently loaded. - /// - private readonly List _plugins = new(); - - /// - /// Create a new instance. - /// - /// A service container to allow initialization of plugins - /// The logger used by this class. - public PluginManager(IServiceProvider provider, ILogger logger) - { - _provider = provider; - _logger = logger; - } - - /// - public T GetPlugin(string name) - { - return (T)_plugins?.FirstOrDefault(x => x.Name == name && x is T); - } - - /// - public ICollection GetPlugins() - { - return _plugins?.OfType().ToArray(); - } - - /// - public ICollection GetAllPlugins() - { - return _plugins; - } - - /// - public void LoadPlugins(ICollection plugins) - { - _plugins.AddRange(plugins); - _logger.LogInformation("Modules enabled: {Plugins}", _plugins.Select(x => x.Name)); - } - - /// - public void LoadPlugins(params Type[] plugins) - { - LoadPlugins( - plugins.Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)).ToArray() - ); - } -} diff --git a/back/src/Kyoo.Host/HostModule.cs b/back/src/Kyoo.Host/HostModule.cs deleted file mode 100644 index 6c43b9a8..00000000 --- a/back/src/Kyoo.Host/HostModule.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System.Collections.Generic; -using Autofac; -using Autofac.Extras.AttributeMetadata; -using Kyoo.Abstractions.Controllers; -using Microsoft.AspNetCore.Builder; -using Serilog; - -namespace Kyoo.Host; - -/// -/// A module that registers host controllers and other needed things. -/// -public class HostModule : IPlugin -{ - /// - public string Name => "Host"; - - /// - /// The plugin manager that loaded all plugins. - /// - private readonly IPluginManager _plugins; - - /// - /// Create a new . - /// - /// The plugin manager that loaded all plugins. - public HostModule(IPluginManager plugins) - { - _plugins = plugins; - } - - /// - public void Configure(ContainerBuilder builder) - { - builder.RegisterModule(); - builder.RegisterInstance(_plugins).As().ExternallyOwned(); - } - - /// - public IEnumerable ConfigureSteps => - new[] { SA.New(app => app.UseSerilogRequestLogging(), SA.Before) }; -} diff --git a/back/src/Kyoo.Host/Kyoo.Host.csproj b/back/src/Kyoo.Host/Kyoo.Host.csproj deleted file mode 100644 index 418d06f9..00000000 --- a/back/src/Kyoo.Host/Kyoo.Host.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - Exe - Kyoo.Host - Kyoo.Host - Kyoo.Host.Program - - 50 - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/back/src/Kyoo.Host/PluginsStartup.cs b/back/src/Kyoo.Host/PluginsStartup.cs deleted file mode 100644 index 40f4c3d1..00000000 --- a/back/src/Kyoo.Host/PluginsStartup.cs +++ /dev/null @@ -1,195 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Autofac; -using Kyoo.Abstractions.Controllers; -using Kyoo.Authentication; -using Kyoo.Core; -using Kyoo.Host.Controllers; -using Kyoo.Meiliseach; -using Kyoo.Postgresql; -using Kyoo.RabbitMq; -using Kyoo.Swagger; -using Kyoo.Utils; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace Kyoo.Host; - -/// -/// The Startup class is used to configure the AspNet's webhost. -/// -public class PluginsStartup -{ - /// - /// A plugin manager used to load plugins and allow them to configure services / asp net. - /// - private readonly IPluginManager _plugins; - - /// - /// The plugin that adds controllers and tasks specific to this host. - /// - private readonly IPlugin _hostModule; - - /// - /// Created from the DI container, those services are needed to load information and instantiate plugins.s - /// - /// The plugin manager to use to load new plugins and configure the host. - public PluginsStartup(IPluginManager plugins) - { - _plugins = plugins; - _hostModule = new HostModule(_plugins); - _plugins.LoadPlugins( - typeof(CoreModule), - typeof(AuthenticationModule), - typeof(PostgresModule), - typeof(MeilisearchModule), - typeof(RabbitMqModule), - typeof(SwaggerModule) - ); - } - - /// - /// Create a new from a webhost. - /// This is meant to be used from . - /// - /// The context of the web host. - /// - /// The logger factory used to log while the application is setting itself up. - /// - /// A new . - public static PluginsStartup FromWebHost(WebHostBuilderContext host, ILoggerFactory logger) - { - HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger); - PluginManager plugins = new(hostProvider, logger.CreateLogger()); - return new PluginsStartup(plugins); - } - - /// - /// Configure the services context via the . - /// - /// The service collection to fill. - public void ConfigureServices(IServiceCollection services) - { - foreach (Assembly assembly in _plugins.GetAllPlugins().Select(x => x.GetType().Assembly)) - services.AddMvcCore().AddApplicationPart(assembly); - - _hostModule.Configure(services); - foreach (IPlugin plugin in _plugins.GetAllPlugins()) - plugin.Configure(services); - } - - /// - /// Configure the autofac container via the . - /// - /// The builder to configure. - public void ConfigureContainer(ContainerBuilder builder) - { - _hostModule.Configure(builder); - foreach (IPlugin plugin in _plugins.GetAllPlugins()) - plugin.Configure(builder); - } - - /// - /// Configure the asp net host. - /// - /// The asp net host to configure - /// An autofac container used to create a new scope to configure asp-net. - public void Configure(IApplicationBuilder app, ILifetimeScope container) - { - IEnumerable steps = _plugins - .GetAllPlugins() - .Append(_hostModule) - .SelectMany(x => x.ConfigureSteps) - .OrderByDescending(x => x.Priority); - - using ILifetimeScope scope = container.BeginLifetimeScope(x => - x.RegisterInstance(app).SingleInstance().ExternallyOwned() - ); - IServiceProvider provider = scope.Resolve(); - foreach (IStartupAction step in steps) - step.Run(provider); - } - - /// - /// A simple host service provider used to activate plugins instance. - /// The same services as a generic host are available and an has been added. - /// - private class HostServiceProvider( - IWebHostEnvironment hostEnvironment, - IConfiguration configuration, - ILoggerFactory loggerFactory - ) : IServiceProvider - { - /// - public object GetService(Type serviceType) - { - if ( - serviceType == typeof(IWebHostEnvironment) - || serviceType == typeof(IHostEnvironment) - ) - return hostEnvironment; - if (serviceType == typeof(IConfiguration)) - return configuration; - if (serviceType == typeof(IServiceProviderIsService)) - return new ProviderIsService(); - if ( - serviceType.IsGenericType - && serviceType.GetGenericTypeDefinition() == typeof(ILogger<>) - ) - { - return Utility.RunGenericMethod( - typeof(LoggerFactoryExtensions), - nameof(LoggerFactoryExtensions.CreateLogger), - serviceType.GetGenericArguments().First(), - loggerFactory - ); - } - - throw new ArgumentException( - $"{serviceType.Name} is not available in configuration stpe" - ); - } - - public class ProviderIsService : IServiceProviderIsService - { - public bool IsService(Type serviceType) - { - Type[] supported = - [ - typeof(IWebHostEnvironment), - typeof(IHostEnvironment), - typeof(IConfiguration), - typeof(IServiceProviderIsService), - ]; - if (supported.Contains(serviceType)) - return true; - return serviceType.IsGenericType - && serviceType.GetGenericTypeDefinition() == typeof(ILogger<>); - } - } - } -} diff --git a/back/src/Kyoo.Host/Program.cs b/back/src/Kyoo.Host/Program.cs deleted file mode 100644 index 708aa6b4..00000000 --- a/back/src/Kyoo.Host/Program.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; - -namespace Kyoo.Host; - -/// -/// Program entrypoint. -/// -public static class Program -{ - /// - /// The string representation of the environment used in . - /// -#if DEBUG - private const string Environment = "Development"; -#else - private const string Environment = "Production"; -#endif - - /// - /// Main function of the program - /// - /// Command line arguments - /// A representing the lifetime of the program. - public static Task Main(string[] args) - { - Application application = new(Environment); - return application.Start(args); - } -} diff --git a/back/src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj b/back/src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj index 6fb681ff..b6ff7e12 100644 --- a/back/src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj +++ b/back/src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj @@ -1,7 +1,6 @@ enable - enable Kyoo.Meilisearch diff --git a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs index 3cbd903b..1ba74dae 100644 --- a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs +++ b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs @@ -16,21 +16,18 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using Autofac; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Meilisearch; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using static System.Text.Json.JsonNamingPolicy; namespace Kyoo.Meiliseach; -public class MeilisearchModule(IConfiguration configuration) : IPlugin +public static class MeilisearchModule { - /// - public string Name => "Meilisearch"; - public static Dictionary IndexSettings => new() { @@ -145,17 +142,16 @@ public class MeilisearchModule(IConfiguration configuration) : IPlugin } /// - public void Configure(ContainerBuilder builder) + public static void ConfigureMeilisearch(this WebApplicationBuilder builder) { builder - .RegisterInstance( + .Services.AddSingleton( new MeilisearchClient( - configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"), - configuration.GetValue("MEILI_MASTER_KEY") + builder.Configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"), + builder.Configuration.GetValue("MEILI_MASTER_KEY") ) - ) - .SingleInstance(); - builder.RegisterType().AsSelf().SingleInstance().AutoActivate(); - builder.RegisterType().As().InstancePerLifetimeScope(); + ); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); } } diff --git a/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj index 807f357a..c3bd4e47 100644 --- a/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj +++ b/back/src/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -2,7 +2,6 @@ Kyoo.Postgresql Kyoo.Postgresql - enable diff --git a/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs b/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs index 725268a0..53cf7cc3 100644 --- a/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs +++ b/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs @@ -3,179 +3,178 @@ using Microsoft.EntityFrameworkCore.Migrations; #nullable disable -namespace Kyoo.Postgresql.Migrations +namespace Kyoo.Postgresql.Migrations; + +/// +public partial class UseDateOnly : Migration { /// - public partial class UseDateOnly : Migration + protected override void Up(MigrationBuilder migrationBuilder) { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder - .AlterDatabase() - .Annotation( - "Npgsql:Enum:genre", - "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" - ) - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted") - .OldAnnotation( - "Npgsql:Enum:genre", - "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" - ) - .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned"); + migrationBuilder + .AlterDatabase() + .Annotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted") + .OldAnnotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned"); - migrationBuilder.AlterColumn( - name: "start_air", - table: "shows", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true + migrationBuilder.AlterColumn( + name: "start_air", + table: "shows", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.AlterColumn( + name: "end_air", + table: "shows", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.AlterColumn( + name: "start_date", + table: "seasons", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.AlterColumn( + name: "end_date", + table: "seasons", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.AlterColumn( + name: "air_date", + table: "movies", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.AlterColumn( + name: "release_date", + table: "episodes", + type: "date", + nullable: true, + oldClrType: typeof(DateTime), + oldType: "timestamp with time zone", + oldNullable: true + ); + + migrationBuilder.CreateIndex( + name: "ix_users_username", + table: "users", + column: "username", + unique: true + ); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex(name: "ix_users_username", table: "users"); + + migrationBuilder + .AlterDatabase() + .Annotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned") + .OldAnnotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .OldAnnotation( + "Npgsql:Enum:watch_status", + "completed,watching,droped,planned,deleted" ); - migrationBuilder.AlterColumn( - name: "end_air", - table: "shows", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true - ); + migrationBuilder.AlterColumn( + name: "start_air", + table: "shows", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); - migrationBuilder.AlterColumn( - name: "start_date", - table: "seasons", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true - ); + migrationBuilder.AlterColumn( + name: "end_air", + table: "shows", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); - migrationBuilder.AlterColumn( - name: "end_date", - table: "seasons", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true - ); + migrationBuilder.AlterColumn( + name: "start_date", + table: "seasons", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); - migrationBuilder.AlterColumn( - name: "air_date", - table: "movies", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true - ); + migrationBuilder.AlterColumn( + name: "end_date", + table: "seasons", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); - migrationBuilder.AlterColumn( - name: "release_date", - table: "episodes", - type: "date", - nullable: true, - oldClrType: typeof(DateTime), - oldType: "timestamp with time zone", - oldNullable: true - ); + migrationBuilder.AlterColumn( + name: "air_date", + table: "movies", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); - migrationBuilder.CreateIndex( - name: "ix_users_username", - table: "users", - column: "username", - unique: true - ); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropIndex(name: "ix_users_username", table: "users"); - - migrationBuilder - .AlterDatabase() - .Annotation( - "Npgsql:Enum:genre", - "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" - ) - .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned") - .OldAnnotation( - "Npgsql:Enum:genre", - "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" - ) - .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation( - "Npgsql:Enum:watch_status", - "completed,watching,droped,planned,deleted" - ); - - migrationBuilder.AlterColumn( - name: "start_air", - table: "shows", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - - migrationBuilder.AlterColumn( - name: "end_air", - table: "shows", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - - migrationBuilder.AlterColumn( - name: "start_date", - table: "seasons", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - - migrationBuilder.AlterColumn( - name: "end_date", - table: "seasons", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - - migrationBuilder.AlterColumn( - name: "air_date", - table: "movies", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - - migrationBuilder.AlterColumn( - name: "release_date", - table: "episodes", - type: "timestamp with time zone", - nullable: true, - oldClrType: typeof(DateOnly), - oldType: "date", - oldNullable: true - ); - } + migrationBuilder.AlterColumn( + name: "release_date", + table: "episodes", + type: "timestamp with time zone", + nullable: true, + oldClrType: typeof(DateOnly), + oldType: "date", + oldNullable: true + ); } } diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index 7b643809..9bdaa75d 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -33,39 +33,19 @@ using Npgsql; namespace Kyoo.Postgresql; -/// -/// A postgresql implementation of . -/// public class PostgresContext : DatabaseContext { - /// - /// Is this instance in debug mode? - /// - private readonly bool _debugMode; - /// /// Should the configure step be skipped? This is used when the database is created via DbContextOptions. /// private readonly bool _skipConfigure; - /// - /// Design time constructor (dotnet ef migrations add). Do not use - /// - public PostgresContext() - : base(null!) { } - public PostgresContext(DbContextOptions options, IHttpContextAccessor accessor) : base(options, accessor) { _skipConfigure = true; } - public PostgresContext(string connection, bool debugMode, IHttpContextAccessor accessor) - : base(accessor) - { - _debugMode = debugMode; - } - /// /// Set connection information for this database context /// @@ -75,8 +55,6 @@ public class PostgresContext : DatabaseContext if (!_skipConfigure) { optionsBuilder.UseNpgsql(); - if (_debugMode) - optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging(); } optionsBuilder.UseSnakeCaseNamingConvention(); diff --git a/back/src/Kyoo.Postgresql/PostgresModule.cs b/back/src/Kyoo.Postgresql/PostgresModule.cs index 478b00d1..e4903b94 100644 --- a/back/src/Kyoo.Postgresql/PostgresModule.cs +++ b/back/src/Kyoo.Postgresql/PostgresModule.cs @@ -17,8 +17,8 @@ // along with Kyoo. If not, see . using System.Data.Common; -using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; +using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -28,49 +28,42 @@ using Npgsql; namespace Kyoo.Postgresql; -/// -/// A module to add postgresql capacity to the app. -/// -public class PostgresModule(IConfiguration configuration, IWebHostEnvironment environment) : IPlugin +public static class PostgresModule { - /// - public string Name => "Postgresql"; - - /// - public void Configure(IServiceCollection services) + public static void ConfigurePostgres(this WebApplicationBuilder builder) { - DbConnectionStringBuilder builder = + DbConnectionStringBuilder conBuilder = new() { - ["USER ID"] = configuration.GetValue("POSTGRES_USER", "KyooUser"), - ["PASSWORD"] = configuration.GetValue("POSTGRES_PASSWORD", "KyooPassword"), - ["SERVER"] = configuration.GetValue("POSTGRES_SERVER", "db"), - ["PORT"] = configuration.GetValue("POSTGRES_PORT", "5432"), - ["DATABASE"] = configuration.GetValue("POSTGRES_DB", "kyooDB"), + ["USER ID"] = builder.Configuration.GetValue("POSTGRES_USER", "KyooUser"), + ["PASSWORD"] = builder.Configuration.GetValue("POSTGRES_PASSWORD", "KyooPassword"), + ["SERVER"] = builder.Configuration.GetValue("POSTGRES_SERVER", "db"), + ["PORT"] = builder.Configuration.GetValue("POSTGRES_PORT", "5432"), + ["DATABASE"] = builder.Configuration.GetValue("POSTGRES_DB", "kyooDB"), ["POOLING"] = "true", ["MAXPOOLSIZE"] = "95", ["TIMEOUT"] = "30" }; - NpgsqlDataSourceBuilder dsBuilder = new(builder.ConnectionString); + NpgsqlDataSourceBuilder dsBuilder = new(conBuilder.ConnectionString); dsBuilder.MapEnum(); dsBuilder.MapEnum(); dsBuilder.MapEnum(); NpgsqlDataSource dataSource = dsBuilder.Build(); - services.AddDbContext( + builder.Services.AddDbContext( x => { x.UseNpgsql(dataSource).UseProjectables(); - if (environment.IsDevelopment()) + if (builder.Environment.IsDevelopment()) x.EnableDetailedErrors().EnableSensitiveDataLogging(); }, ServiceLifetime.Transient ); - services.AddTransient( + builder.Services.AddTransient( (services) => services.GetRequiredService().Database.GetDbConnection() ); - services.AddHealthChecks().AddDbContextCheck(); + builder.Services.AddHealthChecks().AddDbContextCheck(); } } diff --git a/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj b/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj index 382b5b7c..b159b96e 100644 --- a/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj +++ b/back/src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj @@ -1,7 +1,6 @@ enable - enable Kyoo.RabbitMq diff --git a/back/src/Kyoo.RabbitMq/RabbitMqModule.cs b/back/src/Kyoo.RabbitMq/RabbitMqModule.cs index 6aaacb55..86b7b3d8 100644 --- a/back/src/Kyoo.RabbitMq/RabbitMqModule.cs +++ b/back/src/Kyoo.RabbitMq/RabbitMqModule.cs @@ -16,39 +16,30 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using Autofac; -using Kyoo.Abstractions.Controllers; +using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; using RabbitMQ.Client; namespace Kyoo.RabbitMq; -public class RabbitMqModule(IConfiguration configuration) : IPlugin +public static class RabbitMqModule { - /// - public string Name => "RabbitMq"; - - /// - public void Configure(ContainerBuilder builder) + public static void ConfigureRabbitMq(this WebApplicationBuilder builder) { - builder - .Register( - (_) => + builder.Services.AddSingleton(_ => + { + ConnectionFactory factory = + new() { - ConnectionFactory factory = - new() - { - UserName = configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"), - Password = configuration.GetValue("RABBITMQ_DEFAULT_PASS", "guest"), - HostName = configuration.GetValue("RABBITMQ_HOST", "rabbitmq"), - Port = 5672, - }; + UserName = builder.Configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"), + Password = builder.Configuration.GetValue("RABBITMQ_DEFAULT_PASS", "guest"), + HostName = builder.Configuration.GetValue("RABBITMQ_HOST", "rabbitmq"), + Port = 5672, + }; - return factory.CreateConnection(); - } - ) - .AsSelf() - .SingleInstance(); - builder.RegisterType().AsSelf().SingleInstance().AutoActivate(); + return factory.CreateConnection(); + }); + builder.Services.AddSingleton(); } } diff --git a/back/src/Kyoo.Swagger/Kyoo.Swagger.csproj b/back/src/Kyoo.Swagger/Kyoo.Swagger.csproj index 5538a7b2..82eac407 100644 --- a/back/src/Kyoo.Swagger/Kyoo.Swagger.csproj +++ b/back/src/Kyoo.Swagger/Kyoo.Swagger.csproj @@ -2,6 +2,7 @@ Kyoo.Swagger Kyoo.Swagger + disable diff --git a/back/src/Kyoo.Swagger/SwaggerModule.cs b/back/src/Kyoo.Swagger/SwaggerModule.cs index dad785a4..f1e40776 100644 --- a/back/src/Kyoo.Swagger/SwaggerModule.cs +++ b/back/src/Kyoo.Swagger/SwaggerModule.cs @@ -18,7 +18,6 @@ using System.Collections.Generic; using System.Reflection; -using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models.Utils; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc.ApplicationModels; @@ -31,16 +30,9 @@ using static Kyoo.Abstractions.Models.Utils.Constants; namespace Kyoo.Swagger; -/// -/// A module to enable a swagger interface and an OpenAPI endpoint to document Kyoo. -/// -public class SwaggerModule : IPlugin +public static class SwaggerModule { - /// - public string Name => "Swagger"; - - /// - public void Configure(IServiceCollection services) + public static void ConfigureOpenApi(this IServiceCollection services) { services.AddTransient(); services.AddOpenApiDocument(document => @@ -106,24 +98,17 @@ public class SwaggerModule : IPlugin }); } - /// - public IEnumerable ConfigureSteps => - new IStartupAction[] + public static void UseKyooOpenApi(this IApplicationBuilder app) + { + app.UseOpenApi(); + app.UseReDoc(x => { - SA.New(app => app.UseOpenApi(), SA.Before + 1), - SA.New( - app => - app.UseReDoc(x => - { - x.Path = "/doc"; - x.TransformToExternalPath = (internalUiRoute, _) => - "/api" + internalUiRoute; - x.AdditionalSettings["theme"] = new - { - colors = new { primary = new { main = "#e13e13" } } - }; - }), - SA.Before - ) - }; + x.Path = "/doc"; + x.TransformToExternalPath = (internalUiRoute, _) => "/api" + internalUiRoute; + x.AdditionalSettings["theme"] = new + { + colors = new { primary = new { main = "#e13e13" } } + }; + }); + } } From 436cbee752a9379a5df31396c01744bdf8d0f4d8 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 04:56:18 +0200 Subject: [PATCH 3/9] Fix services provider issues --- back/ef.rsp | 2 +- back/src/Kyoo.Core/CoreModule.cs | 3 +- .../Kyoo.Core/Extensions/ServiceExtensions.cs | 50 +++++++++++++++++++ back/src/Kyoo.Core/Kyoo.Core.csproj | 5 ++ back/src/Kyoo.Core/Program.cs | 21 ++++---- .../src/Kyoo.Meilisearch/MeilisearchModule.cs | 5 +- back/src/Kyoo.Postgresql/PostgresContext.cs | 27 +--------- 7 files changed, 76 insertions(+), 37 deletions(-) diff --git a/back/ef.rsp b/back/ef.rsp index 4023d566..1205cb29 100644 --- a/back/ef.rsp +++ b/back/ef.rsp @@ -1,2 +1,2 @@ --project -src/Kyoo.Postgresql/Kyoo.Postgresql.csproj +src/Kyoo.Core diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index a72dab49..db5e99e1 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -20,6 +20,7 @@ using System; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Core.Controllers; +using Kyoo.Core.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; @@ -38,7 +39,7 @@ public static class CoreModule where TRepo : class, IRepository { services.AddScoped(); - services.AddScoped>(x => x.GetRequiredService()); + services.AddScoped>(x => x.GetRequiredService()).AllowLazy(); } public static void ConfigureKyoo(this WebApplicationBuilder builder) diff --git a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs index 9bed18bf..a27509eb 100644 --- a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs +++ b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs @@ -16,7 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; using System.Linq; +using System.Linq.Expressions; using System.Text.Json; using System.Text.Json.Serialization; using AspNetCore.Proxy; @@ -83,4 +85,52 @@ public static class ServiceExtensions services.AddProxies(); services.AddHttpClient(); } + + // Stollen from https://stackoverflow.com/questions/44934511/does-net-core-dependency-injection-support-lazyt + public static IServiceCollection AllowLazy(this IServiceCollection services) + { + ServiceDescriptor lastRegistration = services.Last(); + Type serviceType = lastRegistration.ServiceType; + + // The constructor for Lazy expects a Func which is hard to create dynamically. + Type lazyServiceType = typeof(Lazy<>).MakeGenericType(serviceType); + + // Create a typed MethodInfo for `serviceProvider.GetRequiredService`, + // where T has been resolved to the required ServiceType + System.Reflection.MethodInfo? getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod( + nameof(ServiceProviderServiceExtensions.GetRequiredService), + 1, + [typeof(IServiceProvider)] + ); + + System.Reflection.MethodInfo? getRequiredServiceMethodTyped = getRequiredServiceMethod?.MakeGenericMethod( + serviceType + ); + + // Now create a lambda expression equivalent to: + // + // serviceProvider => serviceProvider.GetRequiredService(); + // + ParameterExpression parameterExpr = Expression.Parameter(typeof(IServiceProvider), "serviceLocator"); + LambdaExpression lambda = Expression.Lambda( + Expression.Call(null, getRequiredServiceMethodTyped!, parameterExpr), + parameterExpr + ); + + Delegate lambdaCompiled = lambda.Compile(); + + services.Add( + new ServiceDescriptor( + lazyServiceType, + serviceProvider => + Activator.CreateInstance( + lazyServiceType, + lambdaCompiled.DynamicInvoke(serviceProvider) + )!, + lastRegistration.Lifetime + ) + ); + + return services; + } } diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj index 49be7338..c1ab42ef 100644 --- a/back/src/Kyoo.Core/Kyoo.Core.csproj +++ b/back/src/Kyoo.Core/Kyoo.Core.csproj @@ -3,6 +3,7 @@ Kyoo.Core Kyoo.Core Exe + kyoo 50 @@ -22,6 +23,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/back/src/Kyoo.Core/Program.cs b/back/src/Kyoo.Core/Program.cs index 3ea03994..ca7eb121 100644 --- a/back/src/Kyoo.Core/Program.cs +++ b/back/src/Kyoo.Core/Program.cs @@ -29,7 +29,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; using Serilog.Templates; @@ -38,7 +37,7 @@ using Serilog.Templates.Themes; #if DEBUG const string EnvironmentName = "Development"; #else - const string EnvironmentName = "Production"; +const string EnvironmentName = "Production"; #endif WebApplicationBuilder builder = WebApplication.CreateBuilder( @@ -72,13 +71,10 @@ AppDomain.CurrentDomain.UnhandledException += (_, ex) => Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception"); builder.Host.UseSerilog(); - -// Set current directory, used by thumbnails for example. -string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); -if (!Directory.Exists(path)) - Directory.CreateDirectory(path); -Environment.CurrentDirectory = path; -Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); +builder + .Services.AddMvcCore() + .AddApplicationPart(typeof(CoreModule).Assembly) + .AddApplicationPart(typeof(AuthenticationModule).Assembly); builder.Services.ConfigureMvc(); builder.Services.ConfigureOpenApi(); @@ -97,6 +93,13 @@ app.UseRouting(); app.UseAuthentication(); app.MapControllers(); +// Set current directory, used by thumbnails for example. +string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); +if (!Directory.Exists(path)) + Directory.CreateDirectory(path); +Environment.CurrentDirectory = path; +Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); + // Activate services that always run in the background app.Services.GetRequiredService(); app.Services.GetRequiredService(); diff --git a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs index 1ba74dae..7fa428e5 100644 --- a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs +++ b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs @@ -16,6 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Meilisearch; @@ -151,7 +154,7 @@ public static class MeilisearchModule builder.Configuration.GetValue("MEILI_MASTER_KEY") ) ); - builder.Services.AddSingleton(); + builder.Services.AddScoped(); builder.Services.AddSingleton(); } } diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index 9bdaa75d..e3cef657 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -33,38 +33,15 @@ using Npgsql; namespace Kyoo.Postgresql; -public class PostgresContext : DatabaseContext +public class PostgresContext(DbContextOptions options, IHttpContextAccessor accessor) + : DatabaseContext(options, accessor) { - /// - /// Should the configure step be skipped? This is used when the database is created via DbContextOptions. - /// - private readonly bool _skipConfigure; - - public PostgresContext(DbContextOptions options, IHttpContextAccessor accessor) - : base(options, accessor) - { - _skipConfigure = true; - } - - /// - /// Set connection information for this database context - /// - /// An option builder to fill. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - if (!_skipConfigure) - { - optionsBuilder.UseNpgsql(); - } - optionsBuilder.UseSnakeCaseNamingConvention(); base.OnConfiguring(optionsBuilder); } - /// - /// Set database parameters to support every types of Kyoo. - /// - /// The database's model builder. protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasPostgresEnum(); From f64cf161ab9adc399495e2c10e31a7a28dcbb91d Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 22:21:42 +0200 Subject: [PATCH 4/9] Remove all autofac references --- .../Kyoo.Abstractions.csproj | 1 - back/src/Kyoo.Abstractions/Module.cs | 75 ------------------- .../AuthenticationModule.cs | 1 - 3 files changed, 77 deletions(-) delete mode 100644 back/src/Kyoo.Abstractions/Module.cs diff --git a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj index 9a05d140..8ee9adb2 100644 --- a/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj +++ b/back/src/Kyoo.Abstractions/Kyoo.Abstractions.csproj @@ -6,7 +6,6 @@ - diff --git a/back/src/Kyoo.Abstractions/Module.cs b/back/src/Kyoo.Abstractions/Module.cs deleted file mode 100644 index 6bdd299a..00000000 --- a/back/src/Kyoo.Abstractions/Module.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Kyoo - A portable and vast media library solution. -// Copyright (c) Kyoo. -// -// See AUTHORS.md and LICENSE file in the project root for full license information. -// -// Kyoo is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// any later version. -// -// Kyoo is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Kyoo. If not, see . - -using Autofac; -using Autofac.Builder; -using Kyoo.Abstractions.Controllers; -using Kyoo.Utils; - -namespace Kyoo.Abstractions; - -/// -/// A static class with helper functions to setup external modules -/// -public static class Module -{ - /// - /// Register a new repository to the container. - /// - /// The container - /// The type of the repository. - /// - /// If your repository implements a special interface, please use - /// - /// The initial container. - public static IRegistrationBuilder< - T, - ConcreteReflectionActivatorData, - SingleRegistrationStyle - > RegisterRepository(this ContainerBuilder builder) - where T : IBaseRepository - { - return builder - .RegisterType() - .AsSelf() - .As() - .As(Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>))!) - .InstancePerLifetimeScope(); - } - - /// - /// Register a new repository with a custom mapping to the container. - /// - /// The container - /// The custom mapping you have for your repository. - /// The type of the repository. - /// - /// If your repository does not implements a special interface, please use - /// - /// The initial container. - public static IRegistrationBuilder< - T2, - ConcreteReflectionActivatorData, - SingleRegistrationStyle - > RegisterRepository(this ContainerBuilder builder) - where T : notnull - where T2 : IBaseRepository, T - { - return builder.RegisterRepository().AsSelf().As(); - } -} diff --git a/back/src/Kyoo.Authentication/AuthenticationModule.cs b/back/src/Kyoo.Authentication/AuthenticationModule.cs index fb9bb1f1..6ce7ebeb 100644 --- a/back/src/Kyoo.Authentication/AuthenticationModule.cs +++ b/back/src/Kyoo.Authentication/AuthenticationModule.cs @@ -20,7 +20,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Autofac; using Kyoo.Abstractions.Controllers; using Kyoo.Authentication.Models; using Microsoft.AspNetCore.Authentication.JwtBearer; From de2308f31971e7ffcc3a19588fc3c26e8c7b787c Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 23:41:45 +0200 Subject: [PATCH 5/9] Fix dotnet ef design time context --- back/ef.rsp | 2 +- back/src/Kyoo.Postgresql/PostgresContext.cs | 14 ++++++++++++++ back/src/Kyoo.Postgresql/PostgresModule.cs | 19 ++++++++++++------- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/back/ef.rsp b/back/ef.rsp index 1205cb29..d57922e4 100644 --- a/back/ef.rsp +++ b/back/ef.rsp @@ -1,2 +1,2 @@ --project -src/Kyoo.Core +src/Kyoo.Postgresql diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index e3cef657..3b8570f4 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -28,7 +28,9 @@ using Kyoo.Postgresql.Utils; using Kyoo.Utils; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.Extensions.Configuration; using Npgsql; namespace Kyoo.Postgresql; @@ -121,3 +123,15 @@ public class PostgresContext(DbContextOptions options, IHttpContextAccessor acce }; } } + +public class PostgresContextBuilder : IDesignTimeDbContextFactory +{ + public PostgresContext CreateDbContext(string[] args) + { + NpgsqlDataSource dataSource = PostgresModule.CreateDataSource(new ConfigurationManager()); + DbContextOptionsBuilder builder = new(); + builder.UseNpgsql(dataSource); + + return new PostgresContext(builder.Options, null!); + } +} diff --git a/back/src/Kyoo.Postgresql/PostgresModule.cs b/back/src/Kyoo.Postgresql/PostgresModule.cs index e4903b94..9b0f9f02 100644 --- a/back/src/Kyoo.Postgresql/PostgresModule.cs +++ b/back/src/Kyoo.Postgresql/PostgresModule.cs @@ -30,16 +30,16 @@ namespace Kyoo.Postgresql; public static class PostgresModule { - public static void ConfigurePostgres(this WebApplicationBuilder builder) + public static NpgsqlDataSource CreateDataSource(IConfiguration configuration) { DbConnectionStringBuilder conBuilder = new() { - ["USER ID"] = builder.Configuration.GetValue("POSTGRES_USER", "KyooUser"), - ["PASSWORD"] = builder.Configuration.GetValue("POSTGRES_PASSWORD", "KyooPassword"), - ["SERVER"] = builder.Configuration.GetValue("POSTGRES_SERVER", "db"), - ["PORT"] = builder.Configuration.GetValue("POSTGRES_PORT", "5432"), - ["DATABASE"] = builder.Configuration.GetValue("POSTGRES_DB", "kyooDB"), + ["USER ID"] = configuration.GetValue("POSTGRES_USER", "KyooUser"), + ["PASSWORD"] = configuration.GetValue("POSTGRES_PASSWORD", "KyooPassword"), + ["SERVER"] = configuration.GetValue("POSTGRES_SERVER", "db"), + ["PORT"] = configuration.GetValue("POSTGRES_PORT", "5432"), + ["DATABASE"] = configuration.GetValue("POSTGRES_DB", "kyooDB"), ["POOLING"] = "true", ["MAXPOOLSIZE"] = "95", ["TIMEOUT"] = "30" @@ -49,7 +49,12 @@ public static class PostgresModule dsBuilder.MapEnum(); dsBuilder.MapEnum(); dsBuilder.MapEnum(); - NpgsqlDataSource dataSource = dsBuilder.Build(); + return dsBuilder.Build(); + } + + public static void ConfigurePostgres(this WebApplicationBuilder builder) + { + NpgsqlDataSource dataSource = CreateDataSource(builder.Configuration); builder.Services.AddDbContext( x => From 1b4d1ef45edeca23578fc942e680ca89424f3876 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 1 Apr 2024 23:42:01 +0200 Subject: [PATCH 6/9] Add genres migrations --- .../20240401213942_AddGenres.Designer.cs | 1380 +++++++++++++++++ .../Migrations/20240401213942_AddGenres.cs | 53 + .../PostgresContextModelSnapshot.cs | 4 +- 3 files changed, 1435 insertions(+), 2 deletions(-) create mode 100644 back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs create mode 100644 back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs diff --git a/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs new file mode 100644 index 00000000..758e37da --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs @@ -0,0 +1,1380 @@ +// +using System; +using System.Collections.Generic; +using Kyoo.Abstractions.Models; +using Kyoo.Postgresql; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations +{ + [DbContext(typeof(PostgresContext))] + [Migration("20240401213942_AddGenres")] + partial class AddGenres + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.3") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresEnum( + modelBuilder, + "genre", + new[] + { + "action", + "adventure", + "animation", + "comedy", + "crime", + "documentary", + "drama", + "family", + "fantasy", + "history", + "horror", + "music", + "mystery", + "romance", + "science_fiction", + "thriller", + "war", + "western", + "kids", + "news", + "reality", + "soap", + "talk", + "politics" + } + ); + NpgsqlModelBuilderExtensions.HasPostgresEnum( + modelBuilder, + "status", + new[] { "unknown", "finished", "airing", "planned" } + ); + NpgsqlModelBuilderExtensions.HasPostgresEnum( + modelBuilder, + "watch_status", + new[] { "completed", "watching", "droped", "planned", "deleted" } + ); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Collection", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview").HasColumnType("text").HasColumnName("overview"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id").HasName("pk_collections"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_collections_slug"); + + b.ToTable("collections", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Episode", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AbsoluteNumber") + .HasColumnType("integer") + .HasColumnName("absolute_number"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EpisodeNumber") + .HasColumnType("integer") + .HasColumnName("episode_number"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name").HasColumnType("text").HasColumnName("name"); + + b.Property("Overview").HasColumnType("text").HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("ReleaseDate") + .HasColumnType("date") + .HasColumnName("release_date"); + + b.Property("Runtime").HasColumnType("integer").HasColumnName("runtime"); + + b.Property("SeasonId").HasColumnType("uuid").HasColumnName("season_id"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId").HasColumnType("uuid").HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id").HasName("pk_episodes"); + + b.HasIndex("SeasonId").HasDatabaseName("ix_episodes_season_id"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_episodes_slug"); + + b.HasIndex("ShowId", "SeasonNumber", "EpisodeNumber", "AbsoluteNumber") + .IsUnique() + .HasDatabaseName( + "ix_episodes_show_id_season_number_episode_number_absolute_numb" + ); + + b.ToTable("episodes", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.EpisodeWatchStatus", + b => + { + b.Property("UserId").HasColumnType("uuid").HasColumnName("user_id"); + + b.Property("EpisodeId") + .HasColumnType("uuid") + .HasColumnName("episode_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "EpisodeId").HasName("pk_episode_watch_status"); + + b.HasIndex("EpisodeId").HasDatabaseName("ix_episode_watch_status_episode_id"); + + b.ToTable("episode_watch_status", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Issue", + b => + { + b.Property("Domain").HasColumnType("text").HasColumnName("domain"); + + b.Property("Cause").HasColumnType("text").HasColumnName("cause"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("Extra") + .IsRequired() + .HasColumnType("json") + .HasColumnName("extra"); + + b.Property("Reason") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reason"); + + b.HasKey("Domain", "Cause").HasName("pk_issues"); + + b.ToTable("issues", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Movie", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("AirDate") + .HasColumnType("date") + .HasColumnName("air_date"); + + b.Property("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property>("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview").HasColumnType("text").HasColumnName("overview"); + + b.Property("Path") + .IsRequired() + .HasColumnType("text") + .HasColumnName("path"); + + b.Property("Rating").HasColumnType("integer").HasColumnName("rating"); + + b.Property("Runtime").HasColumnType("integer").HasColumnName("runtime"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Status").HasColumnType("status").HasColumnName("status"); + + b.Property("StudioId").HasColumnType("uuid").HasColumnName("studio_id"); + + b.Property("Tagline").HasColumnType("text").HasColumnName("tagline"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer").HasColumnType("text").HasColumnName("trailer"); + + b.HasKey("Id").HasName("pk_movies"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_movies_slug"); + + b.HasIndex("StudioId").HasDatabaseName("ix_movies_studio_id"); + + b.ToTable("movies", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.MovieWatchStatus", + b => + { + b.Property("UserId").HasColumnType("uuid").HasColumnName("user_id"); + + b.Property("MovieId").HasColumnType("uuid").HasColumnName("movie_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "MovieId").HasName("pk_movie_watch_status"); + + b.HasIndex("MovieId").HasDatabaseName("ix_movie_watch_status_movie_id"); + + b.ToTable("movie_watch_status", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Season", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("EndDate") + .HasColumnType("date") + .HasColumnName("end_date"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name").HasColumnType("text").HasColumnName("name"); + + b.Property("Overview").HasColumnType("text").HasColumnName("overview"); + + b.Property("SeasonNumber") + .HasColumnType("integer") + .HasColumnName("season_number"); + + b.Property("ShowId").HasColumnType("uuid").HasColumnName("show_id"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartDate") + .HasColumnType("date") + .HasColumnName("start_date"); + + b.HasKey("Id").HasName("pk_seasons"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_seasons_slug"); + + b.HasIndex("ShowId", "SeasonNumber") + .IsUnique() + .HasDatabaseName("ix_seasons_show_id_season_number"); + + b.ToTable("seasons", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Show", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property>("Aliases") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("aliases"); + + b.Property("EndAir").HasColumnType("date").HasColumnName("end_air"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property>("Genres") + .IsRequired() + .HasColumnType("genre[]") + .HasColumnName("genres"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Overview").HasColumnType("text").HasColumnName("overview"); + + b.Property("Rating").HasColumnType("integer").HasColumnName("rating"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("StartAir") + .HasColumnType("date") + .HasColumnName("start_air"); + + b.Property("Status").HasColumnType("status").HasColumnName("status"); + + b.Property("StudioId").HasColumnType("uuid").HasColumnName("studio_id"); + + b.Property("Tagline").HasColumnType("text").HasColumnName("tagline"); + + b.Property>("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.Property("Trailer").HasColumnType("text").HasColumnName("trailer"); + + b.HasKey("Id").HasName("pk_shows"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_shows_slug"); + + b.HasIndex("StudioId").HasDatabaseName("ix_shows_studio_id"); + + b.ToTable("shows", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.ShowWatchStatus", + b => + { + b.Property("UserId").HasColumnType("uuid").HasColumnName("user_id"); + + b.Property("ShowId").HasColumnType("uuid").HasColumnName("show_id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("NextEpisodeId") + .HasColumnType("uuid") + .HasColumnName("next_episode_id"); + + b.Property("PlayedDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("played_date"); + + b.Property("Status") + .HasColumnType("watch_status") + .HasColumnName("status"); + + b.Property("UnseenEpisodesCount") + .HasColumnType("integer") + .HasColumnName("unseen_episodes_count"); + + b.Property("WatchedPercent") + .HasColumnType("integer") + .HasColumnName("watched_percent"); + + b.Property("WatchedTime") + .HasColumnType("integer") + .HasColumnName("watched_time"); + + b.HasKey("UserId", "ShowId").HasName("pk_show_watch_status"); + + b.HasIndex("NextEpisodeId") + .HasDatabaseName("ix_show_watch_status_next_episode_id"); + + b.HasIndex("ShowId").HasDatabaseName("ix_show_watch_status_show_id"); + + b.ToTable("show_watch_status", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Studio", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.HasKey("Id").HasName("pk_studios"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_studios_slug"); + + b.ToTable("studios", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.User", + b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("AddedDate") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("added_date") + .HasDefaultValueSql("now() at time zone 'utc'"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("ExternalId") + .IsRequired() + .HasColumnType("json") + .HasColumnName("external_id"); + + b.Property("Password").HasColumnType("text").HasColumnName("password"); + + b.Property("Permissions") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("permissions"); + + b.Property("Settings") + .IsRequired() + .HasColumnType("json") + .HasColumnName("settings"); + + b.Property("Slug") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)") + .HasColumnName("slug"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.HasKey("Id").HasName("pk_users"); + + b.HasIndex("Slug").IsUnique().HasDatabaseName("ix_users_slug"); + + b.HasIndex("Username").IsUnique().HasDatabaseName("ix_users_username"); + + b.ToTable("users", (string)null); + } + ); + + modelBuilder.Entity( + "link_collection_movie", + b => + { + b.Property("collection_id") + .HasColumnType("uuid") + .HasColumnName("collection_id"); + + b.Property("movie_id").HasColumnType("uuid").HasColumnName("movie_id"); + + b.HasKey("collection_id", "movie_id").HasName("pk_link_collection_movie"); + + b.HasIndex("movie_id").HasDatabaseName("ix_link_collection_movie_movie_id"); + + b.ToTable("link_collection_movie", (string)null); + } + ); + + modelBuilder.Entity( + "link_collection_show", + b => + { + b.Property("collection_id") + .HasColumnType("uuid") + .HasColumnName("collection_id"); + + b.Property("show_id").HasColumnType("uuid").HasColumnName("show_id"); + + b.HasKey("collection_id", "show_id").HasName("pk_link_collection_show"); + + b.HasIndex("show_id").HasDatabaseName("ix_link_collection_show_show_id"); + + b.ToTable("link_collection_show", (string)null); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Collection", + b => + { + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Logo", + b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Poster", + b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Thumbnail", + b1 => + { + b1.Property("CollectionId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("CollectionId"); + + b1.ToTable("collections"); + + b1.WithOwner() + .HasForeignKey("CollectionId") + .HasConstraintName("fk_collections_collections_id"); + } + ); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Thumbnail"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Episode", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Season", "Season") + .WithMany("Episodes") + .HasForeignKey("SeasonId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_episodes_seasons_season_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Episodes") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episodes_shows_show_id"); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Logo", + b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Poster", + b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Thumbnail", + b1 => + { + b1.Property("EpisodeId") + .HasColumnType("uuid") + .HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("EpisodeId"); + + b1.ToTable("episodes"); + + b1.WithOwner() + .HasForeignKey("EpisodeId") + .HasConstraintName("fk_episodes_episodes_id"); + } + ); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Season"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.EpisodeWatchStatus", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "Episode") + .WithMany("Watched") + .HasForeignKey("EpisodeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episode_watch_status_episodes_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_episode_watch_status_users_user_id"); + + b.Navigation("Episode"); + + b.Navigation("User"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Movie", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Movies") + .HasForeignKey("StudioId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_movies_studios_studio_id"); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Logo", + b1 => + { + b1.Property("MovieId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Poster", + b1 => + { + b1.Property("MovieId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Thumbnail", + b1 => + { + b1.Property("MovieId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("MovieId"); + + b1.ToTable("movies"); + + b1.WithOwner() + .HasForeignKey("MovieId") + .HasConstraintName("fk_movies_movies_id"); + } + ); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.MovieWatchStatus", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Movie", "Movie") + .WithMany("Watched") + .HasForeignKey("MovieId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_movie_watch_status_movies_movie_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_movie_watch_status_users_user_id"); + + b.Navigation("Movie"); + + b.Navigation("User"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Season", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Seasons") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_seasons_shows_show_id"); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Logo", + b1 => + { + b1.Property("SeasonId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Poster", + b1 => + { + b1.Property("SeasonId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Thumbnail", + b1 => + { + b1.Property("SeasonId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("SeasonId"); + + b1.ToTable("seasons"); + + b1.WithOwner() + .HasForeignKey("SeasonId") + .HasConstraintName("fk_seasons_seasons_id"); + } + ); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Show"); + + b.Navigation("Thumbnail"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Show", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Studio", "Studio") + .WithMany("Shows") + .HasForeignKey("StudioId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_shows_studios_studio_id"); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Logo", + b1 => + { + b1.Property("ShowId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("logo_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("logo_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Poster", + b1 => + { + b1.Property("ShowId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("poster_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("poster_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + } + ); + + b.OwnsOne( + "Kyoo.Abstractions.Models.Image", + "Thumbnail", + b1 => + { + b1.Property("ShowId").HasColumnType("uuid").HasColumnName("id"); + + b1.Property("Blurhash") + .IsRequired() + .HasMaxLength(32) + .HasColumnType("character varying(32)") + .HasColumnName("thumbnail_blurhash"); + + b1.Property("Source") + .IsRequired() + .HasColumnType("text") + .HasColumnName("thumbnail_source"); + + b1.HasKey("ShowId"); + + b1.ToTable("shows"); + + b1.WithOwner() + .HasForeignKey("ShowId") + .HasConstraintName("fk_shows_shows_id"); + } + ); + + b.Navigation("Logo"); + + b.Navigation("Poster"); + + b.Navigation("Studio"); + + b.Navigation("Thumbnail"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.ShowWatchStatus", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Episode", "NextEpisode") + .WithMany() + .HasForeignKey("NextEpisodeId") + .OnDelete(DeleteBehavior.SetNull) + .HasConstraintName("fk_show_watch_status_episodes_next_episode_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", "Show") + .WithMany("Watched") + .HasForeignKey("ShowId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_show_watch_status_shows_show_id"); + + b.HasOne("Kyoo.Abstractions.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_show_watch_status_users_user_id"); + + b.Navigation("NextEpisode"); + + b.Navigation("Show"); + + b.Navigation("User"); + } + ); + + modelBuilder.Entity( + "link_collection_movie", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Movie", null) + .WithMany() + .HasForeignKey("movie_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_movie_movies_movie_id"); + } + ); + + modelBuilder.Entity( + "link_collection_show", + b => + { + b.HasOne("Kyoo.Abstractions.Models.Collection", null) + .WithMany() + .HasForeignKey("collection_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_collections_collection_id"); + + b.HasOne("Kyoo.Abstractions.Models.Show", null) + .WithMany() + .HasForeignKey("show_id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_link_collection_show_shows_show_id"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Episode", + b => + { + b.Navigation("Watched"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Movie", + b => + { + b.Navigation("Watched"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Season", + b => + { + b.Navigation("Episodes"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Show", + b => + { + b.Navigation("Episodes"); + + b.Navigation("Seasons"); + + b.Navigation("Watched"); + } + ); + + modelBuilder.Entity( + "Kyoo.Abstractions.Models.Studio", + b => + { + b.Navigation("Movies"); + + b.Navigation("Shows"); + } + ); +#pragma warning restore 612, 618 + } + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs new file mode 100644 index 00000000..bb362c8a --- /dev/null +++ b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs @@ -0,0 +1,53 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Kyoo.Postgresql.Migrations; + +/// +public partial class AddGenres : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder + .AlterDatabase() + .Annotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western,kids,news,reality,soap,talk,politics" + ) + .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted") + .OldAnnotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .OldAnnotation( + "Npgsql:Enum:watch_status", + "completed,watching,droped,planned,deleted" + ); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder + .AlterDatabase() + .Annotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" + ) + .Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted") + .OldAnnotation( + "Npgsql:Enum:genre", + "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western,kids,news,reality,soap,talk,politics" + ) + .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") + .OldAnnotation( + "Npgsql:Enum:watch_status", + "completed,watching,droped,planned,deleted" + ); + } +} diff --git a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs index 0a1e4337..a5bfe925 100644 --- a/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs +++ b/back/src/Kyoo.Postgresql/Migrations/PostgresContextModelSnapshot.cs @@ -22,7 +22,7 @@ namespace Kyoo.Postgresql.Migrations .HasAnnotation("ProductVersion", "8.0.3") .HasAnnotation("Relational:MaxIdentifierLength", 63); - NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "genre", new[] { "action", "adventure", "animation", "comedy", "crime", "documentary", "drama", "family", "fantasy", "history", "horror", "music", "mystery", "romance", "science_fiction", "thriller", "war", "western" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "genre", new[] { "action", "adventure", "animation", "comedy", "crime", "documentary", "drama", "family", "fantasy", "history", "horror", "music", "mystery", "romance", "science_fiction", "thriller", "war", "western", "kids", "news", "reality", "soap", "talk", "politics" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "status", new[] { "unknown", "finished", "airing", "planned" }); NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "watch_status", new[] { "completed", "watching", "droped", "planned", "deleted" }); NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); @@ -252,7 +252,7 @@ namespace Kyoo.Postgresql.Migrations .HasColumnType("json") .HasColumnName("external_id"); - b.Property("Genres") + b.Property>("Genres") .IsRequired() .HasColumnType("genre[]") .HasColumnName("genres"); From 7ee28f4557c3fa555a72a728889c99100676d125 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 2 Apr 2024 23:05:26 +0200 Subject: [PATCH 7/9] Update dockerfile --- back/Dockerfile | 2 +- back/Dockerfile.dev | 2 +- back/src/Kyoo.Core/Program.cs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/back/Dockerfile b/back/Dockerfile index 4412eefa..71b33142 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -26,4 +26,4 @@ WORKDIR /kyoo EXPOSE 5000 # The back can take a long time to start if meilisearch is initializing HEALTHCHECK --interval=5s --retries=15 CMD curl --fail http://localhost:5000/health || exit -ENTRYPOINT ["/app/Kyoo.Host"] +ENTRYPOINT ["/app/kyoo"] diff --git a/back/Dockerfile.dev b/back/Dockerfile.dev index 2081618b..6f3e1a27 100644 --- a/back/Dockerfile.dev +++ b/back/Dockerfile.dev @@ -19,4 +19,4 @@ EXPOSE 5000 ENV DOTNET_USE_POLLING_FILE_WATCHER 1 # HEALTHCHECK --interval=5s CMD curl --fail http://localhost:5000/health || exit HEALTHCHECK CMD true -ENTRYPOINT ["dotnet", "watch", "--non-interactive", "run", "--no-restore", "--project", "/app/src/Kyoo.Host"] +ENTRYPOINT ["dotnet", "watch", "--non-interactive", "run", "--no-restore", "--project", "/app/src/Kyoo.Core"] diff --git a/back/src/Kyoo.Core/Program.cs b/back/src/Kyoo.Core/Program.cs index ca7eb121..68c9462b 100644 --- a/back/src/Kyoo.Core/Program.cs +++ b/back/src/Kyoo.Core/Program.cs @@ -82,6 +82,7 @@ builder.ConfigureKyoo(); builder.ConfigureAuthentication(); builder.ConfigurePostgres(); builder.ConfigureMeilisearch(); +builder.ConfigureRabbitMq(); WebApplication app = builder.Build(); CoreModule.Services = app.Services; From 8a639a3aeec4759ddf57227d5f660daf6751cf1f Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 2 Apr 2024 23:14:01 +0200 Subject: [PATCH 8/9] Simplify lazy creation --- back/src/Kyoo.Core/CoreModule.cs | 4 +- .../Kyoo.Core/Extensions/ServiceExtensions.cs | 48 ------------------- 2 files changed, 2 insertions(+), 50 deletions(-) diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index db5e99e1..114cddd4 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -20,7 +20,6 @@ using System; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Core.Controllers; -using Kyoo.Core.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; @@ -39,7 +38,8 @@ public static class CoreModule where TRepo : class, IRepository { services.AddScoped(); - services.AddScoped>(x => x.GetRequiredService()).AllowLazy(); + services.AddScoped>(x => x.GetRequiredService()); + services.AddScoped>>(x => new(() => x.GetRequiredService())); } public static void ConfigureKyoo(this WebApplicationBuilder builder) diff --git a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs index a27509eb..2c92fb56 100644 --- a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs +++ b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs @@ -85,52 +85,4 @@ public static class ServiceExtensions services.AddProxies(); services.AddHttpClient(); } - - // Stollen from https://stackoverflow.com/questions/44934511/does-net-core-dependency-injection-support-lazyt - public static IServiceCollection AllowLazy(this IServiceCollection services) - { - ServiceDescriptor lastRegistration = services.Last(); - Type serviceType = lastRegistration.ServiceType; - - // The constructor for Lazy expects a Func which is hard to create dynamically. - Type lazyServiceType = typeof(Lazy<>).MakeGenericType(serviceType); - - // Create a typed MethodInfo for `serviceProvider.GetRequiredService`, - // where T has been resolved to the required ServiceType - System.Reflection.MethodInfo? getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod( - nameof(ServiceProviderServiceExtensions.GetRequiredService), - 1, - [typeof(IServiceProvider)] - ); - - System.Reflection.MethodInfo? getRequiredServiceMethodTyped = getRequiredServiceMethod?.MakeGenericMethod( - serviceType - ); - - // Now create a lambda expression equivalent to: - // - // serviceProvider => serviceProvider.GetRequiredService(); - // - ParameterExpression parameterExpr = Expression.Parameter(typeof(IServiceProvider), "serviceLocator"); - LambdaExpression lambda = Expression.Lambda( - Expression.Call(null, getRequiredServiceMethodTyped!, parameterExpr), - parameterExpr - ); - - Delegate lambdaCompiled = lambda.Compile(); - - services.Add( - new ServiceDescriptor( - lazyServiceType, - serviceProvider => - Activator.CreateInstance( - lazyServiceType, - lambdaCompiled.DynamicInvoke(serviceProvider) - )!, - lastRegistration.Lifetime - ) - ); - - return services; - } } From 8758c7447e505fb00591607e3c7b3be95bd797d1 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 2 Apr 2024 23:24:24 +0200 Subject: [PATCH 9/9] Format code --- back/Dockerfile | 2 +- back/src/Kyoo.Core/CoreModule.cs | 2 +- back/src/Kyoo.Meilisearch/MeilisearchModule.cs | 13 ++++++------- .../Migrations/20240324174638_UseDateOnly.cs | 5 +---- .../Migrations/20240401213942_AddGenres.cs | 10 ++-------- .../providers/implementations/themoviedatabase.py | 9 ++++----- 6 files changed, 15 insertions(+), 26 deletions(-) diff --git a/back/Dockerfile b/back/Dockerfile index 71b33142..a29161df 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -16,7 +16,7 @@ RUN dotnet restore -a $TARGETARCH COPY . . ARG VERSION -RUN dotnet publish -a $TARGETARCH --no-restore -c Release -o /app "-p:Version=${VERSION:-"0.0.0-dev"}" src/Kyoo.Host +RUN dotnet publish -a $TARGETARCH --no-restore -c Release -o /app "-p:Version=${VERSION:-"0.0.0-dev"}" src/Kyoo.Core FROM mcr.microsoft.com/dotnet/aspnet:8.0 RUN apt-get update && apt-get install -y curl diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index 114cddd4..05d3a36c 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -34,7 +34,7 @@ public static class CoreModule public static IServiceProvider Services { get; set; } public static void AddRepository(this IServiceCollection services) - where T:IResource + where T : IResource where TRepo : class, IRepository { services.AddScoped(); diff --git a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs index 7fa428e5..bc09420e 100644 --- a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs +++ b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs @@ -147,13 +147,12 @@ public static class MeilisearchModule /// public static void ConfigureMeilisearch(this WebApplicationBuilder builder) { - builder - .Services.AddSingleton( - new MeilisearchClient( - builder.Configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"), - builder.Configuration.GetValue("MEILI_MASTER_KEY") - ) - ); + builder.Services.AddSingleton( + new MeilisearchClient( + builder.Configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"), + builder.Configuration.GetValue("MEILI_MASTER_KEY") + ) + ); builder.Services.AddScoped(); builder.Services.AddSingleton(); } diff --git a/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs b/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs index 53cf7cc3..eb82dddf 100644 --- a/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs +++ b/back/src/Kyoo.Postgresql/Migrations/20240324174638_UseDateOnly.cs @@ -112,10 +112,7 @@ public partial class UseDateOnly : Migration "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" ) .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation( - "Npgsql:Enum:watch_status", - "completed,watching,droped,planned,deleted" - ); + .OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted"); migrationBuilder.AlterColumn( name: "start_air", diff --git a/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs index bb362c8a..6cb5aa67 100644 --- a/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs +++ b/back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.cs @@ -23,10 +23,7 @@ public partial class AddGenres : Migration "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western" ) .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation( - "Npgsql:Enum:watch_status", - "completed,watching,droped,planned,deleted" - ); + .OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted"); } /// @@ -45,9 +42,6 @@ public partial class AddGenres : Migration "action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western,kids,news,reality,soap,talk,politics" ) .OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned") - .OldAnnotation( - "Npgsql:Enum:watch_status", - "completed,watching,droped,planned,deleted" - ); + .OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted"); } } diff --git a/scanner/providers/implementations/themoviedatabase.py b/scanner/providers/implementations/themoviedatabase.py index 3b86e3ab..eb1971fa 100644 --- a/scanner/providers/implementations/themoviedatabase.py +++ b/scanner/providers/implementations/themoviedatabase.py @@ -75,11 +75,10 @@ class TheMovieDatabase(Provider): if isinstance(x, list): return [j for i in x for j in flatten(i)] return [x] - return flatten([ - self.genre_map[x["id"]] - for x in genres - if x["id"] in self.genre_map - ]) + + return flatten( + [self.genre_map[x["id"]] for x in genres if x["id"] in self.genre_map] + ) def get_languages(self, *args): return self._languages + list(args)