mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-23 15:30:34 -04:00
Add tv specifics genres (#371)
This commit is contained in:
commit
25be3d77a5
@ -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.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.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.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.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.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||||
@ -17,7 +16,7 @@ RUN dotnet restore -a $TARGETARCH
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
ARG VERSION
|
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
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||||
RUN apt-get update && apt-get install -y curl
|
RUN apt-get update && apt-get install -y curl
|
||||||
@ -27,4 +26,4 @@ WORKDIR /kyoo
|
|||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
# The back can take a long time to start if meilisearch is initializing
|
# 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
|
HEALTHCHECK --interval=5s --retries=15 CMD curl --fail http://localhost:5000/health || exit
|
||||||
ENTRYPOINT ["/app/Kyoo.Host"]
|
ENTRYPOINT ["/app/kyoo"]
|
||||||
|
@ -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.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.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.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.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.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||||
@ -20,4 +19,4 @@ EXPOSE 5000
|
|||||||
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
|
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
|
||||||
# HEALTHCHECK --interval=5s CMD curl --fail http://localhost:5000/health || exit
|
# HEALTHCHECK --interval=5s CMD curl --fail http://localhost:5000/health || exit
|
||||||
HEALTHCHECK CMD true
|
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"]
|
||||||
|
@ -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.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.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.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.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.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||||
|
@ -10,8 +10,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
|
||||||
EndProject
|
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}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.RabbitMq", "src\Kyoo.RabbitMq\Kyoo.RabbitMq.csproj", "{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}"
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.Build.0 = 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
|
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
--project
|
--project
|
||||||
src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
src/Kyoo.Postgresql
|
||||||
--msbuildprojectextensionspath
|
|
||||||
out/obj/Kyoo.Postgresql
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<LangVersion>default</LangVersion>
|
<LangVersion>default</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
<Company>Kyoo</Company>
|
<Company>Kyoo</Company>
|
||||||
<Authors>Kyoo</Authors>
|
<Authors>Kyoo</Authors>
|
||||||
<Copyright>Copyright (c) Kyoo</Copyright>
|
<Copyright>Copyright (c) Kyoo</Copyright>
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Autofac;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A common interface used to discord plugins
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// You can inject services in the IPlugin constructor.
|
|
||||||
/// You should only inject well known services like an ILogger, IConfiguration or IWebHostEnvironment.
|
|
||||||
/// </remarks>
|
|
||||||
public interface IPlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the plugin
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An optional configuration step to allow a plugin to change asp net configurations.
|
|
||||||
/// </summary>
|
|
||||||
/// <seealso cref="SA"/>
|
|
||||||
IEnumerable<IStartupAction> ConfigureSteps => ArraySegment<IStartupAction>.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A configure method that will be run on plugin's startup.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The autofac service container to register services.</param>
|
|
||||||
void Configure(ContainerBuilder builder)
|
|
||||||
{
|
|
||||||
// Skipped
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A configure method that will be run on plugin's startup.
|
|
||||||
/// This is available for libraries that build upon a <see cref="IServiceCollection"/>, for more precise
|
|
||||||
/// configuration use <see cref="Configure(Autofac.ContainerBuilder)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="services">A service container to register new services.</param>
|
|
||||||
void Configure(IServiceCollection services)
|
|
||||||
{
|
|
||||||
// Skipped
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Kyoo.Abstractions.Models.Exceptions;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A manager to load plugins and retrieve information from them.
|
|
||||||
/// </summary>
|
|
||||||
public interface IPluginManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Get a single plugin that match the type and name given.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name of the plugin</param>
|
|
||||||
/// <typeparam name="T">The type of the plugin</typeparam>
|
|
||||||
/// <exception cref="ItemNotFoundException">If no plugins match the query</exception>
|
|
||||||
/// <returns>A plugin that match the queries</returns>
|
|
||||||
public T GetPlugin<T>(string name);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all plugins of the given type.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of plugins to get</typeparam>
|
|
||||||
/// <returns>A list of plugins matching the given type or an empty list of none match.</returns>
|
|
||||||
public ICollection<T> GetPlugins<T>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>All plugins currently loaded.</returns>
|
|
||||||
public ICollection<IPlugin> GetAllPlugins();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load plugins and their dependencies from the plugin directory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugins">
|
|
||||||
/// An initial plugin list to use.
|
|
||||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
|
||||||
/// </param>
|
|
||||||
public void LoadPlugins(ICollection<IPlugin> plugins);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Load plugins and their dependencies from the plugin directory.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugins">
|
|
||||||
/// An initial plugin list to use.
|
|
||||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
|
||||||
/// </param>
|
|
||||||
public void LoadPlugins(params Type[] plugins);
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A list of constant priorities used for <see cref="IStartupAction"/>'s <see cref="IStartupAction.Priority"/>.
|
|
||||||
/// It also contains helper methods for creating new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
public static class SA
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The highest predefined priority existing for <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
public const int Before = 5000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Items defining routing (see IApplicationBuilder.UseRouting use this priority.
|
|
||||||
/// </summary>
|
|
||||||
public const int Routing = 4000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Actions defining new static files router use this priority.
|
|
||||||
/// </summary>
|
|
||||||
public const int StaticFiles = 3000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Actions calling IApplicationBuilder.UseAuthentication use this priority.
|
|
||||||
/// </summary>
|
|
||||||
public const int Authentication = 2000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Actions calling IApplicationBuilder.UseAuthorization use this priority.
|
|
||||||
/// </summary>
|
|
||||||
public const int Authorization = 1000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Action adding endpoint should use this priority (with a negative modificator if there is a catchall).
|
|
||||||
/// </summary>
|
|
||||||
public const int Endpoint = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The lowest predefined priority existing for <see cref="StartupAction"/>.
|
|
||||||
/// It should run after all other actions.
|
|
||||||
/// </summary>
|
|
||||||
public const int After = -1000;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to run</param>
|
|
||||||
/// <param name="priority">The priority of the new action</param>
|
|
||||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
|
||||||
public static StartupAction New(Action action, int priority) => new(action, priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to run</param>
|
|
||||||
/// <param name="priority">The priority of the new action</param>
|
|
||||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
|
||||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
|
||||||
public static StartupAction<T> New<T>(Action<T> action, int priority)
|
|
||||||
where T : notnull => new(action, priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to run</param>
|
|
||||||
/// <param name="priority">The priority of the new action</param>
|
|
||||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
|
||||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
|
||||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
|
||||||
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
|
|
||||||
where T : notnull
|
|
||||||
where T2 : notnull => new(action, priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to run</param>
|
|
||||||
/// <param name="priority">The priority of the new action</param>
|
|
||||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
|
||||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
|
||||||
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
|
|
||||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
|
||||||
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
|
|
||||||
where T : notnull
|
|
||||||
where T2 : notnull
|
|
||||||
where T3 : notnull => new(action, priority);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="IStartupAction"/> with no dependencies.
|
|
||||||
/// </summary>
|
|
||||||
public class StartupAction : IStartupAction
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The action to execute at startup.
|
|
||||||
/// </summary>
|
|
||||||
private readonly Action _action;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Priority { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute on startup.</param>
|
|
||||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
|
||||||
public StartupAction(Action action, int priority)
|
|
||||||
{
|
|
||||||
_action = action;
|
|
||||||
Priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Run(IServiceProvider provider)
|
|
||||||
{
|
|
||||||
_action.Invoke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="IStartupAction"/> with one dependencies.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
|
||||||
public class StartupAction<T> : IStartupAction
|
|
||||||
where T : notnull
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The action to execute at startup.
|
|
||||||
/// </summary>
|
|
||||||
private readonly Action<T> _action;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Priority { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute on startup.</param>
|
|
||||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
|
||||||
public StartupAction(Action<T> action, int priority)
|
|
||||||
{
|
|
||||||
_action = action;
|
|
||||||
Priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Run(IServiceProvider provider)
|
|
||||||
{
|
|
||||||
_action.Invoke(provider.GetRequiredService<T>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="IStartupAction"/> with two dependencies.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
|
||||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
|
||||||
public class StartupAction<T, T2> : IStartupAction
|
|
||||||
where T : notnull
|
|
||||||
where T2 : notnull
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The action to execute at startup.
|
|
||||||
/// </summary>
|
|
||||||
private readonly Action<T, T2> _action;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Priority { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction{T, T2}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute on startup.</param>
|
|
||||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
|
||||||
public StartupAction(Action<T, T2> action, int priority)
|
|
||||||
{
|
|
||||||
_action = action;
|
|
||||||
Priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Run(IServiceProvider provider)
|
|
||||||
{
|
|
||||||
_action.Invoke(provider.GetRequiredService<T>(), provider.GetRequiredService<T2>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="IStartupAction"/> with three dependencies.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The dependency to use.</typeparam>
|
|
||||||
/// <typeparam name="T2">The second dependency to use.</typeparam>
|
|
||||||
/// <typeparam name="T3">The third dependency to use.</typeparam>
|
|
||||||
public class StartupAction<T, T2, T3> : IStartupAction
|
|
||||||
where T : notnull
|
|
||||||
where T2 : notnull
|
|
||||||
where T3 : notnull
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The action to execute at startup.
|
|
||||||
/// </summary>
|
|
||||||
private readonly Action<T, T2, T3> _action;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public int Priority { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="action">The action to execute on startup.</param>
|
|
||||||
/// <param name="priority">The priority of this action (see <see cref="Priority"/>).</param>
|
|
||||||
public StartupAction(Action<T, T2, T3> action, int priority)
|
|
||||||
{
|
|
||||||
_action = action;
|
|
||||||
Priority = priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Run(IServiceProvider provider)
|
|
||||||
{
|
|
||||||
_action.Invoke(
|
|
||||||
provider.GetRequiredService<T>(),
|
|
||||||
provider.GetRequiredService<T2>(),
|
|
||||||
provider.GetRequiredService<T3>()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An action executed on kyoo's startup to initialize the asp-net container.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is the base interface, see <see cref="SA.StartupAction"/> for a simpler use of this.
|
|
||||||
/// </remarks>
|
|
||||||
public interface IStartupAction
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
int Priority { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Run this action to configure the container, a service provider containing all services can be used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider">The service provider containing all services can be used.</param>
|
|
||||||
void Run(IServiceProvider provider);
|
|
||||||
}
|
|
@ -3,11 +3,9 @@
|
|||||||
<Title>Kyoo.Abstractions</Title>
|
<Title>Kyoo.Abstractions</Title>
|
||||||
<Description>Base package to create plugins for Kyoo.</Description>
|
<Description>Base package to create plugins for Kyoo.</Description>
|
||||||
<RootNamespace>Kyoo.Abstractions</RootNamespace>
|
<RootNamespace>Kyoo.Abstractions</RootNamespace>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Autofac" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Dapper" Version="2.1.37" />
|
<PackageReference Include="Dapper" Version="2.1.37" />
|
||||||
<PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" />
|
<PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||||
|
@ -41,4 +41,10 @@ public enum Genre
|
|||||||
Thriller,
|
Thriller,
|
||||||
War,
|
War,
|
||||||
Western,
|
Western,
|
||||||
|
Kids,
|
||||||
|
News,
|
||||||
|
Reality,
|
||||||
|
Soap,
|
||||||
|
Talk,
|
||||||
|
Politics,
|
||||||
}
|
}
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using Autofac;
|
|
||||||
using Autofac.Builder;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Utils;
|
|
||||||
|
|
||||||
namespace Kyoo.Abstractions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A static class with helper functions to setup external modules
|
|
||||||
/// </summary>
|
|
||||||
public static class Module
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Register a new repository to the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The container</param>
|
|
||||||
/// <typeparam name="T">The type of the repository.</typeparam>
|
|
||||||
/// <remarks>
|
|
||||||
/// If your repository implements a special interface, please use <see cref="RegisterRepository{T,T2}"/>
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>The initial container.</returns>
|
|
||||||
public static IRegistrationBuilder<
|
|
||||||
T,
|
|
||||||
ConcreteReflectionActivatorData,
|
|
||||||
SingleRegistrationStyle
|
|
||||||
> RegisterRepository<T>(this ContainerBuilder builder)
|
|
||||||
where T : IBaseRepository
|
|
||||||
{
|
|
||||||
return builder
|
|
||||||
.RegisterType<T>()
|
|
||||||
.AsSelf()
|
|
||||||
.As<IBaseRepository>()
|
|
||||||
.As(Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>))!)
|
|
||||||
.InstancePerLifetimeScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register a new repository with a custom mapping to the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The container</param>
|
|
||||||
/// <typeparam name="T">The custom mapping you have for your repository.</typeparam>
|
|
||||||
/// <typeparam name="T2">The type of the repository.</typeparam>
|
|
||||||
/// <remarks>
|
|
||||||
/// If your repository does not implements a special interface, please use <see cref="RegisterRepository{T}"/>
|
|
||||||
/// </remarks>
|
|
||||||
/// <returns>The initial container.</returns>
|
|
||||||
public static IRegistrationBuilder<
|
|
||||||
T2,
|
|
||||||
ConcreteReflectionActivatorData,
|
|
||||||
SingleRegistrationStyle
|
|
||||||
> RegisterRepository<T, T2>(this ContainerBuilder builder)
|
|
||||||
where T : notnull
|
|
||||||
where T2 : IBaseRepository, T
|
|
||||||
{
|
|
||||||
return builder.RegisterRepository<T2>().AsSelf().As<T>();
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,74 +16,51 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Autofac;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Authentication.Models;
|
using Kyoo.Authentication.Models;
|
||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace Kyoo.Authentication;
|
namespace Kyoo.Authentication;
|
||||||
|
|
||||||
/// <summary>
|
public static class AuthenticationModule
|
||||||
/// A module that enable OpenID authentication for Kyoo.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Create a new authentication module instance and use the given configuration.
|
|
||||||
/// </remarks>
|
|
||||||
public class AuthenticationModule(
|
|
||||||
IConfiguration configuration,
|
|
||||||
ILogger<AuthenticationModule> logger
|
|
||||||
) : IPlugin
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
public static void ConfigureAuthentication(this WebApplicationBuilder builder)
|
||||||
public string Name => "Authentication";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The configuration to use.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IConfiguration _configuration = configuration;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(ContainerBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder.RegisterType<PermissionValidator>().As<IPermissionValidator>().SingleInstance();
|
string secret = builder.Configuration.GetValue(
|
||||||
builder.RegisterType<TokenController>().As<ITokenController>().SingleInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(IServiceCollection services)
|
|
||||||
{
|
|
||||||
string secret = _configuration.GetValue(
|
|
||||||
"AUTHENTICATION_SECRET",
|
"AUTHENTICATION_SECRET",
|
||||||
AuthenticationOption.DefaultSecret
|
AuthenticationOption.DefaultSecret
|
||||||
)!;
|
)!;
|
||||||
PermissionOption options =
|
PermissionOption options =
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Default = _configuration
|
Default = builder
|
||||||
.GetValue("UNLOGGED_PERMISSIONS", "")!
|
.Configuration.GetValue("UNLOGGED_PERMISSIONS", "")!
|
||||||
.Split(',')
|
.Split(',')
|
||||||
.Where(x => x.Length > 0)
|
.Where(x => x.Length > 0)
|
||||||
.ToArray(),
|
.ToArray(),
|
||||||
NewUser = _configuration
|
NewUser = builder
|
||||||
.GetValue("DEFAULT_PERMISSIONS", "overall.read,overall.play")!
|
.Configuration.GetValue("DEFAULT_PERMISSIONS", "overall.read,overall.play")!
|
||||||
.Split(','),
|
.Split(','),
|
||||||
RequireVerification = _configuration.GetValue("REQUIRE_ACCOUNT_VERIFICATION", true),
|
RequireVerification = builder.Configuration.GetValue(
|
||||||
|
"REQUIRE_ACCOUNT_VERIFICATION",
|
||||||
|
true
|
||||||
|
),
|
||||||
PublicUrl =
|
PublicUrl =
|
||||||
_configuration.GetValue<string?>("PUBLIC_URL") ?? "http://localhost:8901",
|
builder.Configuration.GetValue<string?>("PUBLIC_URL")
|
||||||
ApiKeys = _configuration.GetValue("KYOO_APIKEYS", string.Empty)!.Split(','),
|
?? "http://localhost:8901",
|
||||||
OIDC = _configuration
|
ApiKeys = builder.Configuration.GetValue("KYOO_APIKEYS", string.Empty)!.Split(','),
|
||||||
.AsEnumerable()
|
OIDC = builder
|
||||||
|
.Configuration.AsEnumerable()
|
||||||
.Where((pair) => pair.Key.StartsWith("OIDC_"))
|
.Where((pair) => pair.Key.StartsWith("OIDC_"))
|
||||||
.Aggregate(
|
.Aggregate(
|
||||||
new Dictionary<string, OidcProvider>(),
|
new Dictionary<string, OidcProvider>(),
|
||||||
@ -93,7 +70,7 @@ public class AuthenticationModule(
|
|||||||
return acc;
|
return acc;
|
||||||
if (val.Key.Split("_") is not ["OIDC", string provider, string key])
|
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;
|
return acc;
|
||||||
}
|
}
|
||||||
provider = provider.ToLowerInvariant();
|
provider = provider.ToLowerInvariant();
|
||||||
@ -129,20 +106,20 @@ public class AuthenticationModule(
|
|||||||
acc[provider].LogoUrl = val.Value;
|
acc[provider].LogoUrl = val.Value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.LogError("Invalid oidc config value: {Key}", key);
|
Log.Error("Invalid oidc config value: {Key}", key);
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
services.AddSingleton(options);
|
builder.Services.AddSingleton(options);
|
||||||
services.AddSingleton(
|
builder.Services.AddSingleton(
|
||||||
new AuthenticationOption() { Secret = secret, Permissions = options, }
|
new AuthenticationOption() { Secret = secret, Permissions = options, }
|
||||||
);
|
);
|
||||||
|
|
||||||
services
|
builder
|
||||||
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
.AddJwtBearer(options =>
|
.AddJwtBearer(options =>
|
||||||
{
|
{
|
||||||
options.Events = new()
|
options.Events = new()
|
||||||
@ -171,12 +148,8 @@ public class AuthenticationModule(
|
|||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret))
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
builder.Services.AddSingleton<IPermissionValidator, PermissionValidator>();
|
||||||
public IEnumerable<IStartupAction> ConfigureSteps =>
|
builder.Services.AddSingleton<ITokenController, TokenController>();
|
||||||
new IStartupAction[]
|
}
|
||||||
{
|
|
||||||
SA.New<IApplicationBuilder>(app => app.UseAuthentication(), SA.Authentication),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.3" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.3" />
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
|
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||||
|
|
||||||
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -53,8 +53,8 @@ public class LibraryManager : ILibraryManager
|
|||||||
Studios = studioRepository;
|
Studios = studioRepository;
|
||||||
Users = userRepository;
|
Users = userRepository;
|
||||||
|
|
||||||
_repositories = new IBaseRepository[]
|
_repositories =
|
||||||
{
|
[
|
||||||
LibraryItems,
|
LibraryItems,
|
||||||
News,
|
News,
|
||||||
Collections,
|
Collections,
|
||||||
@ -64,7 +64,7 @@ public class LibraryManager : ILibraryManager
|
|||||||
Episodes,
|
Episodes,
|
||||||
Studios,
|
Studios,
|
||||||
Users
|
Users
|
||||||
};
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -42,7 +42,7 @@ public class ThumbnailsManager(
|
|||||||
Lazy<IRepository<User>> users
|
Lazy<IRepository<User>> users
|
||||||
) : IThumbnailsManager
|
) : IThumbnailsManager
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, TaskCompletionSource<object>> _downloading = new();
|
private static readonly Dictionary<string, TaskCompletionSource<object>> _downloading = [];
|
||||||
|
|
||||||
private static async Task _WriteTo(SKBitmap bitmap, string path, int quality)
|
private static async Task _WriteTo(SKBitmap bitmap, string path, int quality)
|
||||||
{
|
{
|
||||||
|
@ -17,29 +17,15 @@
|
|||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
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.Controllers;
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models;
|
||||||
using Kyoo.Core.Api;
|
|
||||||
using Kyoo.Core.Controllers;
|
using Kyoo.Core.Controllers;
|
||||||
using Kyoo.Utils;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Kyoo.Core;
|
namespace Kyoo.Core;
|
||||||
|
|
||||||
/// <summary>
|
public static class CoreModule
|
||||||
/// The core module containing default implementations
|
|
||||||
/// </summary>
|
|
||||||
public class CoreModule : IPlugin
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A service provider to access services in static context (in events for example).
|
/// A service provider to access services in static context (in events for example).
|
||||||
@ -47,102 +33,32 @@ public class CoreModule : IPlugin
|
|||||||
/// <remarks>Don't forget to create a scope.</remarks>
|
/// <remarks>Don't forget to create a scope.</remarks>
|
||||||
public static IServiceProvider Services { get; set; }
|
public static IServiceProvider Services { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
public static void AddRepository<T, TRepo>(this IServiceCollection services)
|
||||||
public string Name => "Core";
|
where T : IResource
|
||||||
|
where TRepo : class, IRepository<T>
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(ContainerBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder
|
services.AddScoped<TRepo>();
|
||||||
.RegisterType<ThumbnailsManager>()
|
services.AddScoped<IRepository<T>>(x => x.GetRequiredService<TRepo>());
|
||||||
.As<IThumbnailsManager>()
|
services.AddScoped<Lazy<IRepository<T>>>(x => new(() => x.GetRequiredService<TRepo>()));
|
||||||
.InstancePerLifetimeScope();
|
|
||||||
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
|
|
||||||
|
|
||||||
builder.RegisterRepository<LibraryItemRepository>();
|
|
||||||
builder.RegisterRepository<CollectionRepository>();
|
|
||||||
builder.RegisterRepository<MovieRepository>();
|
|
||||||
builder.RegisterRepository<ShowRepository>();
|
|
||||||
builder.RegisterRepository<SeasonRepository>();
|
|
||||||
builder.RegisterRepository<EpisodeRepository>();
|
|
||||||
builder.RegisterRepository<StudioRepository>();
|
|
||||||
builder.RegisterRepository<UserRepository>().As<IUserRepository>();
|
|
||||||
builder.RegisterRepository<NewsRepository>();
|
|
||||||
builder
|
|
||||||
.RegisterType<WatchStatusRepository>()
|
|
||||||
.As<IWatchStatusRepository>()
|
|
||||||
.AsSelf()
|
|
||||||
.InstancePerLifetimeScope();
|
|
||||||
builder
|
|
||||||
.RegisterType<IssueRepository>()
|
|
||||||
.As<IIssueRepository>()
|
|
||||||
.AsSelf()
|
|
||||||
.InstancePerLifetimeScope();
|
|
||||||
builder.RegisterType<SqlVariableContext>().InstancePerLifetimeScope();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
public static void ConfigureKyoo(this WebApplicationBuilder builder)
|
||||||
public void Configure(IServiceCollection services)
|
|
||||||
{
|
{
|
||||||
services.AddHttpContextAccessor();
|
builder.Services.AddScoped<IThumbnailsManager, ThumbnailsManager>();
|
||||||
|
builder.Services.AddScoped<ILibraryManager, LibraryManager>();
|
||||||
|
|
||||||
services
|
builder.Services.AddRepository<ILibraryItem, LibraryItemRepository>();
|
||||||
.AddMvcCore(options =>
|
builder.Services.AddRepository<Collection, CollectionRepository>();
|
||||||
{
|
builder.Services.AddRepository<Movie, MovieRepository>();
|
||||||
options.Filters.Add<ExceptionFilter>();
|
builder.Services.AddRepository<Show, ShowRepository>();
|
||||||
options.ModelBinderProviders.Insert(0, new SortBinder.Provider());
|
builder.Services.AddRepository<Season, SeasonRepository>();
|
||||||
options.ModelBinderProviders.Insert(0, new IncludeBinder.Provider());
|
builder.Services.AddRepository<Episode, EpisodeRepository>();
|
||||||
options.ModelBinderProviders.Insert(0, new FilterBinder.Provider());
|
builder.Services.AddRepository<Studio, StudioRepository>();
|
||||||
})
|
builder.Services.AddRepository<INews, NewsRepository>();
|
||||||
.AddJsonOptions(x =>
|
builder.Services.AddRepository<User, UserRepository>();
|
||||||
{
|
builder.Services.AddScoped<IUserRepository>(x => x.GetRequiredService<UserRepository>());
|
||||||
x.JsonSerializerOptions.TypeInfoResolver = new JsonKindResolver()
|
builder.Services.AddScoped<IWatchStatusRepository, WatchStatusRepository>();
|
||||||
{
|
builder.Services.AddScoped<IIssueRepository, IssueRepository>();
|
||||||
Modifiers = { IncludeBinder.HandleLoadableFields }
|
builder.Services.AddScoped<SqlVariableContext>();
|
||||||
};
|
|
||||||
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<RouteOptions>(x =>
|
|
||||||
{
|
|
||||||
x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint));
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddResponseCompression(x =>
|
|
||||||
{
|
|
||||||
x.EnableForHttps = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddProxies();
|
|
||||||
services.AddHttpClient();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<IStartupAction> ConfigureSteps =>
|
|
||||||
new IStartupAction[]
|
|
||||||
{
|
|
||||||
SA.New<IApplicationBuilder>(app => app.UseHsts(), SA.Before),
|
|
||||||
SA.New<IApplicationBuilder>(app => app.UseResponseCompression(), SA.Routing + 1),
|
|
||||||
SA.New<IApplicationBuilder>(app => app.UseRouting(), SA.Routing),
|
|
||||||
SA.New<IApplicationBuilder>(
|
|
||||||
app => app.UseEndpoints(x => x.MapControllers()),
|
|
||||||
SA.Endpoint
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
88
back/src/Kyoo.Core/Extensions/ServiceExtensions.cs
Normal file
88
back/src/Kyoo.Core/Extensions/ServiceExtensions.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
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<ExceptionFilter>();
|
||||||
|
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<RouteOptions>(x =>
|
||||||
|
{
|
||||||
|
x.ConstraintMap.Add("id", typeof(IdentifierRouteConstraint));
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddResponseCompression(x =>
|
||||||
|
{
|
||||||
|
x.EnableForHttps = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddProxies();
|
||||||
|
services.AddHttpClient();
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,11 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Kyoo.Core</AssemblyName>
|
<AssemblyName>Kyoo.Core</AssemblyName>
|
||||||
<RootNamespace>Kyoo.Core</RootNamespace>
|
<RootNamespace>Kyoo.Core</RootNamespace>
|
||||||
<Nullable>enable</Nullable>
|
<OutputType>Exe</OutputType>
|
||||||
|
<AssemblyName>kyoo</AssemblyName>
|
||||||
|
<!-- Limit the number of threads, the default is to not limit so scanning the library
|
||||||
|
create way too many of them and slows the whole server. -->
|
||||||
|
<ThreadPoolMaxThreads>50</ThreadPoolMaxThreads>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -12,13 +16,25 @@
|
|||||||
<PackageReference Include="InterpolatedSql.Dapper" Version="2.3.0" />
|
<PackageReference Include="InterpolatedSql.Dapper" Version="2.3.0" />
|
||||||
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="8.0.0" />
|
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
||||||
|
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.1" />
|
||||||
<PackageReference Include="SkiaSharp" Version="2.88.7" />
|
<PackageReference Include="SkiaSharp" Version="2.88.7" />
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
||||||
<ProjectReference Include="../Kyoo.Postgresql/Kyoo.Postgresql.csproj" />
|
<ProjectReference Include="../Kyoo.Postgresql/Kyoo.Postgresql.csproj" />
|
||||||
|
<ProjectReference Include="../Kyoo.Meilisearch/Kyoo.Meilisearch.csproj" />
|
||||||
|
<ProjectReference Include="../Kyoo.RabbitMq/Kyoo.RabbitMq.csproj" />
|
||||||
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj" />
|
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj" />
|
||||||
|
<ProjectReference Include="../Kyoo.Swagger/Kyoo.Swagger.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
113
back/src/Kyoo.Core/Program.cs
Normal file
113
back/src/Kyoo.Core/Program.cs
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// 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 <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
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 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();
|
||||||
|
|
||||||
|
builder
|
||||||
|
.Services.AddMvcCore()
|
||||||
|
.AddApplicationPart(typeof(CoreModule).Assembly)
|
||||||
|
.AddApplicationPart(typeof(AuthenticationModule).Assembly);
|
||||||
|
|
||||||
|
builder.Services.ConfigureMvc();
|
||||||
|
builder.Services.ConfigureOpenApi();
|
||||||
|
builder.ConfigureKyoo();
|
||||||
|
builder.ConfigureAuthentication();
|
||||||
|
builder.ConfigurePostgres();
|
||||||
|
builder.ConfigureMeilisearch();
|
||||||
|
builder.ConfigureRabbitMq();
|
||||||
|
|
||||||
|
WebApplication app = builder.Build();
|
||||||
|
CoreModule.Services = app.Services;
|
||||||
|
|
||||||
|
app.UseHsts();
|
||||||
|
app.UseKyooOpenApi();
|
||||||
|
app.UseResponseCompression();
|
||||||
|
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<MeiliSync>();
|
||||||
|
app.Services.GetRequiredService<RabbitProducer>();
|
||||||
|
|
||||||
|
await using (AsyncServiceScope scope = app.Services.CreateAsyncScope())
|
||||||
|
{
|
||||||
|
await MeilisearchModule.Initialize(scope.ServiceProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Run(Environment.GetEnvironmentVariable("KYOO_BIND_URL") ?? "http://*:5000");
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hosts of kyoo (main functions) generally only create a new <see cref="Application"/>
|
|
||||||
/// and return <see cref="Start(string[])"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class Application
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The environment in witch Kyoo will run (ether "Production" or "Development").
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _environment;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The logger used for startup and error messages.
|
|
||||||
/// </summary>
|
|
||||||
private ILogger _logger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="Application"/> that will use the specified environment.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="environment">The environment to run in.</param>
|
|
||||||
public Application(string environment)
|
|
||||||
{
|
|
||||||
_environment = environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start the application with the given console args.
|
|
||||||
/// This is generally called from the Main entrypoint of Kyoo.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The console arguments to use for kyoo.</param>
|
|
||||||
/// <returns>A task representing the whole process</returns>
|
|
||||||
public Task Start(string[] args)
|
|
||||||
{
|
|
||||||
return Start(args, _ => { });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start the application with the given console args.
|
|
||||||
/// This is generally called from the Main entrypoint of Kyoo.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">The console arguments to use for kyoo.</param>
|
|
||||||
/// <param name="configure">A custom action to configure the container before the start</param>
|
|
||||||
/// <returns>A task representing the whole process</returns>
|
|
||||||
public async Task Start(string[] args, Action<ContainerBuilder> 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<Application>();
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Start the given host and log failing exceptions.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="host">The host to start.</param>
|
|
||||||
/// <param name="cancellationToken">A token to allow one to stop the host.</param>
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a a web host
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
|
||||||
/// <returns>A new web host instance</returns>
|
|
||||||
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())
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Register settings.json, environment variables and command lines arguments as configuration.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The configuration builder to use</param>
|
|
||||||
/// <param name="args">The command line arguments</param>
|
|
||||||
/// <returns>The modified configuration builder</returns>
|
|
||||||
private IConfigurationBuilder _SetupConfig(IConfigurationBuilder builder, string[] args)
|
|
||||||
{
|
|
||||||
return builder
|
|
||||||
.AddEnvironmentVariables()
|
|
||||||
.AddEnvironmentVariables("KYOO_")
|
|
||||||
.AddCommandLine(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the logging.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The logger builder to configure.</param>
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An implementation of <see cref="IPluginManager"/>.
|
|
||||||
/// This is used to load plugins and retrieve information from them.
|
|
||||||
/// </summary>
|
|
||||||
public class PluginManager : IPluginManager
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The service provider. It allow plugin's activation.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IServiceProvider _provider;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The logger used by this class.
|
|
||||||
/// </summary>
|
|
||||||
private readonly ILogger<PluginManager> _logger;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The list of plugins that are currently loaded.
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<IPlugin> _plugins = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="PluginManager"/> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="provider">A service container to allow initialization of plugins</param>
|
|
||||||
/// <param name="logger">The logger used by this class.</param>
|
|
||||||
public PluginManager(IServiceProvider provider, ILogger<PluginManager> logger)
|
|
||||||
{
|
|
||||||
_provider = provider;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public T GetPlugin<T>(string name)
|
|
||||||
{
|
|
||||||
return (T)_plugins?.FirstOrDefault(x => x.Name == name && x is T);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ICollection<T> GetPlugins<T>()
|
|
||||||
{
|
|
||||||
return _plugins?.OfType<T>().ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public ICollection<IPlugin> GetAllPlugins()
|
|
||||||
{
|
|
||||||
return _plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void LoadPlugins(ICollection<IPlugin> plugins)
|
|
||||||
{
|
|
||||||
_plugins.AddRange(plugins);
|
|
||||||
_logger.LogInformation("Modules enabled: {Plugins}", _plugins.Select(x => x.Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void LoadPlugins(params Type[] plugins)
|
|
||||||
{
|
|
||||||
LoadPlugins(
|
|
||||||
plugins.Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)).ToArray()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Autofac;
|
|
||||||
using Autofac.Extras.AttributeMetadata;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Kyoo.Host;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A module that registers host controllers and other needed things.
|
|
||||||
/// </summary>
|
|
||||||
public class HostModule : IPlugin
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public string Name => "Host";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The plugin manager that loaded all plugins.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IPluginManager _plugins;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="HostModule"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugins">The plugin manager that loaded all plugins.</param>
|
|
||||||
public HostModule(IPluginManager plugins)
|
|
||||||
{
|
|
||||||
_plugins = plugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(ContainerBuilder builder)
|
|
||||||
{
|
|
||||||
builder.RegisterModule<AttributedMetadataModule>();
|
|
||||||
builder.RegisterInstance(_plugins).As<IPluginManager>().ExternallyOwned();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public IEnumerable<IStartupAction> ConfigureSteps =>
|
|
||||||
new[] { SA.New<IApplicationBuilder>(app => app.UseSerilogRequestLogging(), SA.Before) };
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<AssemblyName>Kyoo.Host</AssemblyName>
|
|
||||||
<RootNamespace>Kyoo.Host</RootNamespace>
|
|
||||||
<StartupObject>Kyoo.Host.Program</StartupObject>
|
|
||||||
<!-- Limit the number of threads, the default is to not limit so scanning the library
|
|
||||||
create way too many of them and slows the whole server. -->
|
|
||||||
<ThreadPoolMaxThreads>50</ThreadPoolMaxThreads>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Serilog" Version="3.1.1" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
|
||||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />
|
|
||||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
|
|
||||||
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.1" />
|
|
||||||
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Autofac" Version="8.0.0" />
|
|
||||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
|
|
||||||
<PackageReference Include="Autofac.Extras.AttributeMetadata" Version="6.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.Core/Kyoo.Core.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.Postgresql/Kyoo.Postgresql.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.Meilisearch/Kyoo.Meilisearch.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.RabbitMq/Kyoo.RabbitMq.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.Authentication/Kyoo.Authentication.csproj" />
|
|
||||||
<ProjectReference Include="../Kyoo.Swagger/Kyoo.Swagger.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The Startup class is used to configure the AspNet's webhost.
|
|
||||||
/// </summary>
|
|
||||||
public class PluginsStartup
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A plugin manager used to load plugins and allow them to configure services / asp net.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IPluginManager _plugins;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The plugin that adds controllers and tasks specific to this host.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IPlugin _hostModule;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Created from the DI container, those services are needed to load information and instantiate plugins.s
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugins">The plugin manager to use to load new plugins and configure the host.</param>
|
|
||||||
public PluginsStartup(IPluginManager plugins)
|
|
||||||
{
|
|
||||||
_plugins = plugins;
|
|
||||||
_hostModule = new HostModule(_plugins);
|
|
||||||
_plugins.LoadPlugins(
|
|
||||||
typeof(CoreModule),
|
|
||||||
typeof(AuthenticationModule),
|
|
||||||
typeof(PostgresModule),
|
|
||||||
typeof(MeilisearchModule),
|
|
||||||
typeof(RabbitMqModule),
|
|
||||||
typeof(SwaggerModule)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new <see cref="PluginsStartup"/> from a webhost.
|
|
||||||
/// This is meant to be used from <see cref="WebHostBuilderExtensions.UseStartup"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="host">The context of the web host.</param>
|
|
||||||
/// <param name="logger">
|
|
||||||
/// The logger factory used to log while the application is setting itself up.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A new <see cref="PluginsStartup"/>.</returns>
|
|
||||||
public static PluginsStartup FromWebHost(WebHostBuilderContext host, ILoggerFactory logger)
|
|
||||||
{
|
|
||||||
HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger);
|
|
||||||
PluginManager plugins = new(hostProvider, logger.CreateLogger<PluginManager>());
|
|
||||||
return new PluginsStartup(plugins);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the services context via the <see cref="PluginManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="services">The service collection to fill.</param>
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the autofac container via the <see cref="PluginManager"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">The builder to configure.</param>
|
|
||||||
public void ConfigureContainer(ContainerBuilder builder)
|
|
||||||
{
|
|
||||||
_hostModule.Configure(builder);
|
|
||||||
foreach (IPlugin plugin in _plugins.GetAllPlugins())
|
|
||||||
plugin.Configure(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Configure the asp net host.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="app">The asp net host to configure</param>
|
|
||||||
/// <param name="container">An autofac container used to create a new scope to configure asp-net.</param>
|
|
||||||
public void Configure(IApplicationBuilder app, ILifetimeScope container)
|
|
||||||
{
|
|
||||||
IEnumerable<IStartupAction> 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<IServiceProvider>();
|
|
||||||
foreach (IStartupAction step in steps)
|
|
||||||
step.Run(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A simple host service provider used to activate plugins instance.
|
|
||||||
/// The same services as a generic host are available and an <see cref="ILoggerFactory"/> has been added.
|
|
||||||
/// </summary>
|
|
||||||
private class HostServiceProvider(
|
|
||||||
IWebHostEnvironment hostEnvironment,
|
|
||||||
IConfiguration configuration,
|
|
||||||
ILoggerFactory loggerFactory
|
|
||||||
) : IServiceProvider
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
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<object>(
|
|
||||||
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<>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
|
||||||
|
|
||||||
namespace Kyoo.Host;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Program entrypoint.
|
|
||||||
/// </summary>
|
|
||||||
public static class Program
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The string representation of the environment used in <see cref="IWebHostEnvironment"/>.
|
|
||||||
/// </summary>
|
|
||||||
#if DEBUG
|
|
||||||
private const string Environment = "Development";
|
|
||||||
#else
|
|
||||||
private const string Environment = "Production";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Main function of the program
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="args">Command line arguments</param>
|
|
||||||
/// <returns>A <see cref="Task"/> representing the lifetime of the program.</returns>
|
|
||||||
public static Task Main(string[] args)
|
|
||||||
{
|
|
||||||
Application application = new(Environment);
|
|
||||||
return application.Start(args);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<RootNamespace>Kyoo.Meilisearch</RootNamespace>
|
<RootNamespace>Kyoo.Meilisearch</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -16,21 +16,21 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Autofac;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
using Meilisearch;
|
using Meilisearch;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using static System.Text.Json.JsonNamingPolicy;
|
using static System.Text.Json.JsonNamingPolicy;
|
||||||
|
|
||||||
namespace Kyoo.Meiliseach;
|
namespace Kyoo.Meiliseach;
|
||||||
|
|
||||||
public class MeilisearchModule(IConfiguration configuration) : IPlugin
|
public static class MeilisearchModule
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
|
||||||
public string Name => "Meilisearch";
|
|
||||||
|
|
||||||
public static Dictionary<string, Settings> IndexSettings =>
|
public static Dictionary<string, Settings> IndexSettings =>
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -145,17 +145,15 @@ public class MeilisearchModule(IConfiguration configuration) : IPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Configure(ContainerBuilder builder)
|
public static void ConfigureMeilisearch(this WebApplicationBuilder builder)
|
||||||
{
|
{
|
||||||
builder
|
builder.Services.AddSingleton(
|
||||||
.RegisterInstance(
|
new MeilisearchClient(
|
||||||
new MeilisearchClient(
|
builder.Configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"),
|
||||||
configuration.GetValue("MEILI_HOST", "http://meilisearch:7700"),
|
builder.Configuration.GetValue<string?>("MEILI_MASTER_KEY")
|
||||||
configuration.GetValue<string?>("MEILI_MASTER_KEY")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.SingleInstance();
|
);
|
||||||
builder.RegisterType<MeiliSync>().AsSelf().SingleInstance().AutoActivate();
|
builder.Services.AddScoped<ISearchManager, SearchManager>();
|
||||||
builder.RegisterType<SearchManager>().As<ISearchManager>().InstancePerLifetimeScope();
|
builder.Services.AddSingleton<MeiliSync>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Kyoo.Postgresql</AssemblyName>
|
<AssemblyName>Kyoo.Postgresql</AssemblyName>
|
||||||
<RootNamespace>Kyoo.Postgresql</RootNamespace>
|
<RootNamespace>Kyoo.Postgresql</RootNamespace>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -3,179 +3,175 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
namespace Kyoo.Postgresql.Migrations
|
namespace Kyoo.Postgresql.Migrations;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class UseDateOnly : Migration
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public partial class UseDateOnly : Migration
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
migrationBuilder
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
.AlterDatabase()
|
||||||
{
|
.Annotation(
|
||||||
migrationBuilder
|
"Npgsql:Enum:genre",
|
||||||
.AlterDatabase()
|
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
||||||
.Annotation(
|
)
|
||||||
"Npgsql:Enum:genre",
|
.Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned")
|
||||||
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
.Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted")
|
||||||
)
|
.OldAnnotation(
|
||||||
.Annotation("Npgsql:Enum:status", "unknown,finished,airing,planned")
|
"Npgsql:Enum:genre",
|
||||||
.Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted")
|
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
||||||
.OldAnnotation(
|
)
|
||||||
"Npgsql:Enum:genre",
|
.OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned")
|
||||||
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
.OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned");
|
||||||
)
|
|
||||||
.OldAnnotation("Npgsql:Enum:status", "unknown,finished,airing,planned")
|
|
||||||
.OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned");
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "start_air",
|
name: "start_air",
|
||||||
table: "shows",
|
table: "shows",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "end_air",
|
name: "end_air",
|
||||||
table: "shows",
|
table: "shows",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "start_date",
|
name: "start_date",
|
||||||
table: "seasons",
|
table: "seasons",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "end_date",
|
name: "end_date",
|
||||||
table: "seasons",
|
table: "seasons",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "air_date",
|
name: "air_date",
|
||||||
table: "movies",
|
table: "movies",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateOnly>(
|
migrationBuilder.AlterColumn<DateOnly>(
|
||||||
name: "release_date",
|
name: "release_date",
|
||||||
table: "episodes",
|
table: "episodes",
|
||||||
type: "date",
|
type: "date",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateTime),
|
oldClrType: typeof(DateTime),
|
||||||
oldType: "timestamp with time zone",
|
oldType: "timestamp with time zone",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
migrationBuilder.CreateIndex(
|
||||||
name: "ix_users_username",
|
name: "ix_users_username",
|
||||||
table: "users",
|
table: "users",
|
||||||
column: "username",
|
column: "username",
|
||||||
unique: true
|
unique: true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
{
|
{
|
||||||
migrationBuilder.DropIndex(name: "ix_users_username", table: "users");
|
migrationBuilder.DropIndex(name: "ix_users_username", table: "users");
|
||||||
|
|
||||||
migrationBuilder
|
migrationBuilder
|
||||||
.AlterDatabase()
|
.AlterDatabase()
|
||||||
.Annotation(
|
.Annotation(
|
||||||
"Npgsql:Enum:genre",
|
"Npgsql:Enum:genre",
|
||||||
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
"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:status", "unknown,finished,airing,planned")
|
||||||
.Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned")
|
.Annotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned")
|
||||||
.OldAnnotation(
|
.OldAnnotation(
|
||||||
"Npgsql:Enum:genre",
|
"Npgsql:Enum:genre",
|
||||||
"action,adventure,animation,comedy,crime,documentary,drama,family,fantasy,history,horror,music,mystery,romance,science_fiction,thriller,war,western"
|
"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:status", "unknown,finished,airing,planned")
|
||||||
.OldAnnotation(
|
.OldAnnotation("Npgsql:Enum:watch_status", "completed,watching,droped,planned,deleted");
|
||||||
"Npgsql:Enum:watch_status",
|
|
||||||
"completed,watching,droped,planned,deleted"
|
|
||||||
);
|
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "start_air",
|
name: "start_air",
|
||||||
table: "shows",
|
table: "shows",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "end_air",
|
name: "end_air",
|
||||||
table: "shows",
|
table: "shows",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "start_date",
|
name: "start_date",
|
||||||
table: "seasons",
|
table: "seasons",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "end_date",
|
name: "end_date",
|
||||||
table: "seasons",
|
table: "seasons",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "air_date",
|
name: "air_date",
|
||||||
table: "movies",
|
table: "movies",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
|
|
||||||
migrationBuilder.AlterColumn<DateTime>(
|
migrationBuilder.AlterColumn<DateTime>(
|
||||||
name: "release_date",
|
name: "release_date",
|
||||||
table: "episodes",
|
table: "episodes",
|
||||||
type: "timestamp with time zone",
|
type: "timestamp with time zone",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
oldClrType: typeof(DateOnly),
|
oldClrType: typeof(DateOnly),
|
||||||
oldType: "date",
|
oldType: "date",
|
||||||
oldNullable: true
|
oldNullable: true
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1380
back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs
generated
Normal file
1380
back/src/Kyoo.Postgresql/Migrations/20240401213942_AddGenres.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,47 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Kyoo.Postgresql.Migrations;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddGenres : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ namespace Kyoo.Postgresql.Migrations
|
|||||||
.HasAnnotation("ProductVersion", "8.0.3")
|
.HasAnnotation("ProductVersion", "8.0.3")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.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, "status", new[] { "unknown", "finished", "airing", "planned" });
|
||||||
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "watch_status", new[] { "completed", "watching", "droped", "planned", "deleted" });
|
NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "watch_status", new[] { "completed", "watching", "droped", "planned", "deleted" });
|
||||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||||
@ -252,7 +252,7 @@ namespace Kyoo.Postgresql.Migrations
|
|||||||
.HasColumnType("json")
|
.HasColumnType("json")
|
||||||
.HasColumnName("external_id");
|
.HasColumnName("external_id");
|
||||||
|
|
||||||
b.Property<Genre[]>("Genres")
|
b.Property<List<Genre>>("Genres")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasColumnType("genre[]")
|
.HasColumnType("genre[]")
|
||||||
.HasColumnName("genres");
|
.HasColumnName("genres");
|
||||||
|
@ -28,65 +28,22 @@ using Kyoo.Postgresql.Utils;
|
|||||||
using Kyoo.Utils;
|
using Kyoo.Utils;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
|
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Npgsql;
|
using Npgsql;
|
||||||
|
|
||||||
namespace Kyoo.Postgresql;
|
namespace Kyoo.Postgresql;
|
||||||
|
|
||||||
/// <summary>
|
public class PostgresContext(DbContextOptions options, IHttpContextAccessor accessor)
|
||||||
/// A postgresql implementation of <see cref="DatabaseContext"/>.
|
: DatabaseContext(options, accessor)
|
||||||
/// </summary>
|
|
||||||
public class PostgresContext : DatabaseContext
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Is this instance in debug mode?
|
|
||||||
/// </summary>
|
|
||||||
private readonly bool _debugMode;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Should the configure step be skipped? This is used when the database is created via DbContextOptions.
|
|
||||||
/// </summary>
|
|
||||||
private readonly bool _skipConfigure;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Design time constructor (dotnet ef migrations add). Do not use
|
|
||||||
/// </summary>
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set connection information for this database context
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="optionsBuilder">An option builder to fill.</param>
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
if (!_skipConfigure)
|
|
||||||
{
|
|
||||||
optionsBuilder.UseNpgsql();
|
|
||||||
if (_debugMode)
|
|
||||||
optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging();
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsBuilder.UseSnakeCaseNamingConvention();
|
optionsBuilder.UseSnakeCaseNamingConvention();
|
||||||
base.OnConfiguring(optionsBuilder);
|
base.OnConfiguring(optionsBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set database parameters to support every types of Kyoo.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="modelBuilder">The database's model builder.</param>
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.HasPostgresEnum<Status>();
|
modelBuilder.HasPostgresEnum<Status>();
|
||||||
@ -166,3 +123,15 @@ public class PostgresContext : DatabaseContext
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PostgresContextBuilder : IDesignTimeDbContextFactory<PostgresContext>
|
||||||
|
{
|
||||||
|
public PostgresContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
NpgsqlDataSource dataSource = PostgresModule.CreateDataSource(new ConfigurationManager());
|
||||||
|
DbContextOptionsBuilder builder = new();
|
||||||
|
builder.UseNpgsql(dataSource);
|
||||||
|
|
||||||
|
return new PostgresContext(builder.Options, null!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -28,18 +28,11 @@ using Npgsql;
|
|||||||
|
|
||||||
namespace Kyoo.Postgresql;
|
namespace Kyoo.Postgresql;
|
||||||
|
|
||||||
/// <summary>
|
public static class PostgresModule
|
||||||
/// A module to add postgresql capacity to the app.
|
|
||||||
/// </summary>
|
|
||||||
public class PostgresModule(IConfiguration configuration, IWebHostEnvironment environment) : IPlugin
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
public static NpgsqlDataSource CreateDataSource(IConfiguration configuration)
|
||||||
public string Name => "Postgresql";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(IServiceCollection services)
|
|
||||||
{
|
{
|
||||||
DbConnectionStringBuilder builder =
|
DbConnectionStringBuilder conBuilder =
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
["USER ID"] = configuration.GetValue("POSTGRES_USER", "KyooUser"),
|
["USER ID"] = configuration.GetValue("POSTGRES_USER", "KyooUser"),
|
||||||
@ -52,25 +45,30 @@ public class PostgresModule(IConfiguration configuration, IWebHostEnvironment en
|
|||||||
["TIMEOUT"] = "30"
|
["TIMEOUT"] = "30"
|
||||||
};
|
};
|
||||||
|
|
||||||
NpgsqlDataSourceBuilder dsBuilder = new(builder.ConnectionString);
|
NpgsqlDataSourceBuilder dsBuilder = new(conBuilder.ConnectionString);
|
||||||
dsBuilder.MapEnum<Status>();
|
dsBuilder.MapEnum<Status>();
|
||||||
dsBuilder.MapEnum<Genre>();
|
dsBuilder.MapEnum<Genre>();
|
||||||
dsBuilder.MapEnum<WatchStatus>();
|
dsBuilder.MapEnum<WatchStatus>();
|
||||||
NpgsqlDataSource dataSource = dsBuilder.Build();
|
return dsBuilder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
services.AddDbContext<DatabaseContext, PostgresContext>(
|
public static void ConfigurePostgres(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
NpgsqlDataSource dataSource = CreateDataSource(builder.Configuration);
|
||||||
|
|
||||||
|
builder.Services.AddDbContext<DatabaseContext, PostgresContext>(
|
||||||
x =>
|
x =>
|
||||||
{
|
{
|
||||||
x.UseNpgsql(dataSource).UseProjectables();
|
x.UseNpgsql(dataSource).UseProjectables();
|
||||||
if (environment.IsDevelopment())
|
if (builder.Environment.IsDevelopment())
|
||||||
x.EnableDetailedErrors().EnableSensitiveDataLogging();
|
x.EnableDetailedErrors().EnableSensitiveDataLogging();
|
||||||
},
|
},
|
||||||
ServiceLifetime.Transient
|
ServiceLifetime.Transient
|
||||||
);
|
);
|
||||||
services.AddTransient(
|
builder.Services.AddTransient(
|
||||||
(services) => services.GetRequiredService<DatabaseContext>().Database.GetDbConnection()
|
(services) => services.GetRequiredService<DatabaseContext>().Database.GetDbConnection()
|
||||||
);
|
);
|
||||||
|
|
||||||
services.AddHealthChecks().AddDbContextCheck<DatabaseContext>();
|
builder.Services.AddHealthChecks().AddDbContextCheck<DatabaseContext>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<RootNamespace>Kyoo.RabbitMq</RootNamespace>
|
<RootNamespace>Kyoo.RabbitMq</RootNamespace>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -16,39 +16,30 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Autofac;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
|
|
||||||
namespace Kyoo.RabbitMq;
|
namespace Kyoo.RabbitMq;
|
||||||
|
|
||||||
public class RabbitMqModule(IConfiguration configuration) : IPlugin
|
public static class RabbitMqModule
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
public static void ConfigureRabbitMq(this WebApplicationBuilder builder)
|
||||||
public string Name => "RabbitMq";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(ContainerBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder
|
builder.Services.AddSingleton(_ =>
|
||||||
.Register(
|
{
|
||||||
(_) =>
|
ConnectionFactory factory =
|
||||||
|
new()
|
||||||
{
|
{
|
||||||
ConnectionFactory factory =
|
UserName = builder.Configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"),
|
||||||
new()
|
Password = builder.Configuration.GetValue("RABBITMQ_DEFAULT_PASS", "guest"),
|
||||||
{
|
HostName = builder.Configuration.GetValue("RABBITMQ_HOST", "rabbitmq"),
|
||||||
UserName = configuration.GetValue("RABBITMQ_DEFAULT_USER", "guest"),
|
Port = 5672,
|
||||||
Password = configuration.GetValue("RABBITMQ_DEFAULT_PASS", "guest"),
|
};
|
||||||
HostName = configuration.GetValue("RABBITMQ_HOST", "rabbitmq"),
|
|
||||||
Port = 5672,
|
|
||||||
};
|
|
||||||
|
|
||||||
return factory.CreateConnection();
|
return factory.CreateConnection();
|
||||||
}
|
});
|
||||||
)
|
builder.Services.AddSingleton<RabbitProducer>();
|
||||||
.AsSelf()
|
|
||||||
.SingleInstance();
|
|
||||||
builder.RegisterType<RabbitProducer>().AsSelf().SingleInstance().AutoActivate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>Kyoo.Swagger</AssemblyName>
|
<AssemblyName>Kyoo.Swagger</AssemblyName>
|
||||||
<RootNamespace>Kyoo.Swagger</RootNamespace>
|
<RootNamespace>Kyoo.Swagger</RootNamespace>
|
||||||
|
<Nullable>disable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
@ -31,16 +30,9 @@ using static Kyoo.Abstractions.Models.Utils.Constants;
|
|||||||
|
|
||||||
namespace Kyoo.Swagger;
|
namespace Kyoo.Swagger;
|
||||||
|
|
||||||
/// <summary>
|
public static class SwaggerModule
|
||||||
/// A module to enable a swagger interface and an OpenAPI endpoint to document Kyoo.
|
|
||||||
/// </summary>
|
|
||||||
public class SwaggerModule : IPlugin
|
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
public static void ConfigureOpenApi(this IServiceCollection services)
|
||||||
public string Name => "Swagger";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Configure(IServiceCollection services)
|
|
||||||
{
|
{
|
||||||
services.AddTransient<IApplicationModelProvider, GenericResponseProvider>();
|
services.AddTransient<IApplicationModelProvider, GenericResponseProvider>();
|
||||||
services.AddOpenApiDocument(document =>
|
services.AddOpenApiDocument(document =>
|
||||||
@ -106,24 +98,17 @@ public class SwaggerModule : IPlugin
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
public static void UseKyooOpenApi(this IApplicationBuilder app)
|
||||||
public IEnumerable<IStartupAction> ConfigureSteps =>
|
{
|
||||||
new IStartupAction[]
|
app.UseOpenApi();
|
||||||
|
app.UseReDoc(x =>
|
||||||
{
|
{
|
||||||
SA.New<IApplicationBuilder>(app => app.UseOpenApi(), SA.Before + 1),
|
x.Path = "/doc";
|
||||||
SA.New<IApplicationBuilder>(
|
x.TransformToExternalPath = (internalUiRoute, _) => "/api" + internalUiRoute;
|
||||||
app =>
|
x.AdditionalSettings["theme"] = new
|
||||||
app.UseReDoc(x =>
|
{
|
||||||
{
|
colors = new { primary = new { main = "#e13e13" } }
|
||||||
x.Path = "/doc";
|
};
|
||||||
x.TransformToExternalPath = (internalUiRoute, _) =>
|
});
|
||||||
"/api" + internalUiRoute;
|
}
|
||||||
x.AdditionalSettings["theme"] = new
|
|
||||||
{
|
|
||||||
colors = new { primary = new { main = "#e13e13" } }
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
SA.Before
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -56,12 +56,30 @@ class TheMovieDatabase(Provider):
|
|||||||
53: Genre.THRILLER,
|
53: Genre.THRILLER,
|
||||||
10752: Genre.WAR,
|
10752: Genre.WAR,
|
||||||
37: Genre.WESTERN,
|
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
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
return "themoviedatabase"
|
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):
|
def get_languages(self, *args):
|
||||||
return self._languages + list(args)
|
return self._languages + list(args)
|
||||||
|
|
||||||
@ -154,11 +172,7 @@ class TheMovieDatabase(Provider):
|
|||||||
rating=round(float(movie["vote_average"]) * 10),
|
rating=round(float(movie["vote_average"]) * 10),
|
||||||
runtime=int(movie["runtime"]) if movie["runtime"] is not None else None,
|
runtime=int(movie["runtime"]) if movie["runtime"] is not None else None,
|
||||||
studios=[self.to_studio(x) for x in movie["production_companies"]],
|
studios=[self.to_studio(x) for x in movie["production_companies"]],
|
||||||
genres=[
|
genres=self.process_genres(movie["genres"]),
|
||||||
self.genre_map[x["id"]]
|
|
||||||
for x in movie["genres"]
|
|
||||||
if x["id"] in self.genre_map
|
|
||||||
],
|
|
||||||
external_id=(
|
external_id=(
|
||||||
{
|
{
|
||||||
self.name: MetadataID(
|
self.name: MetadataID(
|
||||||
@ -260,11 +274,7 @@ class TheMovieDatabase(Provider):
|
|||||||
else ShowStatus.FINISHED,
|
else ShowStatus.FINISHED,
|
||||||
rating=round(float(show["vote_average"]) * 10),
|
rating=round(float(show["vote_average"]) * 10),
|
||||||
studios=[self.to_studio(x) for x in show["production_companies"]],
|
studios=[self.to_studio(x) for x in show["production_companies"]],
|
||||||
genres=[
|
genres=self.process_genres(show["genres"]),
|
||||||
self.genre_map[x["id"]]
|
|
||||||
for x in show["genres"]
|
|
||||||
if x["id"] in self.genre_map
|
|
||||||
],
|
|
||||||
external_id={
|
external_id={
|
||||||
self.name: MetadataID(
|
self.name: MetadataID(
|
||||||
show["id"], f"https://www.themoviedb.org/tv/{show['id']}"
|
show["id"], f"https://www.themoviedb.org/tv/{show['id']}"
|
||||||
|
@ -20,6 +20,12 @@ class Genre(str, Enum):
|
|||||||
THRILLER = "Thriller"
|
THRILLER = "Thriller"
|
||||||
WAR = "War"
|
WAR = "War"
|
||||||
WESTERN = "Western"
|
WESTERN = "Western"
|
||||||
|
KIDS = "Kids"
|
||||||
|
NEWS = "News"
|
||||||
|
REALITY = "Reality"
|
||||||
|
SOAP = "Soap"
|
||||||
|
TALK = "Talk"
|
||||||
|
POLITICS = "Politics"
|
||||||
|
|
||||||
def to_kyoo(self):
|
def to_kyoo(self):
|
||||||
return self.value
|
return self.value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user