mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Adding thetvdb, using autofac
This commit is contained in:
parent
8255c2f800
commit
0c4cab48d7
@ -1,21 +1,56 @@
|
|||||||
using Kyoo.Models;
|
using System;
|
||||||
|
using Kyoo.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An interface to automatically retrieve metadata from external providers.
|
||||||
|
/// </summary>
|
||||||
public interface IMetadataProvider
|
public interface IMetadataProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="Provider"/> corresponding to this provider.
|
||||||
|
/// This allow to map metadata to a provider, keep metadata links and
|
||||||
|
/// know witch <see cref="IMetadataProvider"/> is used for a specific <see cref="Library"/>.
|
||||||
|
/// </summary>
|
||||||
Provider Provider { get; }
|
Provider Provider { get; }
|
||||||
|
|
||||||
Task<Collection> GetCollectionFromName(string name);
|
/// <summary>
|
||||||
|
/// Return a new item with metadata from your provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">
|
||||||
|
/// The item to retrieve metadata from. Most of the time, only the name will be available but other
|
||||||
|
/// properties may be filed by other providers before a call to this method. This can allow you to identify
|
||||||
|
/// the collection on your provider.
|
||||||
|
/// </param>
|
||||||
|
/// <remarks>
|
||||||
|
/// You must not use metadata from the given <paramref name="item"/>.
|
||||||
|
/// Merging metadata is the job of Kyoo, a complex <typeparamref name="T"/> is given
|
||||||
|
/// to make a precise search and give you every available properties, not to discard properties.
|
||||||
|
/// </remarks>
|
||||||
|
/// <exception cref="NotSupportedException">
|
||||||
|
/// If this metadata provider does not support <typeparamref name="T"/>.
|
||||||
|
/// </exception>
|
||||||
|
/// <returns>A new <typeparamref name="T"/> containing metadata from your provider</returns>
|
||||||
|
[ItemNotNull]
|
||||||
|
Task<T> Get<T>([NotNull] T item)
|
||||||
|
where T : class, IResource;
|
||||||
|
|
||||||
Task<Show> GetShowByID(Show show);
|
/// <summary>
|
||||||
Task<ICollection<Show>> SearchShows(string showName, bool isMovie);
|
/// Search for a specific type of items with a given query.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="query">The search query to use.</param>
|
||||||
|
/// <exception cref="NotSupportedException">
|
||||||
|
/// If this metadata provider does not support <typeparamref name="T"/>.
|
||||||
|
/// </exception>
|
||||||
|
/// <returns>The list of items that could be found on this specific provider.</returns>
|
||||||
|
[ItemNotNull]
|
||||||
|
Task<ICollection<T>> Search<T>(string query)
|
||||||
|
where T : class, IResource;
|
||||||
|
|
||||||
Task<ICollection<PeopleRole>> GetPeople(Show show);
|
Task<ICollection<PeopleRole>> GetPeople(Show show);
|
||||||
|
|
||||||
Task<Season> GetSeason(Show show, int seasonNumber);
|
|
||||||
|
|
||||||
Task<Episode> GetEpisode(Show show, int? seasonNumber, int? episodeNumber, int? absoluteNumber);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Autofac;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -55,6 +56,15 @@ namespace Kyoo.Controllers
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
ICollection<Type> Requires { get; }
|
ICollection<Type> Requires { get; }
|
||||||
|
|
||||||
|
/// <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>
|
/// <summary>
|
||||||
/// A configure method that will be run on plugin's startup.
|
/// A configure method that will be run on plugin's startup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -64,21 +74,31 @@ namespace Kyoo.Controllers
|
|||||||
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>>
|
/// or <see cref="ProviderCondition.Has(System.Collections.Generic.ICollection{System.Type},System.Collections.Generic.ICollection{System.Type})"/>>
|
||||||
/// You can't simply check on the service collection because some dependencies might be registered after your plugin.
|
/// You can't simply check on the service collection because some dependencies might be registered after your plugin.
|
||||||
/// </param>
|
/// </param>
|
||||||
void Configure(IServiceCollection services, ICollection<Type> availableTypes);
|
void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||||
|
{
|
||||||
|
// Skipped
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An optional configuration step to allow a plugin to change asp net configurations.
|
/// An optional configuration step to allow a plugin to change asp net configurations.
|
||||||
/// WARNING: This is only called on Kyoo's startup so you must restart the app to apply this changes.
|
/// WARNING: This is only called on Kyoo's startup so you must restart the app to apply this changes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="app">The Asp.Net application builder. On most case it is not needed but you can use it to add asp net functionalities.</param>
|
/// <param name="app">The Asp.Net application builder. On most case it is not needed but you can use it to add asp net functionalities.</param>
|
||||||
void ConfigureAspNet(IApplicationBuilder app) {}
|
void ConfigureAspNet(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
// Skipped
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An optional function to execute and initialize your plugin.
|
/// An optional function to execute and initialize your plugin.
|
||||||
/// It can be used to initialize a database connection, fill initial data or anything.
|
/// It can be used to initialize a database connection, fill initial data or anything.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="provider">A service provider to request services</param>
|
/// <param name="provider">A service provider to request services</param>
|
||||||
void Initialize(IServiceProvider provider) {}
|
void Initialize(IServiceProvider provider)
|
||||||
|
{
|
||||||
|
// Skipped
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Autofac;
|
||||||
using Kyoo.Models.Exceptions;
|
using Kyoo.Models.Exceptions;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -42,7 +43,13 @@ namespace Kyoo.Controllers
|
|||||||
public void LoadPlugins(ICollection<IPlugin> plugins);
|
public void LoadPlugins(ICollection<IPlugin> plugins);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure services adding or removing services as the plugins wants.
|
/// Configure container adding or removing services as the plugins wants.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The container to populate</param>
|
||||||
|
void ConfigureContainer(ContainerBuilder builder);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure services via the microsoft way. This allow libraries to add their services.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services">The service collection to populate</param>
|
/// <param name="services">The service collection to populate</param>
|
||||||
public void ConfigureServices(IServiceCollection services);
|
public void ConfigureServices(IServiceCollection services);
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Models;
|
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
|
||||||
{
|
|
||||||
public interface IProviderManager
|
|
||||||
{
|
|
||||||
Task<Collection> GetCollectionFromName(string name, Library library);
|
|
||||||
Task<Show> CompleteShow(Show show, Library library);
|
|
||||||
Task<Show> SearchShow(string showName, bool isMovie, Library library);
|
|
||||||
Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie, Library library);
|
|
||||||
Task<Season> GetSeason(Show show, int seasonNumber, Library library);
|
|
||||||
Task<Episode> GetEpisode(Show show, string episodePath, int? seasonNumber, int? episodeNumber, int? absoluteNumber, Library library);
|
|
||||||
Task<ICollection<PeopleRole>> GetPeople(Show show, Library library);
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Autofac" Version="6.2.0" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2021.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Autofac;
|
||||||
|
using Autofac.Builder;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
@ -15,55 +16,63 @@ namespace Kyoo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a new task to the container.
|
/// Register a new task to the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services">The container</param>
|
/// <param name="builder">The container</param>
|
||||||
/// <typeparam name="T">The type of the task</typeparam>
|
/// <typeparam name="T">The type of the task</typeparam>
|
||||||
/// <returns>The initial container.</returns>
|
/// <returns>The registration builder of this new task. That can be used to edit the registration.</returns>
|
||||||
public static IServiceCollection AddTask<T>(this IServiceCollection services)
|
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||||
|
RegisterTask<T>(this ContainerBuilder builder)
|
||||||
where T : class, ITask
|
where T : class, ITask
|
||||||
{
|
{
|
||||||
services.AddSingleton<ITask, T>();
|
return builder.RegisterType<T>().As<ITask>().SingleInstance();
|
||||||
return services;
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register a new metadata provider to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The container</param>
|
||||||
|
/// <typeparam name="T">The type of the task</typeparam>
|
||||||
|
/// <returns>The registration builder of this new provider. That can be used to edit the registration.</returns>
|
||||||
|
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||||
|
RegisterProvider<T>(this ContainerBuilder builder)
|
||||||
|
where T : class, IMetadataProvider
|
||||||
|
{
|
||||||
|
return builder.RegisterType<T>().As<IMetadataProvider>().InstancePerLifetimeScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a new repository to the container.
|
/// Register a new repository to the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services">The container</param>
|
/// <param name="builder">The container</param>
|
||||||
/// <param name="lifetime">The lifetime of the repository. The default is scoped.</param>
|
|
||||||
/// <typeparam name="T">The type of the repository.</typeparam>
|
/// <typeparam name="T">The type of the repository.</typeparam>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If your repository implements a special interface, please use <see cref="AddRepository{T,T2}"/>
|
/// If your repository implements a special interface, please use <see cref="RegisterRepository{T,T2}"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>The initial container.</returns>
|
/// <returns>The initial container.</returns>
|
||||||
public static IServiceCollection AddRepository<T>(this IServiceCollection services,
|
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||||
ServiceLifetime lifetime = ServiceLifetime.Scoped)
|
RegisterRepository<T>(this ContainerBuilder builder)
|
||||||
where T : IBaseRepository
|
where T : IBaseRepository
|
||||||
{
|
{
|
||||||
Type repository = Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>));
|
return builder.RegisterType<T>()
|
||||||
|
.As<IBaseRepository>()
|
||||||
if (repository != null)
|
.As(Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>)))
|
||||||
services.Add(ServiceDescriptor.Describe(repository, typeof(T), lifetime));
|
.InstancePerLifetimeScope();
|
||||||
services.Add(ServiceDescriptor.Describe(typeof(IBaseRepository), typeof(T), lifetime));
|
|
||||||
return services;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a new repository with a custom mapping to the container.
|
/// Register a new repository with a custom mapping to the container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services"></param>
|
/// <param name="builder">The container</param>
|
||||||
/// <param name="lifetime">The lifetime of the repository. The default is scoped.</param>
|
|
||||||
/// <typeparam name="T">The custom mapping you have for your repository.</typeparam>
|
/// <typeparam name="T">The custom mapping you have for your repository.</typeparam>
|
||||||
/// <typeparam name="T2">The type of the repository.</typeparam>
|
/// <typeparam name="T2">The type of the repository.</typeparam>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If your repository does not implements a special interface, please use <see cref="AddRepository{T}"/>
|
/// If your repository does not implements a special interface, please use <see cref="RegisterRepository{T}"/>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>The initial container.</returns>
|
/// <returns>The initial container.</returns>
|
||||||
public static IServiceCollection AddRepository<T, T2>(this IServiceCollection services,
|
public static IRegistrationBuilder<T2, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||||
ServiceLifetime lifetime = ServiceLifetime.Scoped)
|
RegisterRepository<T, T2>(this ContainerBuilder builder)
|
||||||
where T2 : IBaseRepository, T
|
where T2 : IBaseRepository, T
|
||||||
{
|
{
|
||||||
services.Add(ServiceDescriptor.Describe(typeof(T), typeof(T2), lifetime));
|
return builder.RegisterRepository<T2>().As<T>();
|
||||||
return services.AddRepository<T2>(lifetime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
33
Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
Normal file
33
Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
|
||||||
|
<Company>SDG</Company>
|
||||||
|
<Authors>Zoe Roux</Authors>
|
||||||
|
<RepositoryUrl>https://github.com/AnonymusRaccoon/Kyoo</RepositoryUrl>
|
||||||
|
<LangVersion>default</LangVersion>
|
||||||
|
<RootNamespace>Kyoo.TheTvdb</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputPath>../Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/the-tvdb</OutputPath>
|
||||||
|
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||||
|
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||||
|
<GenerateDependencyFile>false</GenerateDependencyFile>
|
||||||
|
<GenerateRuntimeConfigurationFiles>false</GenerateRuntimeConfigurationFiles>
|
||||||
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||||
|
<PackageReference Include="TvDbSharper" Version="3.2.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<Private>false</Private>
|
||||||
|
<ExcludeAssets>runtime</ExcludeAssets>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
41
Kyoo.TheTvdb/PluginTVDB.cs
Normal file
41
Kyoo.TheTvdb/PluginTVDB.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Kyoo.TheTvdb
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A plugin that add a <see cref="IMetadataProvider"/> for The TVDB.
|
||||||
|
/// </summary>
|
||||||
|
public class PluginTvdb : IPlugin
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Slug => "the-tvdb";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "The TVDB Provider";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "A metadata provider for The TVDB.";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICollection<Type> Provides => new []
|
||||||
|
{
|
||||||
|
typeof(IMetadataProvider)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICollection<ConditionalProvide> ConditionalProvides => ArraySegment<ConditionalProvide>.Empty;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ICollection<Type> Requires => ArraySegment<Type>.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||||
|
{
|
||||||
|
// services.AddProvider<ProviderTvdb>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
203
Kyoo.TheTvdb/ProviderTVDB.cs
Normal file
203
Kyoo.TheTvdb/ProviderTVDB.cs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Controllers;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using TvDbSharper;
|
||||||
|
using TvDbSharper.Dto;
|
||||||
|
|
||||||
|
namespace Kyoo.TheTvdb
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A metadata provider for The TVDB.
|
||||||
|
/// </summary>
|
||||||
|
public class ProviderTvdb : IMetadataProvider
|
||||||
|
{
|
||||||
|
public Provider Provider { get; }
|
||||||
|
public Task<T> Get<T>(T item) where T : class, IResource
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<T>> Search<T>(string query) where T : class, IResource
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<PeopleRole>> GetPeople(Show show)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public class Old
|
||||||
|
// {
|
||||||
|
// private static readonly ProviderID _provider = new()
|
||||||
|
// {
|
||||||
|
// Slug = "the-tvdb",
|
||||||
|
// Name = "TheTVDB",
|
||||||
|
// LogoExtension = "png",
|
||||||
|
// Logo = "https://www.thetvdb.com/images/logo.png"
|
||||||
|
// };
|
||||||
|
// public ProviderID Provider => _provider;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// private readonly TvDbClient _client = new();
|
||||||
|
//
|
||||||
|
// private Task Authentificate()
|
||||||
|
// {
|
||||||
|
// if (_client.Authentication.Token == null)
|
||||||
|
// return _client.Authentication.AuthenticateAsync(APIKey);
|
||||||
|
// return _client.Authentication.RefreshTokenAsync();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Task<Collection> GetCollectionFromName(string name)
|
||||||
|
// {
|
||||||
|
// return Task.FromResult<Collection>(null);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<ICollection<Show>> SearchShows(string showName, bool isMovie)
|
||||||
|
// {
|
||||||
|
// await Authentificate();
|
||||||
|
//
|
||||||
|
// if (isMovie)
|
||||||
|
// return null; //There is no movie search API for now on TheTVDB.
|
||||||
|
// TvDbResponse<SeriesSearchResult[]> shows = await _client.Search.SearchSeriesAsync(showName, SearchParameter.Name);
|
||||||
|
// return shows.Data.Select(x => x.ToShow(Provider)).ToArray();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Show> GetShowByID(Show show)
|
||||||
|
// {
|
||||||
|
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
||||||
|
// return await Task.FromResult<Show>(null);
|
||||||
|
// await Authentificate();
|
||||||
|
// TvDbResponse<Series> serie = await _client.Series.GetAsync(id);
|
||||||
|
// return serie.Data.ToShow(Provider);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<ICollection<PeopleRole>> GetPeople(Show show)
|
||||||
|
// {
|
||||||
|
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
||||||
|
// return null;
|
||||||
|
// await Authentificate();
|
||||||
|
// TvDbResponse<Actor[]> people = await _client.Series.GetActorsAsync(id);
|
||||||
|
// return people.Data.Select(x => x.ToPeopleRole(Provider)).ToArray();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public Task<Season> GetSeason(Show show, int seasonNumber)
|
||||||
|
// {
|
||||||
|
// return Task.FromResult<Season>(null);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Episode> GetEpisode(Show show, int seasonNumber, int episodeNumber, int absoluteNumber)
|
||||||
|
// {
|
||||||
|
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
||||||
|
// return null;
|
||||||
|
// await Authentificate();
|
||||||
|
// TvDbResponse<EpisodeRecord[]> episodes = absoluteNumber != -1
|
||||||
|
// ? await _client.Series.GetEpisodesAsync(id, 0, new EpisodeQuery {AbsoluteNumber = absoluteNumber})
|
||||||
|
// : await _client.Series.GetEpisodesAsync(id, 0, new EpisodeQuery {AiredSeason = seasonNumber, AiredEpisode = episodeNumber});
|
||||||
|
// EpisodeRecord x = episodes.Data[0];
|
||||||
|
//
|
||||||
|
// if (absoluteNumber == -1)
|
||||||
|
// absoluteNumber = x.AbsoluteNumber ?? -1;
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// seasonNumber = x.AiredSeason ?? -1;
|
||||||
|
// episodeNumber = x.AiredEpisodeNumber ?? -1;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return new Episode(seasonNumber,
|
||||||
|
// episodeNumber,
|
||||||
|
// absoluteNumber,
|
||||||
|
// x.EpisodeName,
|
||||||
|
// x.Overview,
|
||||||
|
// DateTime.ParseExact(x.FirstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture),
|
||||||
|
// -1,
|
||||||
|
// x.Filename != null ? "https://www.thetvdb.com/banners/" + x.Filename : null,
|
||||||
|
// new []
|
||||||
|
// {
|
||||||
|
// new MetadataID(Provider, x.Id.ToString(), $"https://www.thetvdb.com/series/{id}/episodes/{x.Id}")
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public static class Convertors
|
||||||
|
// {
|
||||||
|
// private static int? GetYear(string firstAired)
|
||||||
|
// {
|
||||||
|
// if (firstAired?.Length >= 4 && int.TryParse(firstAired.Substring(0, 4), out int year))
|
||||||
|
// return year;
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private static Status? GetStatus(string status)
|
||||||
|
// {
|
||||||
|
// return status switch
|
||||||
|
// {
|
||||||
|
// "Ended" => Status.Finished,
|
||||||
|
// "Continuing" => Status.Airing,
|
||||||
|
// _ => null
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static Show ToShow(this SeriesSearchResult x, ProviderID provider)
|
||||||
|
// {
|
||||||
|
// Show ret = new(x.Slug,
|
||||||
|
// x.SeriesName,
|
||||||
|
// x.Aliases,
|
||||||
|
// null,
|
||||||
|
// x.Overview,
|
||||||
|
// null,
|
||||||
|
// null,
|
||||||
|
// GetStatus(x.Status),
|
||||||
|
// GetYear(x.FirstAired),
|
||||||
|
// null,
|
||||||
|
// new[]
|
||||||
|
// {
|
||||||
|
// new MetadataID(provider, x.Id.ToString(), $"https://www.thetvdb.com/series/{x.Slug}")
|
||||||
|
// });
|
||||||
|
// if (x.Poster != null)
|
||||||
|
// Utility.SetImage(ret, $"https://www.thetvdb.com{x.Poster}", ImageType.Poster);
|
||||||
|
// return ret;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static Show ToShow(this Series x, ProviderID provider)
|
||||||
|
// {
|
||||||
|
// return new(x.Slug,
|
||||||
|
// x.SeriesName,
|
||||||
|
// x.Aliases,
|
||||||
|
// null,
|
||||||
|
// x.Overview,
|
||||||
|
// null,
|
||||||
|
// x.Genre.Select(y => new Genre(Utility.ToSlug(y), y)),
|
||||||
|
// GetStatus(x.Status),
|
||||||
|
// GetYear(x.FirstAired),
|
||||||
|
// null,
|
||||||
|
// new[]
|
||||||
|
// {
|
||||||
|
// new MetadataID(provider, x.Id.ToString(),$"https://www.thetvdb.com/series/{x.Slug}")
|
||||||
|
// })
|
||||||
|
// {
|
||||||
|
// Poster = x.Poster != null ? $"https://www.thetvdb.com/banners/{x.Poster}" : null,
|
||||||
|
// Backdrop = x.FanArt != null ? $"https://www.thetvdb.com/banners/{x.FanArt}" : null
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static PeopleRole ToPeopleRole(this Actor x, ProviderID provider)
|
||||||
|
// {
|
||||||
|
// return new (Utility.ToSlug(x.Name),
|
||||||
|
// x.Name,
|
||||||
|
// x.Role,
|
||||||
|
// null,
|
||||||
|
// x.Image != null ? $"https://www.thetvdb.com/banners/{x.Image}" : null,
|
||||||
|
// new[]
|
||||||
|
// {
|
||||||
|
// new MetadataID(provider, x.Id.ToString(), $"https://www.thetvdb.com/people/{x.Id}")
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
6
Kyoo.sln
6
Kyoo.sln
@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "Kyoo
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -47,5 +49,9 @@ Global
|
|||||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
|
using Autofac;
|
||||||
using Kyoo.Models.Options;
|
using Kyoo.Models.Options;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -126,6 +127,12 @@ namespace Kyoo.Controllers
|
|||||||
else
|
else
|
||||||
_logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name));
|
_logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ConfigureContainer(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
foreach (IPlugin plugin in _plugins)
|
||||||
|
plugin.Configure(builder);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
182
Kyoo/Controllers/ProviderComposite.cs
Normal file
182
Kyoo/Controllers/ProviderComposite.cs
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
using System;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Kyoo.Controllers
|
||||||
|
{
|
||||||
|
public class ProviderComposite : IMetadataProvider
|
||||||
|
{
|
||||||
|
private readonly IEnumerable<IMetadataProvider> _providers;
|
||||||
|
|
||||||
|
|
||||||
|
public ProviderComposite(IEnumerable<IMetadataProvider> providers)
|
||||||
|
{
|
||||||
|
_providers = providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Provider Provider { get; }
|
||||||
|
public Task<T> Get<T>(T item) where T : class, IResource
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<T>> Search<T>(string query) where T : class, IResource
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ICollection<PeopleRole>> GetPeople(Show show)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// private async Task<T> GetMetadata<T>(Func<IMetadataProvider, Task<T>> providerCall, Library library, string what)
|
||||||
|
// where T : new()
|
||||||
|
// {
|
||||||
|
// T ret = new();
|
||||||
|
//
|
||||||
|
// IEnumerable<IMetadataProvider> providers = library?.Providers
|
||||||
|
// .Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
||||||
|
// .Where(x => x != null)
|
||||||
|
// ?? _providers;
|
||||||
|
//
|
||||||
|
// foreach (IMetadataProvider provider in providers)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// ret = Merger.Merge(ret, await providerCall(provider));
|
||||||
|
// } catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// await Console.Error.WriteLineAsync(
|
||||||
|
// $"The provider {provider.Provider.Name} could not work for {what}. Exception: {ex.Message}");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return ret;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private async Task<List<T>> GetMetadata<T>(
|
||||||
|
// Func<IMetadataProvider, Task<ICollection<T>>> providerCall,
|
||||||
|
// Library library,
|
||||||
|
// string what)
|
||||||
|
// {
|
||||||
|
// List<T> ret = new();
|
||||||
|
//
|
||||||
|
// IEnumerable<IMetadataProvider> providers = library?.Providers
|
||||||
|
// .Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
||||||
|
// .Where(x => x != null)
|
||||||
|
// ?? _providers;
|
||||||
|
//
|
||||||
|
// foreach (IMetadataProvider provider in providers)
|
||||||
|
// {
|
||||||
|
// try
|
||||||
|
// {
|
||||||
|
// ret.AddRange(await providerCall(provider) ?? new List<T>());
|
||||||
|
// } catch (Exception ex)
|
||||||
|
// {
|
||||||
|
// await Console.Error.WriteLineAsync(
|
||||||
|
// $"The provider {provider.Provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return ret;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Collection> GetCollectionFromName(string name, Library library)
|
||||||
|
// {
|
||||||
|
// Collection collection = await GetMetadata(
|
||||||
|
// provider => provider.GetCollectionFromName(name),
|
||||||
|
// library,
|
||||||
|
// $"the collection {name}");
|
||||||
|
// collection.Name ??= name;
|
||||||
|
// collection.Slug ??= Utility.ToSlug(name);
|
||||||
|
// return collection;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Show> CompleteShow(Show show, Library library)
|
||||||
|
// {
|
||||||
|
// return await GetMetadata(provider => provider.GetShowByID(show), library, $"the show {show.Title}");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Show> SearchShow(string showName, bool isMovie, Library library)
|
||||||
|
// {
|
||||||
|
// Show show = await GetMetadata(async provider =>
|
||||||
|
// {
|
||||||
|
// Show searchResult = (await provider.SearchShows(showName, isMovie))?.FirstOrDefault();
|
||||||
|
// if (searchResult == null)
|
||||||
|
// return null;
|
||||||
|
// return await provider.GetShowByID(searchResult);
|
||||||
|
// }, library, $"the show {showName}");
|
||||||
|
// show.Slug = Utility.ToSlug(showName);
|
||||||
|
// show.Title ??= showName;
|
||||||
|
// show.IsMovie = isMovie;
|
||||||
|
// show.Genres = show.Genres?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
||||||
|
// show.People = show.People?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
||||||
|
// return show;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie, Library library)
|
||||||
|
// {
|
||||||
|
// IEnumerable<Show> shows = await GetMetadata(
|
||||||
|
// provider => provider.SearchShows(showName, isMovie),
|
||||||
|
// library,
|
||||||
|
// $"the show {showName}");
|
||||||
|
// return shows.Select(show =>
|
||||||
|
// {
|
||||||
|
// show.Slug = Utility.ToSlug(showName);
|
||||||
|
// show.Title ??= showName;
|
||||||
|
// show.IsMovie = isMovie;
|
||||||
|
// return show;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Season> GetSeason(Show show, int seasonNumber, Library library)
|
||||||
|
// {
|
||||||
|
// Season season = await GetMetadata(
|
||||||
|
// provider => provider.GetSeason(show, seasonNumber),
|
||||||
|
// library,
|
||||||
|
// $"the season {seasonNumber} of {show.Title}");
|
||||||
|
// season.Show = show;
|
||||||
|
// season.ShowID = show.ID;
|
||||||
|
// season.ShowSlug = show.Slug;
|
||||||
|
// season.Title ??= $"Season {season.SeasonNumber}";
|
||||||
|
// return season;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<Episode> GetEpisode(Show show,
|
||||||
|
// string episodePath,
|
||||||
|
// int? seasonNumber,
|
||||||
|
// int? episodeNumber,
|
||||||
|
// int? absoluteNumber,
|
||||||
|
// Library library)
|
||||||
|
// {
|
||||||
|
// Episode episode = await GetMetadata(
|
||||||
|
// provider => provider.GetEpisode(show, seasonNumber, episodeNumber, absoluteNumber),
|
||||||
|
// library,
|
||||||
|
// "an episode");
|
||||||
|
// episode.Show = show;
|
||||||
|
// episode.ShowID = show.ID;
|
||||||
|
// episode.ShowSlug = show.Slug;
|
||||||
|
// episode.Path = episodePath;
|
||||||
|
// episode.SeasonNumber ??= seasonNumber;
|
||||||
|
// episode.EpisodeNumber ??= episodeNumber;
|
||||||
|
// episode.AbsoluteNumber ??= absoluteNumber;
|
||||||
|
// return episode;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public async Task<ICollection<PeopleRole>> GetPeople(Show show, Library library)
|
||||||
|
// {
|
||||||
|
// List<PeopleRole> people = await GetMetadata(
|
||||||
|
// provider => provider.GetPeople(show),
|
||||||
|
// library,
|
||||||
|
// $"a cast member of {show.Title}");
|
||||||
|
// return people?.GroupBy(x => x.Slug)
|
||||||
|
// .Select(x => x.First())
|
||||||
|
// .Select(x =>
|
||||||
|
// {
|
||||||
|
// x.Show = show;
|
||||||
|
// x.ShowID = show.ID;
|
||||||
|
// return x;
|
||||||
|
// }).ToList();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
@ -1,166 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Kyoo.Models;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
|
||||||
{
|
|
||||||
public class ProviderManager : IProviderManager
|
|
||||||
{
|
|
||||||
private readonly IEnumerable<IMetadataProvider> _providers;
|
|
||||||
|
|
||||||
public ProviderManager(IPluginManager pluginManager)
|
|
||||||
{
|
|
||||||
_providers = pluginManager.GetPlugins<IMetadataProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<T> GetMetadata<T>(Func<IMetadataProvider, Task<T>> providerCall, Library library, string what)
|
|
||||||
where T : new()
|
|
||||||
{
|
|
||||||
T ret = new();
|
|
||||||
|
|
||||||
IEnumerable<IMetadataProvider> providers = library?.Providers
|
|
||||||
.Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
|
||||||
.Where(x => x != null)
|
|
||||||
?? _providers;
|
|
||||||
|
|
||||||
foreach (IMetadataProvider provider in providers)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ret = Merger.Merge(ret, await providerCall(provider));
|
|
||||||
} catch (Exception ex)
|
|
||||||
{
|
|
||||||
await Console.Error.WriteLineAsync(
|
|
||||||
$"The provider {provider.Provider.Name} could not work for {what}. Exception: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<List<T>> GetMetadata<T>(
|
|
||||||
Func<IMetadataProvider, Task<ICollection<T>>> providerCall,
|
|
||||||
Library library,
|
|
||||||
string what)
|
|
||||||
{
|
|
||||||
List<T> ret = new();
|
|
||||||
|
|
||||||
IEnumerable<IMetadataProvider> providers = library?.Providers
|
|
||||||
.Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
|
|
||||||
.Where(x => x != null)
|
|
||||||
?? _providers;
|
|
||||||
|
|
||||||
foreach (IMetadataProvider provider in providers)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ret.AddRange(await providerCall(provider) ?? new List<T>());
|
|
||||||
} catch (Exception ex)
|
|
||||||
{
|
|
||||||
await Console.Error.WriteLineAsync(
|
|
||||||
$"The provider {provider.Provider.Name} coudln't work for {what}. Exception: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Collection> GetCollectionFromName(string name, Library library)
|
|
||||||
{
|
|
||||||
Collection collection = await GetMetadata(
|
|
||||||
provider => provider.GetCollectionFromName(name),
|
|
||||||
library,
|
|
||||||
$"the collection {name}");
|
|
||||||
collection.Name ??= name;
|
|
||||||
collection.Slug ??= Utility.ToSlug(name);
|
|
||||||
return collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Show> CompleteShow(Show show, Library library)
|
|
||||||
{
|
|
||||||
return await GetMetadata(provider => provider.GetShowByID(show), library, $"the show {show.Title}");
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Show> SearchShow(string showName, bool isMovie, Library library)
|
|
||||||
{
|
|
||||||
Show show = await GetMetadata(async provider =>
|
|
||||||
{
|
|
||||||
Show searchResult = (await provider.SearchShows(showName, isMovie))?.FirstOrDefault();
|
|
||||||
if (searchResult == null)
|
|
||||||
return null;
|
|
||||||
return await provider.GetShowByID(searchResult);
|
|
||||||
}, library, $"the show {showName}");
|
|
||||||
show.Slug = Utility.ToSlug(showName);
|
|
||||||
show.Title ??= showName;
|
|
||||||
show.IsMovie = isMovie;
|
|
||||||
show.Genres = show.Genres?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
|
||||||
show.People = show.People?.GroupBy(x => x.Slug).Select(x => x.First()).ToList();
|
|
||||||
return show;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<Show>> SearchShows(string showName, bool isMovie, Library library)
|
|
||||||
{
|
|
||||||
IEnumerable<Show> shows = await GetMetadata(
|
|
||||||
provider => provider.SearchShows(showName, isMovie),
|
|
||||||
library,
|
|
||||||
$"the show {showName}");
|
|
||||||
return shows.Select(show =>
|
|
||||||
{
|
|
||||||
show.Slug = Utility.ToSlug(showName);
|
|
||||||
show.Title ??= showName;
|
|
||||||
show.IsMovie = isMovie;
|
|
||||||
return show;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Season> GetSeason(Show show, int seasonNumber, Library library)
|
|
||||||
{
|
|
||||||
Season season = await GetMetadata(
|
|
||||||
provider => provider.GetSeason(show, seasonNumber),
|
|
||||||
library,
|
|
||||||
$"the season {seasonNumber} of {show.Title}");
|
|
||||||
season.Show = show;
|
|
||||||
season.ShowID = show.ID;
|
|
||||||
season.ShowSlug = show.Slug;
|
|
||||||
season.Title ??= $"Season {season.SeasonNumber}";
|
|
||||||
return season;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Episode> GetEpisode(Show show,
|
|
||||||
string episodePath,
|
|
||||||
int? seasonNumber,
|
|
||||||
int? episodeNumber,
|
|
||||||
int? absoluteNumber,
|
|
||||||
Library library)
|
|
||||||
{
|
|
||||||
Episode episode = await GetMetadata(
|
|
||||||
provider => provider.GetEpisode(show, seasonNumber, episodeNumber, absoluteNumber),
|
|
||||||
library,
|
|
||||||
"an episode");
|
|
||||||
episode.Show = show;
|
|
||||||
episode.ShowID = show.ID;
|
|
||||||
episode.ShowSlug = show.Slug;
|
|
||||||
episode.Path = episodePath;
|
|
||||||
episode.SeasonNumber ??= seasonNumber;
|
|
||||||
episode.EpisodeNumber ??= episodeNumber;
|
|
||||||
episode.AbsoluteNumber ??= absoluteNumber;
|
|
||||||
return episode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ICollection<PeopleRole>> GetPeople(Show show, Library library)
|
|
||||||
{
|
|
||||||
List<PeopleRole> people = await GetMetadata(
|
|
||||||
provider => provider.GetPeople(show),
|
|
||||||
library,
|
|
||||||
$"a cast member of {show.Title}");
|
|
||||||
return people?.GroupBy(x => x.Slug)
|
|
||||||
.Select(x => x.First())
|
|
||||||
.Select(x =>
|
|
||||||
{
|
|
||||||
x.Show = show;
|
|
||||||
x.ShowID = show.ID;
|
|
||||||
return x;
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using Autofac;
|
||||||
|
using Autofac.Core;
|
||||||
|
using Autofac.Core.Registration;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models.Options;
|
using Kyoo.Models.Options;
|
||||||
using Kyoo.Models.Permissions;
|
using Kyoo.Models.Permissions;
|
||||||
@ -34,7 +36,7 @@ namespace Kyoo
|
|||||||
typeof(IFileManager),
|
typeof(IFileManager),
|
||||||
typeof(ITranscoder),
|
typeof(ITranscoder),
|
||||||
typeof(IThumbnailsManager),
|
typeof(IThumbnailsManager),
|
||||||
typeof(IProviderManager),
|
typeof(IMetadataProvider),
|
||||||
typeof(ITaskManager),
|
typeof(ITaskManager),
|
||||||
typeof(ILibraryManager)
|
typeof(ILibraryManager)
|
||||||
};
|
};
|
||||||
@ -88,6 +90,39 @@ namespace Kyoo
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Configure(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
builder.RegisterType<ConfigurationManager>().As<IConfigurationManager>().SingleInstance();
|
||||||
|
builder.RegisterType<FileManager>().As<IFileManager>().SingleInstance();
|
||||||
|
builder.RegisterType<Transcoder>().As<ITranscoder>().SingleInstance();
|
||||||
|
builder.RegisterType<ThumbnailsManager>().As<IThumbnailsManager>().SingleInstance();
|
||||||
|
builder.RegisterType<TaskManager>().As<ITaskManager>().SingleInstance();
|
||||||
|
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
|
||||||
|
builder.RegisterComposite<ProviderComposite, IMetadataProvider>().InstancePerLifetimeScope();
|
||||||
|
|
||||||
|
builder.RegisterTask<Crawler>();
|
||||||
|
|
||||||
|
static bool DatabaseIsPresent(IComponentRegistryBuilder x)
|
||||||
|
=> x.IsRegistered(new TypedService(typeof(DatabaseContext)));
|
||||||
|
|
||||||
|
builder.RegisterRepository<ILibraryRepository, LibraryRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<ICollectionRepository, CollectionRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IShowRepository, ShowRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<ISeasonRepository, SeasonRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IEpisodeRepository, EpisodeRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<ITrackRepository, TrackRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IPeopleRepository, PeopleRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IStudioRepository, StudioRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IGenreRepository, GenreRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IProviderRepository, ProviderRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
builder.RegisterRepository<IUserRepository, UserRepository>().OnlyIf(DatabaseIsPresent);
|
||||||
|
|
||||||
|
builder.RegisterType<PassthroughPermissionValidator>().As<IPermissionValidator>()
|
||||||
|
.IfNotRegistered(typeof(IPermissionValidator));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
||||||
{
|
{
|
||||||
@ -109,36 +144,7 @@ namespace Kyoo
|
|||||||
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
|
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddSingleton<IConfigurationManager, ConfigurationManager>();
|
|
||||||
services.AddSingleton<IFileManager, FileManager>();
|
|
||||||
services.AddSingleton<ITranscoder, Transcoder>();
|
|
||||||
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
|
||||||
services.AddSingleton<IProviderManager, ProviderManager>();
|
|
||||||
services.AddSingleton<ITaskManager, TaskManager>();
|
|
||||||
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
|
services.AddHostedService(x => x.GetService<ITaskManager>() as TaskManager);
|
||||||
|
|
||||||
services.AddScoped<ILibraryManager, LibraryManager>();
|
|
||||||
|
|
||||||
if (ProviderCondition.Has(typeof(DatabaseContext), availableTypes))
|
|
||||||
{
|
|
||||||
services.AddRepository<ILibraryRepository, LibraryRepository>();
|
|
||||||
services.AddRepository<ILibraryItemRepository, LibraryItemRepository>();
|
|
||||||
services.AddRepository<ICollectionRepository, CollectionRepository>();
|
|
||||||
services.AddRepository<IShowRepository, ShowRepository>();
|
|
||||||
services.AddRepository<ISeasonRepository, SeasonRepository>();
|
|
||||||
services.AddRepository<IEpisodeRepository, EpisodeRepository>();
|
|
||||||
services.AddRepository<ITrackRepository, TrackRepository>();
|
|
||||||
services.AddRepository<IPeopleRepository, PeopleRepository>();
|
|
||||||
services.AddRepository<IStudioRepository, StudioRepository>();
|
|
||||||
services.AddRepository<IGenreRepository, GenreRepository>();
|
|
||||||
services.AddRepository<IProviderRepository, ProviderRepository>();
|
|
||||||
services.AddRepository<IUserRepository, UserRepository>();
|
|
||||||
}
|
|
||||||
|
|
||||||
services.AddTask<Crawler>();
|
|
||||||
|
|
||||||
if (services.All(x => x.ServiceType != typeof(IPermissionValidator)))
|
|
||||||
services.AddSingleton<IPermissionValidator, PassthroughPermissionValidator>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
|
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
|
||||||
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
|
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
|
||||||
|
<PackageReference Include="Autofac" Version="6.2.0" />
|
||||||
|
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="7.1.0" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.8" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.17" />
|
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.17" />
|
||||||
|
@ -2,12 +2,13 @@ using System;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Autofac.Extensions.DependencyInjection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -30,6 +31,8 @@ namespace Kyoo
|
|||||||
if (!File.Exists("./settings.json"))
|
if (!File.Exists("./settings.json"))
|
||||||
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json");
|
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json");
|
||||||
|
|
||||||
|
IHostBuilder builder = CreateWebHostBuilder(args);
|
||||||
|
|
||||||
bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
|
bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
|
||||||
{
|
{
|
||||||
"d" => true,
|
"d" => true,
|
||||||
@ -43,18 +46,21 @@ namespace Kyoo
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (debug == null && Environment.GetEnvironmentVariable("ENVIRONMENT") != null)
|
if (debug == null && Environment.GetEnvironmentVariable("ENVIRONMENT") != null)
|
||||||
Console.WriteLine($"Invalid ENVIRONMENT variable. Supported values are \"debug\" and \"prod\". Ignoring...");
|
{
|
||||||
|
Console.WriteLine(
|
||||||
|
$"Invalid ENVIRONMENT variable. Supported values are \"debug\" and \"prod\". Ignoring...");
|
||||||
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
debug ??= true;
|
debug ??= true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Console.WriteLine($"Running as {Environment.UserName}.");
|
|
||||||
IWebHostBuilder builder = CreateWebHostBuilder(args);
|
|
||||||
if (debug != null)
|
if (debug != null)
|
||||||
builder = builder.UseEnvironment(debug == true ? "Development" : "Production");
|
builder = builder.UseEnvironment(debug == true ? "Development" : "Production");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
Console.WriteLine($"Running as {Environment.UserName}.");
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -81,13 +87,14 @@ namespace Kyoo
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
||||||
/// <returns>A new web host instance</returns>
|
/// <returns>A new web host instance</returns>
|
||||||
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
private static IHostBuilder CreateWebHostBuilder(string[] args)
|
||||||
{
|
{
|
||||||
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
|
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
|
||||||
|
|
||||||
return new WebHostBuilder()
|
|
||||||
|
return new HostBuilder()
|
||||||
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||||
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
||||||
.UseConfiguration(configuration)
|
|
||||||
.ConfigureAppConfiguration(x => SetupConfig(x, args))
|
.ConfigureAppConfiguration(x => SetupConfig(x, args))
|
||||||
.ConfigureLogging((context, builder) =>
|
.ConfigureLogging((context, builder) =>
|
||||||
{
|
{
|
||||||
@ -99,18 +106,20 @@ namespace Kyoo
|
|||||||
.AddDebug()
|
.AddDebug()
|
||||||
.AddEventSourceLogger();
|
.AddEventSourceLogger();
|
||||||
})
|
})
|
||||||
.UseDefaultServiceProvider((context, options) =>
|
// .UseDefaultServiceProvider((context, options) =>
|
||||||
{
|
// {
|
||||||
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
|
// options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
|
||||||
if (context.HostingEnvironment.IsDevelopment())
|
// if (context.HostingEnvironment.IsDevelopment())
|
||||||
StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
|
// StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
|
||||||
})
|
// })
|
||||||
.ConfigureServices(x => x.AddRouting())
|
.ConfigureServices(x => x.AddRouting())
|
||||||
.UseKestrel(options => { options.AddServerHeader = false; })
|
.ConfigureWebHost(x => x
|
||||||
.UseIIS()
|
.UseKestrel(options => { options.AddServerHeader = false; })
|
||||||
.UseIISIntegration()
|
.UseIIS()
|
||||||
.UseUrls(configuration.GetValue<string>("basics:url"))
|
.UseIISIntegration()
|
||||||
.UseStartup<Startup>();
|
.UseUrls(configuration.GetValue<string>("basics:url"))
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Autofac;
|
||||||
using Kyoo.Authentication;
|
using Kyoo.Authentication;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
@ -71,12 +72,16 @@ namespace Kyoo
|
|||||||
|
|
||||||
services.AddHttpClient();
|
services.AddHttpClient();
|
||||||
|
|
||||||
services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
|
// services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
|
||||||
|
|
||||||
services.AddSingleton(_plugins);
|
|
||||||
services.AddTask<PluginInitializer>();
|
|
||||||
_plugins.ConfigureServices(services);
|
_plugins.ConfigureServices(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ConfigureContainer(ContainerBuilder builder)
|
||||||
|
{
|
||||||
|
builder.RegisterInstance(_plugins).As<IPluginManager>().ExternallyOwned();
|
||||||
|
builder.RegisterTask<PluginInitializer>();
|
||||||
|
_plugins.ConfigureContainer(builder);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure the asp net host.
|
/// Configure the asp net host.
|
||||||
|
@ -25,7 +25,7 @@ namespace Kyoo.Tasks
|
|||||||
|
|
||||||
[Injected] public IServiceProvider ServiceProvider { private get; set; }
|
[Injected] public IServiceProvider ServiceProvider { private get; set; }
|
||||||
[Injected] public IThumbnailsManager ThumbnailsManager { private get; set; }
|
[Injected] public IThumbnailsManager ThumbnailsManager { private get; set; }
|
||||||
[Injected] public IProviderManager MetadataProvider { private get; set; }
|
[Injected] public IMetadataProvider MetadataProvider { private get; set; }
|
||||||
[Injected] public ITranscoder Transcoder { private get; set; }
|
[Injected] public ITranscoder Transcoder { private get; set; }
|
||||||
[Injected] public IConfiguration Config { private get; set; }
|
[Injected] public IConfiguration Config { private get; set; }
|
||||||
|
|
||||||
@ -258,7 +258,7 @@ namespace Kyoo.Tasks
|
|||||||
Collection collection = await libraryManager.GetOrDefault<Collection>(Utility.ToSlug(collectionName));
|
Collection collection = await libraryManager.GetOrDefault<Collection>(Utility.ToSlug(collectionName));
|
||||||
if (collection != null)
|
if (collection != null)
|
||||||
return collection;
|
return collection;
|
||||||
collection = await MetadataProvider.GetCollectionFromName(collectionName, library);
|
// collection = await MetadataProvider.GetCollectionFromName(collectionName, library);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -283,9 +283,10 @@ namespace Kyoo.Tasks
|
|||||||
await libraryManager.Load(old, x => x.ExternalIDs);
|
await libraryManager.Load(old, x => x.ExternalIDs);
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
Show show = await MetadataProvider.SearchShow(showTitle, isMovie, library);
|
|
||||||
|
Show show = new();//await MetadataProvider.SearchShow(showTitle, isMovie, library);
|
||||||
show.Path = showPath;
|
show.Path = showPath;
|
||||||
show.People = await MetadataProvider.GetPeople(show, library);
|
// show.People = await MetadataProvider.GetPeople(show, library);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -325,7 +326,7 @@ namespace Kyoo.Tasks
|
|||||||
}
|
}
|
||||||
catch (ItemNotFoundException)
|
catch (ItemNotFoundException)
|
||||||
{
|
{
|
||||||
Season season = await MetadataProvider.GetSeason(show, seasonNumber, library);
|
Season season = new();//await MetadataProvider.GetSeason(show, seasonNumber, library);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await libraryManager.Create(season);
|
await libraryManager.Create(season);
|
||||||
@ -348,12 +349,12 @@ namespace Kyoo.Tasks
|
|||||||
string episodePath,
|
string episodePath,
|
||||||
Library library)
|
Library library)
|
||||||
{
|
{
|
||||||
Episode episode = await MetadataProvider.GetEpisode(show,
|
Episode episode = new();/*await MetadataProvider.GetEpisode(show,
|
||||||
episodePath,
|
episodePath,
|
||||||
season?.SeasonNumber,
|
season?.SeasonNumber,
|
||||||
episodeNumber,
|
episodeNumber,
|
||||||
absoluteNumber,
|
absoluteNumber,
|
||||||
library);
|
library);*/
|
||||||
|
|
||||||
if (episode.SeasonNumber != null)
|
if (episode.SeasonNumber != null)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user