diff --git a/Kyoo.Common/Controllers/IMetadataProvider.cs b/Kyoo.Common/Controllers/IMetadataProvider.cs
index a0c30cbb..9c260030 100644
--- a/Kyoo.Common/Controllers/IMetadataProvider.cs
+++ b/Kyoo.Common/Controllers/IMetadataProvider.cs
@@ -1,21 +1,56 @@
-using Kyoo.Models;
+using System;
+using Kyoo.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
+using JetBrains.Annotations;
namespace Kyoo.Controllers
{
+ ///
+ /// An interface to automatically retrieve metadata from external providers.
+ ///
public interface IMetadataProvider
{
+ ///
+ /// The corresponding to this provider.
+ /// This allow to map metadata to a provider, keep metadata links and
+ /// know witch is used for a specific .
+ ///
Provider Provider { get; }
- Task GetCollectionFromName(string name);
+ ///
+ /// Return a new item with metadata from your provider.
+ ///
+ ///
+ /// 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.
+ ///
+ ///
+ /// You must not use metadata from the given .
+ /// Merging metadata is the job of Kyoo, a complex is given
+ /// to make a precise search and give you every available properties, not to discard properties.
+ ///
+ ///
+ /// If this metadata provider does not support .
+ ///
+ /// A new containing metadata from your provider
+ [ItemNotNull]
+ Task Get([NotNull] T item)
+ where T : class, IResource;
- Task GetShowByID(Show show);
- Task> SearchShows(string showName, bool isMovie);
+ ///
+ /// Search for a specific type of items with a given query.
+ ///
+ /// The search query to use.
+ ///
+ /// If this metadata provider does not support .
+ ///
+ /// The list of items that could be found on this specific provider.
+ [ItemNotNull]
+ Task> Search(string query)
+ where T : class, IResource;
+
Task> GetPeople(Show show);
-
- Task GetSeason(Show show, int seasonNumber);
-
- Task GetEpisode(Show show, int? seasonNumber, int? episodeNumber, int? absoluteNumber);
}
}
diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs
index 3201df83..83cc70a4 100644
--- a/Kyoo.Common/Controllers/IPlugin.cs
+++ b/Kyoo.Common/Controllers/IPlugin.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Autofac;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@@ -55,6 +56,15 @@ namespace Kyoo.Controllers
///
ICollection Requires { get; }
+ ///
+ /// A configure method that will be run on plugin's startup.
+ ///
+ /// The autofac service container to register services.
+ void Configure(ContainerBuilder builder)
+ {
+ // Skipped
+ }
+
///
/// A configure method that will be run on plugin's startup.
///
@@ -64,21 +74,31 @@ namespace Kyoo.Controllers
/// or >
/// You can't simply check on the service collection because some dependencies might be registered after your plugin.
///
- void Configure(IServiceCollection services, ICollection availableTypes);
+ void Configure(IServiceCollection services, ICollection availableTypes)
+ {
+ // Skipped
+ }
+
///
/// 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.
///
/// The Asp.Net application builder. On most case it is not needed but you can use it to add asp net functionalities.
- void ConfigureAspNet(IApplicationBuilder app) {}
-
+ void ConfigureAspNet(IApplicationBuilder app)
+ {
+ // Skipped
+ }
+
///
/// An optional function to execute and initialize your plugin.
/// It can be used to initialize a database connection, fill initial data or anything.
///
/// A service provider to request services
- void Initialize(IServiceProvider provider) {}
+ void Initialize(IServiceProvider provider)
+ {
+ // Skipped
+ }
}
///
diff --git a/Kyoo.Common/Controllers/IPluginManager.cs b/Kyoo.Common/Controllers/IPluginManager.cs
index bd4ef513..04d308f3 100644
--- a/Kyoo.Common/Controllers/IPluginManager.cs
+++ b/Kyoo.Common/Controllers/IPluginManager.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using Autofac;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@@ -42,7 +43,13 @@ namespace Kyoo.Controllers
public void LoadPlugins(ICollection plugins);
///
- /// Configure services adding or removing services as the plugins wants.
+ /// Configure container adding or removing services as the plugins wants.
+ ///
+ /// The container to populate
+ void ConfigureContainer(ContainerBuilder builder);
+
+ ///
+ /// Configure services via the microsoft way. This allow libraries to add their services.
///
/// The service collection to populate
public void ConfigureServices(IServiceCollection services);
diff --git a/Kyoo.Common/Controllers/IProviderManager.cs b/Kyoo.Common/Controllers/IProviderManager.cs
deleted file mode 100644
index dd83a283..00000000
--- a/Kyoo.Common/Controllers/IProviderManager.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using Kyoo.Models;
-
-namespace Kyoo.Controllers
-{
- public interface IProviderManager
- {
- Task GetCollectionFromName(string name, Library library);
- Task CompleteShow(Show show, Library library);
- Task SearchShow(string showName, bool isMovie, Library library);
- Task> SearchShows(string showName, bool isMovie, Library library);
- Task GetSeason(Show show, int seasonNumber, Library library);
- Task GetEpisode(Show show, string episodePath, int? seasonNumber, int? episodeNumber, int? absoluteNumber, Library library);
- Task> GetPeople(Show show, Library library);
- }
-}
\ No newline at end of file
diff --git a/Kyoo.Common/Kyoo.Common.csproj b/Kyoo.Common/Kyoo.Common.csproj
index 349ef6a0..ada2ed60 100644
--- a/Kyoo.Common/Kyoo.Common.csproj
+++ b/Kyoo.Common/Kyoo.Common.csproj
@@ -21,6 +21,7 @@
+
diff --git a/Kyoo.Common/Module.cs b/Kyoo.Common/Module.cs
index a8a81b88..d4442d98 100644
--- a/Kyoo.Common/Module.cs
+++ b/Kyoo.Common/Module.cs
@@ -1,5 +1,6 @@
-using System;
using System.Linq;
+using Autofac;
+using Autofac.Builder;
using Kyoo.Controllers;
using Kyoo.Models;
using Microsoft.Extensions.Configuration;
@@ -15,55 +16,63 @@ namespace Kyoo
///
/// Register a new task to the container.
///
- /// The container
+ /// The container
/// The type of the task
- /// The initial container.
- public static IServiceCollection AddTask(this IServiceCollection services)
+ /// The registration builder of this new task. That can be used to edit the registration.
+ public static IRegistrationBuilder
+ RegisterTask(this ContainerBuilder builder)
where T : class, ITask
{
- services.AddSingleton();
- return services;
+ return builder.RegisterType().As().SingleInstance();
+ }
+
+ ///
+ /// Register a new metadata provider to the container.
+ ///
+ /// The container
+ /// The type of the task
+ /// The registration builder of this new provider. That can be used to edit the registration.
+ public static IRegistrationBuilder
+ RegisterProvider(this ContainerBuilder builder)
+ where T : class, IMetadataProvider
+ {
+ return builder.RegisterType().As().InstancePerLifetimeScope();
}
///
/// Register a new repository to the container.
///
- /// The container
- /// The lifetime of the repository. The default is scoped.
+ /// The container
/// The type of the repository.
///
- /// If your repository implements a special interface, please use
+ /// If your repository implements a special interface, please use
///
/// The initial container.
- public static IServiceCollection AddRepository(this IServiceCollection services,
- ServiceLifetime lifetime = ServiceLifetime.Scoped)
+ public static IRegistrationBuilder
+ RegisterRepository(this ContainerBuilder builder)
where T : IBaseRepository
{
- Type repository = Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>));
-
- if (repository != null)
- services.Add(ServiceDescriptor.Describe(repository, typeof(T), lifetime));
- services.Add(ServiceDescriptor.Describe(typeof(IBaseRepository), typeof(T), lifetime));
- return services;
+ return builder.RegisterType()
+ .As()
+ .As(Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>)))
+ .InstancePerLifetimeScope();
}
///
/// Register a new repository with a custom mapping to the container.
///
- ///
- /// The lifetime of the repository. The default is scoped.
+ /// The container
/// The custom mapping you have for your repository.
/// The type of the repository.
///
- /// If your repository does not implements a special interface, please use
+ /// If your repository does not implements a special interface, please use
///
/// The initial container.
- public static IServiceCollection AddRepository(this IServiceCollection services,
- ServiceLifetime lifetime = ServiceLifetime.Scoped)
+ public static IRegistrationBuilder
+ RegisterRepository(this ContainerBuilder builder)
where T2 : IBaseRepository, T
{
- services.Add(ServiceDescriptor.Describe(typeof(T), typeof(T2), lifetime));
- return services.AddRepository(lifetime);
+ return builder.RegisterRepository().As();
}
///
diff --git a/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj b/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
new file mode 100644
index 00000000..1b6aee8f
--- /dev/null
+++ b/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
@@ -0,0 +1,33 @@
+
+
+ net5.0
+
+ SDG
+ Zoe Roux
+ https://github.com/AnonymusRaccoon/Kyoo
+ default
+ Kyoo.TheTvdb
+
+
+
+ ../Kyoo/bin/$(Configuration)/$(TargetFramework)/plugins/the-tvdb
+ false
+ false
+ false
+ false
+ true
+
+
+
+
+
+
+
+
+
+ all
+ false
+ runtime
+
+
+
diff --git a/Kyoo.TheTvdb/PluginTVDB.cs b/Kyoo.TheTvdb/PluginTVDB.cs
new file mode 100644
index 00000000..6484b51d
--- /dev/null
+++ b/Kyoo.TheTvdb/PluginTVDB.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using Kyoo.Controllers;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Kyoo.TheTvdb
+{
+ ///
+ /// A plugin that add a for The TVDB.
+ ///
+ public class PluginTvdb : IPlugin
+ {
+ ///
+ public string Slug => "the-tvdb";
+
+ ///
+ public string Name => "The TVDB Provider";
+
+ ///
+ public string Description => "A metadata provider for The TVDB.";
+
+ ///
+ public ICollection Provides => new []
+ {
+ typeof(IMetadataProvider)
+ };
+
+ ///
+ public ICollection ConditionalProvides => ArraySegment.Empty;
+
+ ///
+ public ICollection Requires => ArraySegment.Empty;
+
+
+ ///
+ public void Configure(IServiceCollection services, ICollection availableTypes)
+ {
+ // services.AddProvider();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kyoo.TheTvdb/ProviderTVDB.cs b/Kyoo.TheTvdb/ProviderTVDB.cs
new file mode 100644
index 00000000..eeb065c9
--- /dev/null
+++ b/Kyoo.TheTvdb/ProviderTVDB.cs
@@ -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
+{
+ ///
+ /// A metadata provider for The TVDB.
+ ///
+ public class ProviderTvdb : IMetadataProvider
+ {
+ public Provider Provider { get; }
+ public Task Get(T item) where T : class, IResource
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> Search(string query) where T : class, IResource
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> 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 GetCollectionFromName(string name)
+ // {
+ // return Task.FromResult(null);
+ // }
+ //
+ // public async Task> SearchShows(string showName, bool isMovie)
+ // {
+ // await Authentificate();
+ //
+ // if (isMovie)
+ // return null; //There is no movie search API for now on TheTVDB.
+ // TvDbResponse shows = await _client.Search.SearchSeriesAsync(showName, SearchParameter.Name);
+ // return shows.Data.Select(x => x.ToShow(Provider)).ToArray();
+ // }
+ //
+ // public async Task GetShowByID(Show show)
+ // {
+ // if (!int.TryParse(show?.GetID(Provider.Name), out int id))
+ // return await Task.FromResult(null);
+ // await Authentificate();
+ // TvDbResponse serie = await _client.Series.GetAsync(id);
+ // return serie.Data.ToShow(Provider);
+ // }
+ //
+ // public async Task> GetPeople(Show show)
+ // {
+ // if (!int.TryParse(show?.GetID(Provider.Name), out int id))
+ // return null;
+ // await Authentificate();
+ // TvDbResponse people = await _client.Series.GetActorsAsync(id);
+ // return people.Data.Select(x => x.ToPeopleRole(Provider)).ToArray();
+ // }
+ //
+ // public Task GetSeason(Show show, int seasonNumber)
+ // {
+ // return Task.FromResult(null);
+ // }
+ //
+ // public async Task GetEpisode(Show show, int seasonNumber, int episodeNumber, int absoluteNumber)
+ // {
+ // if (!int.TryParse(show?.GetID(Provider.Name), out int id))
+ // return null;
+ // await Authentificate();
+ // TvDbResponse 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}")
+ // });
+ // }
+ // }
+}
\ No newline at end of file
diff --git a/Kyoo.sln b/Kyoo.sln
index 60998b55..55aeb44c 100644
--- a/Kyoo.sln
+++ b/Kyoo.sln
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "Kyoo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.SqLite", "Kyoo.SqLite\Kyoo.SqLite.csproj", "{6515380E-1E57-42DA-B6E3-E1C8A848818A}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheTvdb", "Kyoo.TheTvdb\Kyoo.TheTvdb.csproj", "{D06BF829-23F5-40F3-A62D-627D9F4B4D6C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
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}.Release|Any CPU.ActiveCfg = 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
EndGlobal
diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs
index 7d0c399b..cd0a38f6 100644
--- a/Kyoo/Controllers/PluginManager.cs
+++ b/Kyoo/Controllers/PluginManager.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
+using Autofac;
using Kyoo.Models.Options;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
@@ -126,6 +127,12 @@ namespace Kyoo.Controllers
else
_logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name));
}
+
+ public void ConfigureContainer(ContainerBuilder builder)
+ {
+ foreach (IPlugin plugin in _plugins)
+ plugin.Configure(builder);
+ }
///
public void ConfigureServices(IServiceCollection services)
diff --git a/Kyoo/Controllers/ProviderComposite.cs b/Kyoo/Controllers/ProviderComposite.cs
new file mode 100644
index 00000000..9b7e498b
--- /dev/null
+++ b/Kyoo/Controllers/ProviderComposite.cs
@@ -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 _providers;
+
+
+ public ProviderComposite(IEnumerable providers)
+ {
+ _providers = providers;
+ }
+
+ public Provider Provider { get; }
+ public Task Get(T item) where T : class, IResource
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> Search(string query) where T : class, IResource
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task> GetPeople(Show show)
+ {
+ throw new NotImplementedException();
+ }
+
+ // private async Task GetMetadata(Func> providerCall, Library library, string what)
+ // where T : new()
+ // {
+ // T ret = new();
+ //
+ // IEnumerable 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> GetMetadata(
+ // Func>> providerCall,
+ // Library library,
+ // string what)
+ // {
+ // List ret = new();
+ //
+ // IEnumerable 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());
+ // } 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 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 CompleteShow(Show show, Library library)
+ // {
+ // return await GetMetadata(provider => provider.GetShowByID(show), library, $"the show {show.Title}");
+ // }
+ //
+ // public async Task 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> SearchShows(string showName, bool isMovie, Library library)
+ // {
+ // IEnumerable 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 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 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> GetPeople(Show show, Library library)
+ // {
+ // List 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();
+ // }
+ }
+}
diff --git a/Kyoo/Controllers/ProviderManager.cs b/Kyoo/Controllers/ProviderManager.cs
deleted file mode 100644
index 6ed5f796..00000000
--- a/Kyoo/Controllers/ProviderManager.cs
+++ /dev/null
@@ -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 _providers;
-
- public ProviderManager(IPluginManager pluginManager)
- {
- _providers = pluginManager.GetPlugins();
- }
-
- private async Task GetMetadata(Func> providerCall, Library library, string what)
- where T : new()
- {
- T ret = new();
-
- IEnumerable 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> GetMetadata(
- Func>> providerCall,
- Library library,
- string what)
- {
- List ret = new();
-
- IEnumerable 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());
- } 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 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 CompleteShow(Show show, Library library)
- {
- return await GetMetadata(provider => provider.GetShowByID(show), library, $"the show {show.Title}");
- }
-
- public async Task 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> SearchShows(string showName, bool isMovie, Library library)
- {
- IEnumerable 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 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 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> GetPeople(Show show, Library library)
- {
- List 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();
- }
- }
-}
diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs
index 34e24e75..a0dc0729 100644
--- a/Kyoo/CoreModule.cs
+++ b/Kyoo/CoreModule.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
+using Autofac;
+using Autofac.Core;
+using Autofac.Core.Registration;
using Kyoo.Controllers;
using Kyoo.Models.Options;
using Kyoo.Models.Permissions;
@@ -34,7 +36,7 @@ namespace Kyoo
typeof(IFileManager),
typeof(ITranscoder),
typeof(IThumbnailsManager),
- typeof(IProviderManager),
+ typeof(IMetadataProvider),
typeof(ITaskManager),
typeof(ILibraryManager)
};
@@ -88,6 +90,39 @@ namespace Kyoo
_configuration = configuration;
}
+ ///
+ public void Configure(ContainerBuilder builder)
+ {
+ builder.RegisterType().As().SingleInstance();
+ builder.RegisterType().As().SingleInstance();
+ builder.RegisterType().As().SingleInstance();
+ builder.RegisterType().As().SingleInstance();
+ builder.RegisterType().As().SingleInstance();
+ builder.RegisterType().As().InstancePerLifetimeScope();
+ builder.RegisterComposite().InstancePerLifetimeScope();
+
+ builder.RegisterTask();
+
+ static bool DatabaseIsPresent(IComponentRegistryBuilder x)
+ => x.IsRegistered(new TypedService(typeof(DatabaseContext)));
+
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+ builder.RegisterRepository().OnlyIf(DatabaseIsPresent);
+
+ builder.RegisterType().As()
+ .IfNotRegistered(typeof(IPermissionValidator));
+ }
+
///
public void Configure(IServiceCollection services, ICollection availableTypes)
{
@@ -109,36 +144,7 @@ namespace Kyoo
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
});
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
services.AddHostedService(x => x.GetService() as TaskManager);
-
- services.AddScoped();
-
- if (ProviderCondition.Has(typeof(DatabaseContext), availableTypes))
- {
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- services.AddRepository();
- }
-
- services.AddTask();
-
- if (services.All(x => x.ServiceType != typeof(IPermissionValidator)))
- services.AddSingleton();
}
///
diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj
index 438f3e9b..b1bad964 100644
--- a/Kyoo/Kyoo.csproj
+++ b/Kyoo/Kyoo.csproj
@@ -34,6 +34,8 @@
+
+
diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs
index 12227266..44b80849 100644
--- a/Kyoo/Program.cs
+++ b/Kyoo/Program.cs
@@ -2,12 +2,13 @@ using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
+using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Hosting.StaticWebAssets;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
+
namespace Kyoo
{
///
@@ -30,6 +31,8 @@ namespace Kyoo
if (!File.Exists("./settings.json"))
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json");
+ IHostBuilder builder = CreateWebHostBuilder(args);
+
bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
{
"d" => true,
@@ -43,18 +46,21 @@ namespace Kyoo
};
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
debug ??= true;
#endif
- Console.WriteLine($"Running as {Environment.UserName}.");
- IWebHostBuilder builder = CreateWebHostBuilder(args);
if (debug != null)
builder = builder.UseEnvironment(debug == true ? "Development" : "Production");
+
try
{
+ Console.WriteLine($"Running as {Environment.UserName}.");
await builder.Build().RunAsync();
}
catch (Exception ex)
@@ -81,13 +87,14 @@ namespace Kyoo
///
/// Command line parameters that can be handled by kestrel
/// A new web host instance
- private static IWebHostBuilder CreateWebHostBuilder(string[] args)
+ private static IHostBuilder CreateWebHostBuilder(string[] args)
{
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
- return new WebHostBuilder()
+
+ return new HostBuilder()
+ .UseServiceProviderFactory(new AutofacServiceProviderFactory())
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
- .UseConfiguration(configuration)
.ConfigureAppConfiguration(x => SetupConfig(x, args))
.ConfigureLogging((context, builder) =>
{
@@ -99,18 +106,20 @@ namespace Kyoo
.AddDebug()
.AddEventSourceLogger();
})
- .UseDefaultServiceProvider((context, options) =>
- {
- options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
- if (context.HostingEnvironment.IsDevelopment())
- StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
- })
+ // .UseDefaultServiceProvider((context, options) =>
+ // {
+ // options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
+ // if (context.HostingEnvironment.IsDevelopment())
+ // StaticWebAssetsLoader.UseStaticWebAssets(context.HostingEnvironment, context.Configuration);
+ // })
.ConfigureServices(x => x.AddRouting())
- .UseKestrel(options => { options.AddServerHeader = false; })
- .UseIIS()
- .UseIISIntegration()
- .UseUrls(configuration.GetValue("basics:url"))
- .UseStartup();
+ .ConfigureWebHost(x => x
+ .UseKestrel(options => { options.AddServerHeader = false; })
+ .UseIIS()
+ .UseIISIntegration()
+ .UseUrls(configuration.GetValue("basics:url"))
+ .UseStartup()
+ );
}
}
}
diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs
index 4d5995ef..5557e872 100644
--- a/Kyoo/Startup.cs
+++ b/Kyoo/Startup.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using Autofac;
using Kyoo.Authentication;
using Kyoo.Controllers;
using Kyoo.Models;
@@ -71,12 +72,16 @@ namespace Kyoo
services.AddHttpClient();
- services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
-
- services.AddSingleton(_plugins);
- services.AddTask();
+ // services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
_plugins.ConfigureServices(services);
}
+
+ public void ConfigureContainer(ContainerBuilder builder)
+ {
+ builder.RegisterInstance(_plugins).As().ExternallyOwned();
+ builder.RegisterTask();
+ _plugins.ConfigureContainer(builder);
+ }
///
/// Configure the asp net host.
diff --git a/Kyoo/Tasks/Crawler.cs b/Kyoo/Tasks/Crawler.cs
index 9f1185dd..e9d99010 100644
--- a/Kyoo/Tasks/Crawler.cs
+++ b/Kyoo/Tasks/Crawler.cs
@@ -25,7 +25,7 @@ namespace Kyoo.Tasks
[Injected] public IServiceProvider ServiceProvider { 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 IConfiguration Config { private get; set; }
@@ -258,7 +258,7 @@ namespace Kyoo.Tasks
Collection collection = await libraryManager.GetOrDefault(Utility.ToSlug(collectionName));
if (collection != null)
return collection;
- collection = await MetadataProvider.GetCollectionFromName(collectionName, library);
+ // collection = await MetadataProvider.GetCollectionFromName(collectionName, library);
try
{
@@ -283,9 +283,10 @@ namespace Kyoo.Tasks
await libraryManager.Load(old, x => x.ExternalIDs);
return old;
}
- Show show = await MetadataProvider.SearchShow(showTitle, isMovie, library);
+
+ Show show = new();//await MetadataProvider.SearchShow(showTitle, isMovie, library);
show.Path = showPath;
- show.People = await MetadataProvider.GetPeople(show, library);
+ // show.People = await MetadataProvider.GetPeople(show, library);
try
{
@@ -325,7 +326,7 @@ namespace Kyoo.Tasks
}
catch (ItemNotFoundException)
{
- Season season = await MetadataProvider.GetSeason(show, seasonNumber, library);
+ Season season = new();//await MetadataProvider.GetSeason(show, seasonNumber, library);
try
{
await libraryManager.Create(season);
@@ -348,12 +349,12 @@ namespace Kyoo.Tasks
string episodePath,
Library library)
{
- Episode episode = await MetadataProvider.GetEpisode(show,
+ Episode episode = new();/*await MetadataProvider.GetEpisode(show,
episodePath,
season?.SeasonNumber,
episodeNumber,
absoluteNumber,
- library);
+ library);*/
if (episode.SeasonNumber != null)
{