mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
CodingStlye: Fixing whitespaces
This commit is contained in:
parent
8ff2fe3965
commit
d3a03771dd
@ -7,6 +7,7 @@ trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
smart_tab = true
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_style = space
|
||||
|
@ -6,12 +6,15 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.354" />
|
||||
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.354" PrivateAssets="All" />
|
||||
|
||||
<None Include="$(MSBuildThisFileDirectory)stylecop.json" Link="stylecop.json" Visible="false" />
|
||||
<None Include="$(MSBuildThisFileDirectory).editorconfig" Link="stylecop.json" Visible="false" />
|
||||
<None Include="$(MSBuildThisFileDirectory).editorconfig" Link=".editorconfig" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)Kyoo.ruleset</CodeAnalysisRuleSet>
|
||||
<!-- <AnalysisMode>AllEnabledByDefault</AnalysisMode>-->
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -26,62 +26,62 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// The repository that handle libraries.
|
||||
/// </summary>
|
||||
ILibraryRepository LibraryRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries's items (a wrapper arround shows & collections).
|
||||
/// </summary>
|
||||
ILibraryItemRepository LibraryItemRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle collections.
|
||||
/// </summary>
|
||||
ICollectionRepository CollectionRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IShowRepository ShowRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle seasons.
|
||||
/// </summary>
|
||||
ISeasonRepository SeasonRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle episodes.
|
||||
/// </summary>
|
||||
IEpisodeRepository EpisodeRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle tracks.
|
||||
/// </summary>
|
||||
ITrackRepository TrackRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle people.
|
||||
/// </summary>
|
||||
IPeopleRepository PeopleRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle studios.
|
||||
/// </summary>
|
||||
IStudioRepository StudioRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle genres.
|
||||
/// </summary>
|
||||
IGenreRepository GenreRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle providers.
|
||||
/// </summary>
|
||||
IProviderRepository ProviderRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
IUserRepository UserRepository { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's ID
|
||||
/// </summary>
|
||||
@ -91,7 +91,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(int id) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug
|
||||
/// </summary>
|
||||
@ -101,7 +101,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get<T>(string slug) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function.
|
||||
/// </summary>
|
||||
@ -121,7 +121,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
@ -131,7 +131,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The season found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
@ -142,7 +142,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemNotNull]
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
@ -162,7 +162,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(int id) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
@ -171,7 +171,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault<T>(string slug) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function or null if it is not found.
|
||||
/// </summary>
|
||||
@ -189,7 +189,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
@ -198,7 +198,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The season found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
@ -208,7 +208,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The episode found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
@ -284,7 +284,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="Load{T,T2}(T, System.Linq.Expressions.Expression{System.Func{T,System.Collections.Generic.ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, System.String, bool)"/>
|
||||
Task Load([NotNull] IResource obj, string memberName, bool force = false);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper arround shows or collections) from a library.
|
||||
/// </summary>
|
||||
@ -297,7 +297,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper arround shows or collections) from a library.
|
||||
/// </summary>
|
||||
@ -311,7 +311,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper arround shows or collections) from a library.
|
||||
/// </summary>
|
||||
@ -324,7 +324,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper arround shows or collections) from a library.
|
||||
/// </summary>
|
||||
@ -338,8 +338,8 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetItemsFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
@ -349,10 +349,10 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
@ -366,7 +366,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetPeopleFromShow(showID, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
@ -376,10 +376,10 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
@ -393,8 +393,8 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -404,10 +404,10 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -421,7 +421,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetRolesFromPeople(id, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -431,10 +431,10 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -449,7 +449,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Pagination limit = default
|
||||
) => GetRolesFromPeople(slug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
@ -457,7 +457,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="libraryID">The library's ID to setup relations with (optional)</param>
|
||||
/// <param name="collectionID">The collection's ID to setup relations with (optional)</param>
|
||||
Task AddShowLink(int showID, int? libraryID, int? collectionID);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Setup relations between a show, a library and a collection
|
||||
/// </summary>
|
||||
@ -477,7 +477,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all resources with filters
|
||||
/// </summary>
|
||||
@ -516,7 +516,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The resource registers and completed by database's informations (related items & so on)</returns>
|
||||
Task<T> Create<T>([NotNull] T item) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
@ -524,7 +524,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists<T>([NotNull] T item) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource
|
||||
/// </summary>
|
||||
@ -542,7 +542,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete<T>(T item) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID.
|
||||
/// </summary>
|
||||
@ -550,7 +550,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete<T>(int id) where T : class, IResource;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug.
|
||||
/// </summary>
|
||||
|
@ -20,17 +20,17 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// A slug to identify this plugin in queries.
|
||||
/// </summary>
|
||||
string Slug { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of the plugin
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The description of this plugin. This will be displayed on the "installed plugins" page.
|
||||
/// </summary>
|
||||
string Description { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if the plugin should be enabled, <c>false</c> otherwise.
|
||||
/// If a plugin is not enabled, no configure method will be called.
|
||||
@ -41,7 +41,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// By default, a plugin is always enabled. This method can be overriden to change this behavior.
|
||||
/// </remarks>
|
||||
virtual bool Enabled => true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A list of types that will be available via the IOptions interfaces and will be listed inside
|
||||
/// an IConfiguration.
|
||||
@ -64,7 +64,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <seealso cref="SA"/>
|
||||
virtual IEnumerable<IStartupAction> ConfigureSteps => ArraySegment<IStartupAction>.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// </summary>
|
||||
/// <param name="builder">The autofac service container to register services.</param>
|
||||
@ -72,7 +72,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
// Skipped
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A configure method that will be run on plugin's startup.
|
||||
/// This is available for libraries that build upon a <see cref="IServiceCollection"/>, for more precise
|
||||
@ -94,4 +94,4 @@ namespace Kyoo.Abstractions.Controllers
|
||||
// Skipped
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,14 +17,14 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">If no plugins match the query</exception>
|
||||
/// <returns>A plugin that match the queries</returns>
|
||||
public T GetPlugin<T>(string name);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of plugins to get</typeparam>
|
||||
/// <returns>A list of plugins matching the given type or an empty list of none match.</returns>
|
||||
public ICollection<T> GetPlugins<T>();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all plugins currently running on Kyoo. This also includes deleted plugins if the app as not been restarted.
|
||||
/// </summary>
|
||||
@ -39,7 +39,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// You should not try to put plugins from the plugins directory here as they will get automatically loaded.
|
||||
/// </param>
|
||||
public void LoadPlugins(ICollection<IPlugin> plugins);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Load plugins and their dependencies from the plugin directory.
|
||||
/// </summary>
|
||||
@ -49,4 +49,4 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </param>
|
||||
public void LoadPlugins(params Type[] plugins);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Count = count;
|
||||
AfterID = afterID;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly create a new pagination from a limit number.
|
||||
/// </summary>
|
||||
@ -57,7 +57,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
|
||||
/// </summary>
|
||||
public bool Descendant { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Sort{T}"/> instance.
|
||||
/// </summary>
|
||||
@ -68,7 +68,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
Key = key;
|
||||
Descendant = descendant;
|
||||
|
||||
|
||||
if (!Utility.IsPropertyExpression(Key))
|
||||
throw new ArgumentException("The given sort key is not valid.");
|
||||
}
|
||||
@ -86,7 +86,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Descendant = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
|
||||
string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
|
||||
|
||||
@ -116,7 +116,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </summary>
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A common repository for every resources.
|
||||
/// </summary>
|
||||
@ -147,7 +147,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Get(Expression<Func<T, bool>> where);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
@ -169,7 +169,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource found</returns>
|
||||
[ItemCanBeNull]
|
||||
Task<T> GetOrDefault(Expression<Func<T, bool>> where);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Search for resources.
|
||||
/// </summary>
|
||||
@ -177,7 +177,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>A list of resources found</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> Search(string query);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get every resources that match all filters
|
||||
/// </summary>
|
||||
@ -186,7 +186,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
[ItemNotNull]
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default);
|
||||
/// <summary>
|
||||
@ -208,8 +208,8 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <returns>How many resources matched that filter</returns>
|
||||
Task<int> GetCount(Expression<Func<T, bool>> where = null);
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
@ -217,7 +217,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource registers and completed by database's information (related items & so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Create([NotNull] T obj);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
@ -225,7 +225,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> CreateIfNotExists([NotNull] T obj);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource
|
||||
/// </summary>
|
||||
@ -235,7 +235,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The resource edited and completed by database's information (related items & so on)</returns>
|
||||
[ItemNotNull]
|
||||
Task<T> Edit([NotNull] T edited, bool resetOld);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID
|
||||
/// </summary>
|
||||
@ -254,7 +254,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
Task Delete([NotNull] T obj);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Delete all resources that match the predicate.
|
||||
/// </summary>
|
||||
@ -299,7 +299,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
@ -308,7 +308,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
@ -316,7 +316,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
@ -325,7 +325,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> GetOrDefault(string showSlug, int seasonNumber);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The repository to handle episodes
|
||||
/// </summary>
|
||||
@ -366,7 +366,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID and it's absolute number.
|
||||
/// </summary>
|
||||
@ -389,7 +389,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// A repository to handle tracks
|
||||
/// </summary>
|
||||
public interface ITrackRepository : IRepository<Track> { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle libraries.
|
||||
/// </summary>
|
||||
@ -425,7 +425,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get items (A wrapper around shows or collections) from a library.
|
||||
/// </summary>
|
||||
@ -451,18 +451,18 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<LibraryItem, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository for collections
|
||||
/// </summary>
|
||||
public interface ICollectionRepository : IRepository<Collection> { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A repository for genres.
|
||||
/// </summary>
|
||||
public interface IGenreRepository : IRepository<Genre> { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A repository for studios.
|
||||
/// </summary>
|
||||
@ -482,7 +482,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
/// <summary>
|
||||
@ -498,7 +498,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromShow(showID, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
@ -508,7 +508,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
/// <summary>
|
||||
@ -524,7 +524,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -534,7 +534,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
/// <summary>
|
||||
@ -550,7 +550,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Expression<Func<PeopleRole, object>> sort,
|
||||
Pagination limit = default
|
||||
) => GetFromPeople(id, where, new Sort<PeopleRole>(sort), limit);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
@ -560,7 +560,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default);
|
||||
/// <summary>
|
||||
@ -591,7 +591,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||
/// <typeparam name="T">The type of metadata to retrieve</typeparam>
|
||||
/// <returns>A filtered list of external ids.</returns>
|
||||
Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
||||
Task<ICollection<MetadataID>> GetMetadataID<T>(Expression<Func<MetadataID, bool>> where = null,
|
||||
Sort<MetadataID> sort = default,
|
||||
Pagination limit = default)
|
||||
where T : class, IMetadata;
|
||||
@ -609,9 +609,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
) where T : class, IMetadata
|
||||
=> GetMetadataID<T>(where, new Sort<MetadataID>(sort), limit);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle users.
|
||||
/// </summary>
|
||||
public interface IUserRepository : IRepository<User> {}
|
||||
public interface IUserRepository : IRepository<User> { }
|
||||
}
|
||||
|
@ -19,22 +19,22 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// The name of this parameter.
|
||||
/// </summary>
|
||||
public string Name { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The description of this parameter.
|
||||
/// </summary>
|
||||
public string Description { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of this parameter.
|
||||
/// </summary>
|
||||
public Type Type { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this parameter required or can it be ignored?
|
||||
/// </summary>
|
||||
public bool IsRequired { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The default value of this object.
|
||||
/// </summary>
|
||||
@ -44,7 +44,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// The value of the parameter.
|
||||
/// </summary>
|
||||
private object Value { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new task parameter.
|
||||
/// </summary>
|
||||
@ -61,7 +61,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Type = typeof(T)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new required task parameter.
|
||||
/// </summary>
|
||||
@ -79,7 +79,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
IsRequired = true
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a parameter's value to give to a task.
|
||||
/// </summary>
|
||||
@ -104,9 +104,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <returns>A new parameter's value for this current parameter</returns>
|
||||
public TaskParameter CreateValue(object value)
|
||||
{
|
||||
return this with {Value = value};
|
||||
return this with { Value = value };
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the value of this parameter. If the value is of the wrong type, it will be converted.
|
||||
/// </summary>
|
||||
@ -140,12 +140,12 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="name">The name of the task (case sensitive)</param>
|
||||
public TaskParameter this[string name] => this.FirstOrDefault(x => x.Name == name);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty, <see cref="TaskParameters"/>
|
||||
/// </summary>
|
||||
public TaskParameters() {}
|
||||
|
||||
public TaskParameters() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="TaskParameters"/> with an initial parameters content
|
||||
/// </summary>
|
||||
@ -155,7 +155,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
AddRange(parameters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A common interface that tasks should implement.
|
||||
/// </summary>
|
||||
@ -168,7 +168,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// All parameters that this task as. Every one of them will be given to the run function with a value.
|
||||
/// </returns>
|
||||
public TaskParameters GetParameters();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Start this task.
|
||||
/// </summary>
|
||||
@ -191,4 +191,4 @@ namespace Kyoo.Abstractions.Controllers
|
||||
[NotNull] IProgress<float> progress,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <exception cref="ItemNotFoundException">
|
||||
/// The task could not be found.
|
||||
/// </exception>
|
||||
void StartTask(string taskSlug,
|
||||
void StartTask(string taskSlug,
|
||||
[NotNull] IProgress<float> progress,
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null);
|
||||
@ -66,13 +66,13 @@ namespace Kyoo.Abstractions.Controllers
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null)
|
||||
where T : ITask;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all currently running tasks
|
||||
/// </summary>
|
||||
/// <returns>A list of currently running tasks.</returns>
|
||||
ICollection<(TaskMetadataAttribute, ITask)> GetRunningTasks();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get all available tasks
|
||||
/// </summary>
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Kyoo.Abstractions.Models;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers
|
||||
{
|
||||
|
@ -23,9 +23,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="action">The action to run</param>
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction New(Action action, int priority)
|
||||
public static StartupAction New(Action action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
@ -33,9 +33,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="priority">The priority of the new action</param>
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T> New<T>(Action<T> action, int priority)
|
||||
public static StartupAction<T> New<T>(Action<T> action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
@ -44,9 +44,9 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T">A dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
|
||||
public static StartupAction<T, T2> New<T, T2>(Action<T, T2> action, int priority)
|
||||
=> new(action, priority);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
@ -56,11 +56,11 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <typeparam name="T2">A second dependency that this action will use.</typeparam>
|
||||
/// <typeparam name="T3">A third dependency that this action will use.</typeparam>
|
||||
/// <returns>A new <see cref="StartupAction"/></returns>
|
||||
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
|
||||
public static StartupAction<T, T2, T3> New<T, T2, T3>(Action<T, T2, T3> action, int priority)
|
||||
=> new(action, priority);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An action executed on kyoo's startup to initialize the asp-net container.
|
||||
/// </summary>
|
||||
@ -81,7 +81,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="provider">The service provider containing all services can be used.</param>
|
||||
void Run(IServiceProvider provider);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with no dependencies.
|
||||
/// </summary>
|
||||
@ -94,7 +94,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction"/>.
|
||||
/// </summary>
|
||||
@ -126,7 +126,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T}"/>.
|
||||
/// </summary>
|
||||
@ -144,7 +144,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
_action.Invoke(provider.GetRequiredService<T>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with two dependencies.
|
||||
/// </summary>
|
||||
@ -180,7 +180,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="IStartupAction"/> with three dependencies.
|
||||
/// </summary>
|
||||
@ -196,7 +196,7 @@ namespace Kyoo.Abstractions.Controllers
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Priority { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="StartupAction{T, T2, T3}"/>.
|
||||
/// </summary>
|
||||
|
@ -20,13 +20,13 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// If multiples files with the same schemes exists, an exception will be thrown.
|
||||
/// </remarks>
|
||||
public string[] Scheme { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if the scheme should be removed from the path before calling
|
||||
/// methods of this <see cref="IFileSystem"/>, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool StripScheme { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="FileSystemMetadataAttribute"/> using the specified schemes.
|
||||
@ -36,7 +36,7 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
{
|
||||
Scheme = schemes;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="FileSystemMetadataAttribute"/> using a dictionary of metadata.
|
||||
/// </summary>
|
||||
|
@ -23,7 +23,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
Overall,
|
||||
Admin
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Specify permissions needed for the API.
|
||||
/// </summary>
|
||||
@ -63,7 +63,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
Kind = permission;
|
||||
Group = group;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
@ -97,7 +97,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind Kind { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
@ -118,7 +118,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
type = type[..^3];
|
||||
Type = type.ToLower();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
@ -134,7 +134,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
{
|
||||
Kind = permission;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
@ -158,7 +158,7 @@ namespace Kyoo.Abstractions.Models.Permissions
|
||||
/// <param name="attribute">The permission attribute to validate</param>
|
||||
/// <returns>An authorization filter used to validate the permission</returns>
|
||||
IFilterMetadata Create(PermissionAttribute attribute);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
|
@ -19,11 +19,11 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// The name of the field containing the related resource's ID.
|
||||
/// </summary>
|
||||
public string RelationID { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/>.
|
||||
/// </summary>
|
||||
public LoadableRelationAttribute() {}
|
||||
public LoadableRelationAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/> with a baking relationID field.
|
||||
|
@ -6,13 +6,13 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// Remove an property from the serialization pipeline. It will simply be skipped.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class SerializeIgnoreAttribute : Attribute {}
|
||||
|
||||
public class SerializeIgnoreAttribute : Attribute { }
|
||||
|
||||
/// <summary>
|
||||
/// Remove a property from the deserialization pipeline. The user can't input value for this property.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
|
||||
public class DeserializeIgnoreAttribute : Attribute {}
|
||||
public class DeserializeIgnoreAttribute : Attribute { }
|
||||
|
||||
/// <summary>
|
||||
/// Change the way the field is serialized. It allow one to use a string format like formatting instead of the default value.
|
||||
@ -25,7 +25,7 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// The format string to use.
|
||||
/// </summary>
|
||||
public string Format { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="SerializeAsAttribute"/> with the selected format.
|
||||
/// </summary>
|
||||
|
@ -16,12 +16,12 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// The slug of the task, used to start it.
|
||||
/// </summary>
|
||||
public string Slug { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of the task that will be displayed to the user.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A quick description of what this task will do.
|
||||
/// </summary>
|
||||
@ -31,18 +31,18 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
/// Should this task be automatically run at app startup?
|
||||
/// </summary>
|
||||
public bool RunOnStartup { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The priority of this task. Only used if <see cref="RunOnStartup"/> is true.
|
||||
/// It allow one to specify witch task will be started first as tasked are run on a Priority's descending order.
|
||||
/// </summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if this task should not be displayed to the user, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
public bool IsHidden { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskMetadataAttribute"/> with the given slug, name and description.
|
||||
@ -56,7 +56,7 @@ namespace Kyoo.Abstractions.Models.Attributes
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskMetadataAttribute"/> using a dictionary of metadata.
|
||||
/// </summary>
|
||||
|
@ -9,16 +9,16 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The start time of the chapter (in second from the start of the episode).
|
||||
/// </summary>
|
||||
public float StartTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The end time of the chapter (in second from the start of the episode)&.
|
||||
/// The end time of the chapter (in second from the start of the episode).
|
||||
/// </summary>
|
||||
public float EndTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this chapter. This should be a human-readable name that could be presented to the user.
|
||||
/// There should be well-known chapters name for commonly used chapters.
|
||||
/// For example, use "Opening" for the introduction-song and "Credits" for the end chapter with credits.
|
||||
/// For example, use "Opening" for the introduction-song and "Credits" for the end chapter with credits.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
@ -35,4 +35,4 @@ namespace Kyoo.Abstractions.Models
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
public Type Type { get; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ConfigurationReference"/> using a given path and type.
|
||||
/// This method does not create sub configuration resources. Please see <see cref="CreateReference"/>
|
||||
@ -75,7 +75,7 @@ namespace Kyoo.Abstractions.Models
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Return the list of configuration reference a type has.
|
||||
/// </summary>
|
||||
|
@ -15,7 +15,7 @@ namespace Kyoo.Abstractions.Models.Exceptions
|
||||
public DuplicatedItemException()
|
||||
: base("Already exists in the database.")
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="DuplicatedItemException"/> with a custom message.
|
||||
/// </summary>
|
||||
@ -23,7 +23,7 @@ namespace Kyoo.Abstractions.Models.Exceptions
|
||||
public DuplicatedItemException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
|
@ -15,24 +15,24 @@ namespace Kyoo.Abstractions.Models.Exceptions
|
||||
/// </summary>
|
||||
public TaskFailedException()
|
||||
: base("A task failed.")
|
||||
{}
|
||||
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskFailedException"/> with a custom message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message to use.</param>
|
||||
public TaskFailedException(string message)
|
||||
: base(message)
|
||||
{}
|
||||
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="TaskFailedException"/> wrapping another exception.
|
||||
/// </summary>
|
||||
/// <param name="exception">The exception to wrap.</param>
|
||||
public TaskFailedException(Exception exception)
|
||||
: base(exception)
|
||||
{}
|
||||
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// The serialization constructor
|
||||
/// </summary>
|
||||
|
@ -14,7 +14,7 @@ namespace Kyoo.Abstractions.Models
|
||||
Movie,
|
||||
Collection
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A type union between <see cref="Show"/> and <see cref="Collection"/>.
|
||||
/// This is used to list content put inside a library.
|
||||
@ -23,30 +23,30 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The title of the show or collection.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The summary of the show or collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished? This is only applicable for shows.
|
||||
/// </summary>
|
||||
public Status? Status { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection started airing. It can be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? StartAir { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The date this show or collection finished airing.
|
||||
/// It must be after the <see cref="StartAir"/> but can be the same (example: for movies).
|
||||
@ -64,17 +64,17 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </summary>
|
||||
[SerializeAs("{HOST}/api/{Type:l}/{Slug}/poster")]
|
||||
public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of this item (ether a collection, a show or a movie).
|
||||
/// </summary>
|
||||
public ItemType Type { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty <see cref="LibraryItem"/>.
|
||||
/// </summary>
|
||||
public LibraryItem() {}
|
||||
public LibraryItem() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a show.
|
||||
@ -92,7 +92,7 @@ namespace Kyoo.Abstractions.Models
|
||||
Images = show.Images;
|
||||
Type = show.IsMovie ? ItemType.Movie : ItemType.Show;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="LibraryItem"/> from a collection
|
||||
/// </summary>
|
||||
@ -125,7 +125,7 @@ namespace Kyoo.Abstractions.Models
|
||||
Images = x.Images,
|
||||
Type = x.IsMovie ? ItemType.Movie : ItemType.Show
|
||||
};
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An expression to create a <see cref="LibraryItem"/> representing a collection.
|
||||
/// </summary>
|
||||
|
@ -15,12 +15,12 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The link of the current page.
|
||||
/// </summary>
|
||||
public Uri This { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The link of the first page.
|
||||
/// </summary>
|
||||
public Uri First { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The link of the next page.
|
||||
/// </summary>
|
||||
@ -30,13 +30,13 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The number of items in the current page.
|
||||
/// </summary>
|
||||
public int Count => Items.Count;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of items in the page.
|
||||
/// </summary>
|
||||
public ICollection<T> Items { get; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/>.
|
||||
/// </summary>
|
||||
@ -72,7 +72,7 @@ namespace Kyoo.Abstractions.Models
|
||||
query["afterID"] = items.Last().ID.ToString();
|
||||
Next = new Uri(url + query.ToQueryString());
|
||||
}
|
||||
|
||||
|
||||
query.Remove("afterID");
|
||||
First = new Uri(url + query.ToQueryString());
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug => ForPeople ? Show.Slug : People.Slug;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should this role be used as a Show substitute (the value is <c>true</c>) or
|
||||
/// as a People substitute (the value is <c>false</c>).
|
||||
@ -30,7 +30,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The people that played this role.
|
||||
/// </summary>
|
||||
public People People { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show where the People playing in.
|
||||
/// </summary>
|
||||
@ -39,13 +39,13 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The show where the People played in.
|
||||
/// </summary>
|
||||
public Show Show { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of work the person has done for the show.
|
||||
/// That can be something like "Actor", "Writer", "Music", "Voice Actor"...
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The role the People played.
|
||||
/// This is mostly used to inform witch character was played for actor and voice actors.
|
||||
|
@ -12,10 +12,10 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this collection.
|
||||
/// </summary>
|
||||
@ -23,7 +23,7 @@ namespace Kyoo.Abstractions.Models
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of this poster.
|
||||
/// By default, the http path for this poster is returned from the public API.
|
||||
@ -37,17 +37,17 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The description of this collection.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows contained in this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of libraries that contains this collection.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using JetBrains.Annotations;
|
||||
@ -22,15 +22,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
if (ShowSlug != null || Show != null)
|
||||
return GetSlug(ShowSlug ?? Show.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
|
||||
return ShowID != 0
|
||||
? GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber)
|
||||
return ShowID != 0
|
||||
? GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber)
|
||||
: null;
|
||||
}
|
||||
[UsedImplicitly] [NotNull] private set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
|
||||
|
||||
Match match = Regex.Match(value, @"(?<show>.+)-s(?<season>\d+)e(?<episode>\d+)");
|
||||
|
||||
if (match.Success)
|
||||
@ -59,7 +59,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string ShowSlug { private get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this episode.
|
||||
/// </summary>
|
||||
@ -68,7 +68,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The show that contains this episode. This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(ShowID))] public Show Show { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Season containing this episode.
|
||||
/// </summary>
|
||||
@ -87,22 +87,22 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The season in witch this episode is in.
|
||||
/// </summary>
|
||||
public int? SeasonNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of this episode in it's season.
|
||||
/// </summary>
|
||||
public int? EpisodeNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season.
|
||||
/// </summary>
|
||||
public int? AbsoluteNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of the video file for this episode. Any format supported by a <see cref="IFileSystem"/> is allowed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
@ -114,17 +114,17 @@ namespace Kyoo.Abstractions.Models
|
||||
[SerializeAs("{HOST}/api/episodes/{Slug}/thumbnail")]
|
||||
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
|
||||
public string Thumb => Images?.GetValueOrDefault(Models.Images.Thumbnail);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The title of this episode.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The overview of this episode.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The release date of this episode. It can be null if unknown.
|
||||
/// </summary>
|
||||
@ -137,7 +137,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The list of tracks this episode has. This lists video, audio and subtitles available.
|
||||
/// </summary>
|
||||
[EditableRelation] [LoadableRelation] public ICollection<Track> Tracks { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the slug of an episode.
|
||||
@ -157,8 +157,8 @@ namespace Kyoo.Abstractions.Models
|
||||
/// </param>
|
||||
/// <returns>The slug corresponding to the given arguments</returns>
|
||||
/// <exception cref="ArgumentNullException">The given show slug was null.</exception>
|
||||
public static string GetSlug([NotNull] string showSlug,
|
||||
int? seasonNumber,
|
||||
public static string GetSlug([NotNull] string showSlug,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? absoluteNumber = null)
|
||||
{
|
||||
|
@ -11,15 +11,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this genre.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows that have this genre.
|
||||
/// </summary>
|
||||
@ -28,8 +28,8 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// Create a new, empty <see cref="Genre"/>.
|
||||
/// </summary>
|
||||
public Genre() {}
|
||||
|
||||
public Genre() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Genre"/> and specify it's <see cref="Name"/>.
|
||||
/// The <see cref="Slug"/> is automatically calculated from it's name.
|
||||
|
@ -14,7 +14,8 @@ namespace Kyoo.Abstractions.Models
|
||||
/// <summary>
|
||||
/// The link to metadata providers that this show has. See <see cref="MetadataID"/> for more information.
|
||||
/// </summary>
|
||||
[EditableRelation] [LoadableRelation]
|
||||
[EditableRelation]
|
||||
[LoadableRelation]
|
||||
public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// this field is automatically assigned by the <see cref="IRepository{T}"/>.
|
||||
/// </remarks>
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A human-readable identifier that can be used instead of an ID.
|
||||
/// A slug must be unique for a type of resource but it can be changed.
|
||||
@ -24,6 +24,6 @@ namespace Kyoo.Abstractions.Models
|
||||
/// There is no setter for a slug since it can be computed from other fields.
|
||||
/// For example, a season slug is {ShowSlug}-s{SeasonNumber}.
|
||||
/// </remarks>
|
||||
public string Slug { get; }
|
||||
public string Slug { get; }
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// An arbitrary index should not be used, instead use indexes from <see cref="Models.Images"/>
|
||||
/// </remarks>
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
|
||||
// TODO remove Posters properties add them via the json serializer for every IThumbnails
|
||||
}
|
||||
|
||||
|
@ -10,15 +10,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this library.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of paths that this library is responsible for. This is mainly used by the Scan task.
|
||||
/// </summary>
|
||||
@ -33,7 +33,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The list of shows in this library.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Show> Shows { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections in this library.
|
||||
/// </summary>
|
||||
|
@ -11,15 +11,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this person.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
@ -31,10 +31,10 @@ namespace Kyoo.Abstractions.Models
|
||||
[SerializeAs("{HOST}/api/people/{Slug}/poster")]
|
||||
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
|
||||
public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of roles this person has played in. See <see cref="PeopleRole"/> for more information.
|
||||
/// </summary>
|
||||
|
@ -14,15 +14,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this provider.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<int, string> Images { get; set; }
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using JetBrains.Annotations;
|
||||
@ -13,7 +13,7 @@ namespace Kyoo.Abstractions.Models
|
||||
public class Season : IResource, IMetadata, IThumbnails
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
public int ID { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed] public string Slug
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Abstractions.Models
|
||||
[UsedImplicitly] [NotNull] private set
|
||||
{
|
||||
Match match = Regex.Match(value ?? "", @"(?<show>.+)-s(?<season>\d+)");
|
||||
|
||||
|
||||
if (!match.Success)
|
||||
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
|
||||
ShowSlug = match.Groups["show"].Value;
|
||||
@ -39,7 +39,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The slug of the Show that contain this episode. If this is not set, this season is ill-formed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string ShowSlug { private get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this season.
|
||||
/// </summary>
|
||||
@ -59,17 +59,17 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The title of this season.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A quick overview of this season.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The starting air date of this season.
|
||||
/// </summary>
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ending date of this season.
|
||||
/// </summary>
|
||||
@ -86,7 +86,7 @@ namespace Kyoo.Abstractions.Models
|
||||
[SerializeAs("{HOST}/api/seasons/{Slug}/thumb")]
|
||||
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
|
||||
public string Poster => Images?.GetValueOrDefault(Models.Images.Poster);
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
|
@ -12,31 +12,31 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The title of this show.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of alternative titles of this show.
|
||||
/// </summary>
|
||||
[EditableRelation] public string[] Aliases { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of the root directory of this show.
|
||||
/// This can be any kind of path supported by <see cref="IFileSystem"/>
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this show.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished?
|
||||
/// </summary>
|
||||
@ -48,12 +48,12 @@ namespace Kyoo.Abstractions.Models
|
||||
/// TODO for now, this is set to a youtube url. It should be cached and converted to a local file.
|
||||
[Obsolete("Use Images instead of this, this is only kept for the API response.")]
|
||||
public string TrailerUrl => Images?.GetValueOrDefault(Models.Images.Trailer);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The date this show started airing. It can be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateTime? StartAir { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The date this show finished airing.
|
||||
/// It must be after the <see cref="StartAir"/> but can be the same (example: for movies).
|
||||
@ -108,39 +108,39 @@ namespace Kyoo.Abstractions.Models
|
||||
/// This must be explicitly loaded via a call to <see cref="ILibraryManager.Load"/>.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(StudioID))] [EditableRelation] public Studio Studio { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
[LoadableRelation] [EditableRelation] public ICollection<Genre> Genres { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of people that made this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] [EditableRelation] public ICollection<PeopleRole> People { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The different seasons in this show. If this is a movie, this list is always null or empty.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Season> Seasons { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes in this show.
|
||||
/// If this is a movie, there will be a unique episode (with the seasonNumber and episodeNumber set to null).
|
||||
/// Having an episode is necessary to store metadata and tracks.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Episode> Episodes { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of libraries that contains this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Library> Libraries { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections that contains this show.
|
||||
/// </summary>
|
||||
[LoadableRelation] public ICollection<Collection> Collections { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnMerge(object merged)
|
||||
{
|
||||
|
@ -11,15 +11,15 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The name of this studio.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows that are made by this studio.
|
||||
/// </summary>
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Abstractions.Models
|
||||
|
||||
/// <inheritdoc />
|
||||
[EditableRelation] [LoadableRelation] public ICollection<MetadataID> ExternalIDs { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty, <see cref="Studio"/>.
|
||||
/// </summary>
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed] public string Slug
|
||||
{
|
||||
@ -42,12 +42,14 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
Match match = Regex.Match(value,
|
||||
Match match = Regex.Match(value,
|
||||
@"(?<ep>[^\.]+)\.(?<lang>\w{0,3})(-(?<index>\d+))?(\.(?<forced>forced))?\.(?<type>\w+)(\.\w*)?");
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new ArgumentException("Invalid track slug. " +
|
||||
"Format: {episodeSlug}.{language}[-{index}][.forced].{type}[.{extension}]");
|
||||
}
|
||||
|
||||
EpisodeSlug = match.Groups["ep"].Value;
|
||||
Language = match.Groups["lang"].Value;
|
||||
@ -58,53 +60,53 @@ namespace Kyoo.Abstractions.Models
|
||||
Type = Enum.Parse<StreamType>(match.Groups["type"].Value, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the episode that contain this track. If this is not set, this track is ill-formed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string EpisodeSlug { private get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The title of the stream.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The language of this stream (as a ISO-639-2 language code)
|
||||
/// </summary>
|
||||
public string Language { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The codec of this stream.
|
||||
/// </summary>
|
||||
public string Codec { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this stream the default one of it's type?
|
||||
/// </summary>
|
||||
public bool IsDefault { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this stream tagged as forced?
|
||||
/// </summary>
|
||||
public bool IsForced { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this track extern to the episode's file?
|
||||
/// </summary>
|
||||
public bool IsExternal { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of this track.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of this stream.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public StreamType Type { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the episode that uses this track.
|
||||
/// </summary>
|
||||
@ -137,7 +139,7 @@ namespace Kyoo.Abstractions.Models
|
||||
name += " Forced";
|
||||
if (IsExternal)
|
||||
name += " (External)";
|
||||
if (Title is {Length: > 1})
|
||||
if (Title is { Length: > 1 })
|
||||
name += " - " + Title;
|
||||
return name;
|
||||
}
|
||||
@ -164,8 +166,8 @@ namespace Kyoo.Abstractions.Models
|
||||
public static string BuildSlug(string baseSlug,
|
||||
StreamType type)
|
||||
{
|
||||
return baseSlug.EndsWith($".{type}", StringComparison.InvariantCultureIgnoreCase)
|
||||
? baseSlug
|
||||
return baseSlug.EndsWith($".{type}", StringComparison.InvariantCultureIgnoreCase)
|
||||
? baseSlug
|
||||
: $"{baseSlug}.{type.ToString().ToLowerInvariant()}";
|
||||
}
|
||||
}
|
||||
|
@ -9,30 +9,30 @@ namespace Kyoo.Abstractions.Models
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int ID { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Slug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A username displayed to the user.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user email address.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user password (hashed, it can't be read like that). The hashing format is implementation defined.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of permissions of the user. The format of this is implementation dependent.
|
||||
/// </summary>
|
||||
public string[] Permissions { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Arbitrary extra data that can be used by specific authentication implementations.
|
||||
/// </summary>
|
||||
@ -45,13 +45,13 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The list of shows the user has finished.
|
||||
/// </summary>
|
||||
public ICollection<Show> Watched { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes the user is watching (stopped in progress or the next episode of the show)
|
||||
/// </summary>
|
||||
public ICollection<WatchedEpisode> CurrentlyWatching { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of episode currently watching by an user
|
||||
/// </summary>
|
||||
@ -61,17 +61,17 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The ID of the user that started watching this episode.
|
||||
/// </summary>
|
||||
public int UserID { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the episode started.
|
||||
/// </summary>
|
||||
public int EpisodeID { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Episode"/> started.
|
||||
/// </summary>
|
||||
public Episode Episode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (between 0 and 100).
|
||||
/// </summary>
|
||||
|
@ -11,32 +11,32 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The query of the search request.
|
||||
/// </summary>
|
||||
public string Query { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The collections that matched the search.
|
||||
/// </summary>
|
||||
public ICollection<Collection> Collections { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The shows that matched the search.
|
||||
/// </summary>
|
||||
public ICollection<Show> Shows { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The episodes that matched the search.
|
||||
/// </summary>
|
||||
public ICollection<Episode> Episodes { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The people that matched the search.
|
||||
/// </summary>
|
||||
public ICollection<People> People { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The genres that matched the search.
|
||||
/// </summary>
|
||||
public ICollection<Genre> Genres { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The studios that matched the search.
|
||||
/// </summary>
|
||||
|
@ -20,7 +20,7 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The ID of the episode associated with this item.
|
||||
/// </summary>
|
||||
public int EpisodeID { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The slug of this episode.
|
||||
/// </summary>
|
||||
@ -30,54 +30,54 @@ namespace Kyoo.Abstractions.Models
|
||||
/// The title of the show containing this episode.
|
||||
/// </summary>
|
||||
public string ShowTitle { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the show containing this episode
|
||||
/// </summary>
|
||||
public string ShowSlug { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The season in witch this episode is in.
|
||||
/// </summary>
|
||||
public int? SeasonNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of this episode is it's season.
|
||||
/// </summary>
|
||||
public int? EpisodeNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season.
|
||||
/// </summary>
|
||||
public int? AbsoluteNumber { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The title of this episode.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The release date of this episode. It can be null if unknown.
|
||||
/// </summary>
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of the video file for this episode. Any format supported by a <see cref="IFileSystem"/> is allowed.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The episode that come before this one if you follow usual watch orders.
|
||||
/// If this is the first episode or this is a movie, it will be null.
|
||||
/// </summary>
|
||||
public Episode PreviousEpisode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The episode that come after this one if you follow usual watch orders.
|
||||
/// If this is the last aired episode or this is a movie, it will be null.
|
||||
/// </summary>
|
||||
public Episode NextEpisode { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> if this is a movie, <c>false</c> otherwise.
|
||||
/// </summary>
|
||||
@ -89,14 +89,14 @@ namespace Kyoo.Abstractions.Models
|
||||
/// This can be disabled using the internal query flag.
|
||||
/// </summary>
|
||||
[SerializeAs("{HOST}/api/show/{ShowSlug}/poster")] public string Poster { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of this item's logo.
|
||||
/// By default, the http path for the logo is returned from the public API.
|
||||
/// This can be disabled using the internal query flag.
|
||||
/// </summary>
|
||||
[SerializeAs("{HOST}/api/show/{ShowSlug}/logo")] public string Logo { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of this item's backdrop.
|
||||
/// By default, the http path for the backdrop is returned from the public API.
|
||||
@ -109,27 +109,27 @@ namespace Kyoo.Abstractions.Models
|
||||
/// Common containers are mp4, mkv, avi and so on.
|
||||
/// </summary>
|
||||
public string Container { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The video track. See <see cref="Track"/> for more information.
|
||||
/// </summary>
|
||||
public Track Video { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of audio tracks. See <see cref="Track"/> for more information.
|
||||
/// </summary>
|
||||
public ICollection<Track> Audios { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of subtitles tracks. See <see cref="Track"/> for more information.
|
||||
/// </summary>
|
||||
public ICollection<Track> Subtitles { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of chapters. See <see cref="Chapter"/> for more information.
|
||||
/// </summary>
|
||||
public ICollection<Chapter> Chapters { get; set; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="WatchItem"/> from an <see cref="Episode"/>.
|
||||
@ -146,15 +146,15 @@ namespace Kyoo.Abstractions.Models
|
||||
|
||||
await library.Load(ep, x => x.Show);
|
||||
await library.Load(ep, x => x.Tracks);
|
||||
|
||||
|
||||
if (!ep.Show.IsMovie && ep.SeasonNumber != null && ep.EpisodeNumber != null)
|
||||
{
|
||||
if (ep.EpisodeNumber > 1)
|
||||
previous = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value, ep.EpisodeNumber.Value - 1);
|
||||
else if (ep.SeasonNumber > 1)
|
||||
{
|
||||
previous = (await library.GetAll(x => x.ShowID == ep.ShowID
|
||||
&& x.SeasonNumber == ep.SeasonNumber.Value - 1,
|
||||
previous = (await library.GetAll(x => x.ShowID == ep.ShowID
|
||||
&& x.SeasonNumber == ep.SeasonNumber.Value - 1,
|
||||
limit: 1,
|
||||
sort: new Sort<Episode>(x => x.EpisodeNumber, true))
|
||||
).FirstOrDefault();
|
||||
@ -167,12 +167,12 @@ namespace Kyoo.Abstractions.Models
|
||||
}
|
||||
else if (!ep.Show.IsMovie && ep.AbsoluteNumber != null)
|
||||
{
|
||||
previous = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
||||
previous = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
||||
&& x.AbsoluteNumber == ep.EpisodeNumber + 1);
|
||||
next = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
||||
next = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
||||
&& x.AbsoluteNumber == ep.AbsoluteNumber + 1);
|
||||
}
|
||||
|
||||
|
||||
return new WatchItem
|
||||
{
|
||||
EpisodeID = ep.ID,
|
||||
@ -188,7 +188,7 @@ namespace Kyoo.Abstractions.Models
|
||||
Container = PathIO.GetExtension(ep.Path)![1..],
|
||||
Video = ep.Tracks.FirstOrDefault(x => x.Type == StreamType.Video),
|
||||
Audios = ep.Tracks.Where(x => x.Type == StreamType.Audio).ToArray(),
|
||||
Subtitles = ep.Tracks.Where(x => x.Type == StreamType.Subtitle).ToArray(),
|
||||
Subtitles = ep.Tracks.Where(x => x.Type == StreamType.Subtitle).ToArray(),
|
||||
PreviousEpisode = previous,
|
||||
NextEpisode = next,
|
||||
Chapters = await GetChapters(ep.Path)
|
||||
@ -200,7 +200,7 @@ namespace Kyoo.Abstractions.Models
|
||||
private static async Task<ICollection<Chapter>> GetChapters(string episodePath)
|
||||
{
|
||||
string path = PathIO.Combine(
|
||||
PathIO.GetDirectoryName(episodePath)!,
|
||||
PathIO.GetDirectoryName(episodePath)!,
|
||||
"Chapters",
|
||||
PathIO.GetFileNameWithoutExtension(episodePath) + ".txt"
|
||||
);
|
||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Abstractions
|
||||
/// <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>
|
||||
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||
RegisterProvider<T>(this ContainerBuilder builder)
|
||||
where T : class, IMetadataProvider
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace Kyoo.Abstractions
|
||||
/// If your repository implements a special interface, please use <see cref="RegisterRepository{T,T2}"/>
|
||||
/// </remarks>
|
||||
/// <returns>The initial container.</returns>
|
||||
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||
public static IRegistrationBuilder<T, ConcreteReflectionActivatorData, SingleRegistrationStyle>
|
||||
RegisterRepository<T>(this ContainerBuilder builder)
|
||||
where T : IBaseRepository
|
||||
{
|
||||
|
@ -42,7 +42,7 @@ namespace Kyoo.Utils
|
||||
}
|
||||
return Generator(self, mapper);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A map where the mapping function is asynchronous.
|
||||
/// Note: <see cref="SelectAsync{T,T2}"/> might interest you.
|
||||
@ -54,7 +54,7 @@ namespace Kyoo.Utils
|
||||
/// <returns>The list mapped as an AsyncEnumerable</returns>
|
||||
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
|
||||
[LinqTunnel]
|
||||
public static IAsyncEnumerable<T2> MapAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
public static IAsyncEnumerable<T2> MapAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
[NotNull] Func<T, int, Task<T2>> mapper)
|
||||
{
|
||||
if (self == null)
|
||||
@ -76,7 +76,7 @@ namespace Kyoo.Utils
|
||||
|
||||
return Generator(self, mapper);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An asynchronous version of Select.
|
||||
/// </summary>
|
||||
@ -87,7 +87,7 @@ namespace Kyoo.Utils
|
||||
/// <returns>The list mapped as an AsyncEnumerable</returns>
|
||||
/// <exception cref="ArgumentNullException">The list or the mapper can't be null</exception>
|
||||
[LinqTunnel]
|
||||
public static IAsyncEnumerable<T2> SelectAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
public static IAsyncEnumerable<T2> SelectAsync<T, T2>([NotNull] this IEnumerable<T> self,
|
||||
[NotNull] Func<T, Task<T2>> mapper)
|
||||
{
|
||||
if (self == null)
|
||||
@ -159,7 +159,7 @@ namespace Kyoo.Utils
|
||||
do
|
||||
{
|
||||
yield return enumerator.Current;
|
||||
}
|
||||
}
|
||||
while (enumerator.MoveNext());
|
||||
}
|
||||
|
||||
@ -179,7 +179,7 @@ namespace Kyoo.Utils
|
||||
foreach (T i in self)
|
||||
action(i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A foreach used as a function with a little specificity: the list can be null.
|
||||
/// </summary>
|
||||
@ -192,7 +192,7 @@ namespace Kyoo.Utils
|
||||
foreach (object i in self)
|
||||
action(i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A foreach used as a function with a little specificity: the list can be null.
|
||||
/// </summary>
|
||||
@ -205,7 +205,7 @@ namespace Kyoo.Utils
|
||||
foreach (object i in self)
|
||||
await action(i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A foreach used as a function with a little specificity: the list can be null.
|
||||
/// </summary>
|
||||
@ -219,7 +219,7 @@ namespace Kyoo.Utils
|
||||
foreach (T i in self)
|
||||
await action(i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A foreach used as a function with a little specificity: the list can be null.
|
||||
/// </summary>
|
||||
@ -233,7 +233,7 @@ namespace Kyoo.Utils
|
||||
await foreach (T i in self)
|
||||
action(i);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Split a list in a small chunk of data.
|
||||
/// </summary>
|
||||
@ -247,7 +247,7 @@ namespace Kyoo.Utils
|
||||
for (int i = 0; i < list.Count; i += countPerList)
|
||||
yield return list.GetRange(i, Math.Min(list.Count - i, countPerList));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Split a list in a small chunk of data.
|
||||
/// </summary>
|
||||
@ -260,7 +260,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
T[] ret = new T[countPerList];
|
||||
int i = 0;
|
||||
|
||||
|
||||
using IEnumerator<T> enumerator = list.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace Kyoo.Utils
|
||||
/// <returns>The two list merged as an array</returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static T[] MergeLists<T>([CanBeNull] IEnumerable<T> first,
|
||||
[CanBeNull] IEnumerable<T> second,
|
||||
[CanBeNull] IEnumerable<T> second,
|
||||
[CanBeNull] Func<T, T, bool> isEqual = null)
|
||||
{
|
||||
if (first == null)
|
||||
@ -82,7 +82,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
bool success = first.TryAdd(key, value);
|
||||
hasChanged |= success;
|
||||
|
||||
|
||||
if (success || first[key]?.Equals(default) == false || value?.Equals(default) != false)
|
||||
continue;
|
||||
first[key] = value;
|
||||
@ -150,9 +150,9 @@ namespace Kyoo.Utils
|
||||
{
|
||||
Type type = typeof(T);
|
||||
IEnumerable<PropertyInfo> properties = type.GetProperties()
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
|
||||
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
object value = property.GetValue(second);
|
||||
@ -163,7 +163,7 @@ namespace Kyoo.Utils
|
||||
merge.OnMerge(second);
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set every non-default values of seconds to the corresponding property of second.
|
||||
/// Dictionaries are handled like anonymous objects with a property per key/pair value
|
||||
@ -190,15 +190,15 @@ namespace Kyoo.Utils
|
||||
/// <typeparam name="T">Fields of T will be completed</typeparam>
|
||||
/// <returns><see cref="first"/></returns>
|
||||
/// <exception cref="ArgumentNullException">If first is null</exception>
|
||||
public static T Complete<T>([NotNull] T first,
|
||||
[CanBeNull] T second,
|
||||
public static T Complete<T>([NotNull] T first,
|
||||
[CanBeNull] T second,
|
||||
[InstantHandle] Func<PropertyInfo, bool> where = null)
|
||||
{
|
||||
if (first == null)
|
||||
throw new ArgumentNullException(nameof(first));
|
||||
if (second == null)
|
||||
return first;
|
||||
|
||||
|
||||
Type type = typeof(T);
|
||||
IEnumerable<PropertyInfo> properties = type.GetProperties()
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
@ -206,7 +206,7 @@ namespace Kyoo.Utils
|
||||
|
||||
if (where != null)
|
||||
properties = properties.Where(where);
|
||||
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
object value = property.GetValue(second);
|
||||
@ -261,7 +261,7 @@ namespace Kyoo.Utils
|
||||
/// <typeparam name="T">Fields of T will be merged</typeparam>
|
||||
/// <returns><see cref="first"/></returns>
|
||||
[ContractAnnotation("first:notnull => notnull; second:notnull => notnull", true)]
|
||||
public static T Merge<T>([CanBeNull] T first,
|
||||
public static T Merge<T>([CanBeNull] T first,
|
||||
[CanBeNull] T second,
|
||||
[InstantHandle] Func<PropertyInfo, bool> where = null)
|
||||
{
|
||||
@ -269,21 +269,21 @@ namespace Kyoo.Utils
|
||||
return second;
|
||||
if (second == null)
|
||||
return first;
|
||||
|
||||
|
||||
Type type = typeof(T);
|
||||
IEnumerable<PropertyInfo> properties = type.GetProperties()
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
.Where(x => x.CanRead && x.CanWrite
|
||||
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
|
||||
|
||||
|
||||
if (where != null)
|
||||
properties = properties.Where(where);
|
||||
|
||||
|
||||
foreach (PropertyInfo property in properties)
|
||||
{
|
||||
object oldValue = property.GetValue(first);
|
||||
object newValue = property.GetValue(second);
|
||||
object defaultValue = property.PropertyType.GetClrDefault();
|
||||
|
||||
|
||||
if (oldValue?.Equals(defaultValue) != false)
|
||||
property.SetValue(first, newValue);
|
||||
else if (Utility.IsOfGenericType(property.PropertyType, typeof(IDictionary<,>)))
|
||||
@ -310,7 +310,7 @@ namespace Kyoo.Utils
|
||||
.GenericTypeArguments
|
||||
.First();
|
||||
Func<IResource, IResource, bool> equalityComparer = enumerableType.IsAssignableTo(typeof(IResource))
|
||||
? (x, y) => x.Slug == y.Slug
|
||||
? (x, y) => x.Slug == y.Slug
|
||||
: null;
|
||||
property.SetValue(first, Utility.RunGenericMethod<object>(
|
||||
typeof(Merger),
|
||||
@ -344,4 +344,4 @@ namespace Kyoo.Utils
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -37,7 +37,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -47,7 +47,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -57,7 +57,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -67,7 +67,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
@ -77,7 +77,7 @@ namespace Kyoo.Utils
|
||||
{
|
||||
return action.Method;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a MethodInfo from a direct method.
|
||||
/// </summary>
|
||||
|
@ -28,7 +28,7 @@ namespace Kyoo.Utils
|
||||
return ex.Body is MemberExpression ||
|
||||
ex.Body.NodeType == ExpressionType.Convert && ((UnaryExpression)ex.Body).Operand is MemberExpression;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of a property. Useful for selectors as members ex: Load(x => x.Shows)
|
||||
/// </summary>
|
||||
@ -66,7 +66,7 @@ namespace Kyoo.Utils
|
||||
_ => throw new ArgumentException($"Can't get value of a non property/field (member: {member}).")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Slugify a string (Replace spaces by -, Uniformize accents é -> e)
|
||||
/// </summary>
|
||||
@ -78,7 +78,7 @@ namespace Kyoo.Utils
|
||||
return null;
|
||||
|
||||
str = str.ToLowerInvariant();
|
||||
|
||||
|
||||
string normalizedString = str.Normalize(NormalizationForm.FormD);
|
||||
StringBuilder stringBuilder = new();
|
||||
foreach (char c in normalizedString)
|
||||
@ -104,7 +104,7 @@ namespace Kyoo.Utils
|
||||
public static object GetClrDefault(this Type type)
|
||||
{
|
||||
return type.IsValueType
|
||||
? Activator.CreateInstance(type)
|
||||
? Activator.CreateInstance(type)
|
||||
: null;
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ namespace Kyoo.Utils
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
return IsOfGenericType(obj.GetType(), genericType);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Check if <see cref="type"/> inherit from a generic type <see cref="genericType"/>.
|
||||
/// </summary>
|
||||
@ -201,15 +201,15 @@ namespace Kyoo.Utils
|
||||
/// The list of generic parameters.
|
||||
/// </param>
|
||||
/// <param name="args">
|
||||
/// The list of parameters.
|
||||
/// The list of parameters.
|
||||
/// </param>
|
||||
/// <exception cref="ArgumentException">No method match the given constraints.</exception>
|
||||
/// <returns>The method handle of the matching method.</returns>
|
||||
[PublicAPI]
|
||||
[NotNull]
|
||||
public static MethodInfo GetMethod([NotNull] Type type,
|
||||
public static MethodInfo GetMethod([NotNull] Type type,
|
||||
BindingFlags flag,
|
||||
string name,
|
||||
string name,
|
||||
[NotNull] Type[] generics,
|
||||
[NotNull] object[] args)
|
||||
{
|
||||
@ -219,7 +219,7 @@ namespace Kyoo.Utils
|
||||
throw new ArgumentNullException(nameof(generics));
|
||||
if (args == null)
|
||||
throw new ArgumentNullException(nameof(args));
|
||||
|
||||
|
||||
MethodInfo[] methods = type.GetMethods(flag | BindingFlags.Public)
|
||||
.Where(x => x.Name == name)
|
||||
.Where(x => x.GetGenericArguments().Length == generics.Length)
|
||||
@ -234,7 +234,7 @@ namespace Kyoo.Utils
|
||||
// return x.GetGenericArguments().All(y => y.IsAssignableFrom(generics[i++]));
|
||||
// })
|
||||
// .IfEmpty(() => throw new NullReferenceException($"No method {name} match the generics specified."))
|
||||
|
||||
|
||||
// TODO this won't work for Type<T> because T is specified in arguments but not in the parameters type.
|
||||
// .Where(x =>
|
||||
// {
|
||||
@ -249,7 +249,7 @@ namespace Kyoo.Utils
|
||||
return methods[0];
|
||||
throw new ArgumentException($"Multiple methods named {name} match the generics and parameters constraints.");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Run a generic static method for a runtime <see cref="Type"/>.
|
||||
/// </summary>
|
||||
@ -276,14 +276,14 @@ namespace Kyoo.Utils
|
||||
/// <seealso cref="RunGenericMethod{T}(object,string,System.Type,object[])"/>
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type[],object[])"/>
|
||||
public static T RunGenericMethod<T>(
|
||||
[NotNull] Type owner,
|
||||
[NotNull] Type owner,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type type,
|
||||
params object[] args)
|
||||
{
|
||||
return RunGenericMethod<T>(owner, methodName, new[] {type}, args);
|
||||
return RunGenericMethod<T>(owner, methodName, new[] { type }, args);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Run a generic static method for a multiple runtime <see cref="Type"/>.
|
||||
/// If your generic method only needs one type, see
|
||||
@ -313,7 +313,7 @@ namespace Kyoo.Utils
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type,object[])"/>
|
||||
[PublicAPI]
|
||||
public static T RunGenericMethod<T>(
|
||||
[NotNull] Type owner,
|
||||
[NotNull] Type owner,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type[] types,
|
||||
params object[] args)
|
||||
@ -361,7 +361,7 @@ namespace Kyoo.Utils
|
||||
[NotNull] Type type,
|
||||
params object[] args)
|
||||
{
|
||||
return RunGenericMethod<T>(instance, methodName, new[] {type}, args);
|
||||
return RunGenericMethod<T>(instance, methodName, new[] { type }, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -392,7 +392,7 @@ namespace Kyoo.Utils
|
||||
/// <seealso cref="RunGenericMethod{T}(object,string,System.Type[],object[])"/>
|
||||
/// <seealso cref="RunGenericMethod{T}(System.Type,string,System.Type,object[])"/>
|
||||
public static T RunGenericMethod<T>(
|
||||
[NotNull] object instance,
|
||||
[NotNull] object instance,
|
||||
[NotNull] string methodName,
|
||||
[NotNull] Type[] types,
|
||||
params object[] args)
|
||||
@ -436,4 +436,4 @@ namespace Kyoo.Utils
|
||||
return $"{type.Name[..type.Name.IndexOf('`')]}<{generics}>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -32,10 +33,10 @@ namespace Kyoo.Authentication
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Slug => "auth";
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Authentication";
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "Enable OpenID authentication for Kyoo.";
|
||||
|
||||
@ -70,8 +71,10 @@ namespace Kyoo.Authentication
|
||||
/// <param name="configuration">The configuration to use</param>
|
||||
/// <param name="logger">The logger used to allow IdentityServer to log things</param>
|
||||
/// <param name="environment">The environment information to check if the app runs in debug mode</param>
|
||||
[SuppressMessage("ReSharper", "ContextualLoggerProblem",
|
||||
Justification = "The logger is used for a dependency that is not created via the container.")]
|
||||
public AuthenticationModule(IConfiguration configuration,
|
||||
ILogger<DefaultCorsPolicyService> logger,
|
||||
ILogger<DefaultCorsPolicyService> logger,
|
||||
IWebHostEnvironment environment)
|
||||
{
|
||||
_configuration = configuration;
|
||||
@ -100,16 +103,16 @@ namespace Kyoo.Authentication
|
||||
IdentityModelEventSource.ShowPII = true;
|
||||
|
||||
services.AddControllers();
|
||||
|
||||
|
||||
// TODO handle direct-videos with bearers (probably add a cookie and a app.Use to translate that for videos)
|
||||
|
||||
|
||||
// TODO Check if tokens should be stored.
|
||||
|
||||
List<Client> clients = new();
|
||||
_configuration.GetSection("authentication:clients").Bind(clients);
|
||||
CertificateOption certificateOptions = new();
|
||||
_configuration.GetSection(CertificateOption.Path).Bind(certificateOptions);
|
||||
|
||||
|
||||
clients.AddRange(IdentityContext.GetClients());
|
||||
foreach (Client client in clients)
|
||||
{
|
||||
@ -131,7 +134,7 @@ namespace Kyoo.Authentication
|
||||
.AddInMemoryClients(clients)
|
||||
.AddProfileService<AccountApi>()
|
||||
.AddSigninKeys(certificateOptions);
|
||||
|
||||
|
||||
services.AddAuthentication()
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
@ -181,4 +184,4 @@ namespace Kyoo.Authentication
|
||||
SA.New<IApplicationBuilder>(app => app.UseAuthorization(), SA.Authorization)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ namespace Kyoo.Authentication
|
||||
/// <param name="builder">The identity server that will be modified.</param>
|
||||
/// <param name="options">The certificate options</param>
|
||||
/// <returns></returns>
|
||||
public static IIdentityServerBuilder AddSigninKeys(this IIdentityServerBuilder builder,
|
||||
public static IIdentityServerBuilder AddSigninKeys(this IIdentityServerBuilder builder,
|
||||
CertificateOption options)
|
||||
{
|
||||
X509Certificate2 certificate = GetCertificate(options);
|
||||
builder.AddSigningCredential(certificate);
|
||||
|
||||
|
||||
if (certificate.NotAfter.AddDays(-7) <= DateTime.UtcNow)
|
||||
{
|
||||
Console.WriteLine("Signin certificate will expire soon, renewing it.");
|
||||
@ -54,8 +54,8 @@ namespace Kyoo.Authentication
|
||||
/// <returns>A valid certificate</returns>
|
||||
private static X509Certificate2 GetCertificate(CertificateOption options)
|
||||
{
|
||||
return File.Exists(options.File)
|
||||
? GetExistingCredential(options.File, options.Password)
|
||||
return File.Exists(options.File)
|
||||
? GetExistingCredential(options.File, options.Password)
|
||||
: GenerateCertificate(options.File, options.Password);
|
||||
}
|
||||
|
||||
@ -83,19 +83,19 @@ namespace Kyoo.Authentication
|
||||
private static X509Certificate2 GenerateCertificate(string file, string password)
|
||||
{
|
||||
SecureRandom random = new();
|
||||
|
||||
|
||||
X509V3CertificateGenerator certificateGenerator = new();
|
||||
certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One,
|
||||
certificateGenerator.SetSerialNumber(BigIntegers.CreateRandomInRange(BigInteger.One,
|
||||
BigInteger.ValueOf(long.MaxValue), random));
|
||||
certificateGenerator.SetIssuerDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
|
||||
certificateGenerator.SetSubjectDN(new X509Name($"C=NL, O=SDG, CN=Kyoo"));
|
||||
certificateGenerator.SetNotBefore(DateTime.UtcNow.Date);
|
||||
certificateGenerator.SetNotAfter(DateTime.UtcNow.Date.AddMonths(3));
|
||||
|
||||
|
||||
KeyGenerationParameters keyGenerationParameters = new(random, 2048);
|
||||
RsaKeyPairGenerator keyPairGenerator = new();
|
||||
keyPairGenerator.Init(keyGenerationParameters);
|
||||
|
||||
|
||||
AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
|
||||
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
|
||||
|
||||
@ -104,7 +104,7 @@ namespace Kyoo.Authentication
|
||||
X509Certificate bouncyCert = certificateGenerator.Generate(signatureFactory);
|
||||
|
||||
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
|
||||
store.SetKeyEntry("Kyoo_key", new AsymmetricKeyEntry(subjectKeyPair.Private), new []
|
||||
store.SetKeyEntry("Kyoo_key", new AsymmetricKeyEntry(subjectKeyPair.Private), new[]
|
||||
{
|
||||
new X509CertificateEntry(bouncyCert)
|
||||
});
|
||||
|
@ -15,7 +15,7 @@ namespace Kyoo.Authentication
|
||||
{
|
||||
/// <summary>
|
||||
/// A permission validator to validate permission with user Permission array
|
||||
/// or the default array from the configurations if the user is not logged.
|
||||
/// or the default array from the configurations if the user is not logged.
|
||||
/// </summary>
|
||||
public class PermissionValidatorFactory : IPermissionValidator
|
||||
{
|
||||
@ -38,7 +38,7 @@ namespace Kyoo.Authentication
|
||||
{
|
||||
return new PermissionValidator(attribute.Type, attribute.Kind, attribute.Group, _options);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata Create(PartialPermissionAttribute attribute)
|
||||
{
|
||||
@ -149,4 +149,4 @@ namespace Kyoo.Authentication
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Authentication
|
||||
return new(user.ID.ToString())
|
||||
{
|
||||
DisplayName = user.Username,
|
||||
AdditionalClaims = new[] {new Claim("permissions", string.Join(',', user.Permissions))}
|
||||
AdditionalClaims = new[] { new Claim("permissions", string.Join(',', user.Permissions)) }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -13,13 +13,13 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
/// </summary>
|
||||
[EmailAddress(ErrorMessage = "The email is invalid.")]
|
||||
public string Email { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The new username of the user.
|
||||
/// </summary>
|
||||
[MinLength(4, ErrorMessage = "The username must have at least 4 characters")]
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The picture icon.
|
||||
/// </summary>
|
||||
|
@ -9,17 +9,17 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
/// The user's username.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user's password.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should the user stay logged in? If true a cookie will be put.
|
||||
/// </summary>
|
||||
public bool StayLoggedIn { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The return url of the login flow.
|
||||
/// </summary>
|
||||
|
@ -9,7 +9,7 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
/// The One Time Access Code
|
||||
/// </summary>
|
||||
public string Otac { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Should the user stay logged
|
||||
/// </summary>
|
||||
|
@ -15,13 +15,13 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
/// </summary>
|
||||
[EmailAddress(ErrorMessage = "The email must be a valid email address")]
|
||||
public string Email { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user's username.
|
||||
/// </summary>
|
||||
[MinLength(4, ErrorMessage = "The username must have at least {1} characters")]
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user's password.
|
||||
/// </summary>
|
||||
@ -44,5 +44,5 @@ namespace Kyoo.Authentication.Models.DTO
|
||||
ExtraData = new Dictionary<string, string>()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,11 +42,11 @@ namespace Kyoo.Authentication
|
||||
AllowedGrantTypes = GrantTypes.Code,
|
||||
RequirePkce = true,
|
||||
RequireClientSecret = false,
|
||||
|
||||
|
||||
AllowAccessTokensViaBrowser = true,
|
||||
AllowOfflineAccess = true,
|
||||
RequireConsent = false,
|
||||
|
||||
|
||||
AllowedScopes = { "openid", "profile", "kyoo.read", "kyoo.write", "kyoo.play", "kyoo.admin" },
|
||||
RedirectUris = { "/", "/silent.html" },
|
||||
PostLogoutRedirectUris = { "/logout" }
|
||||
@ -84,7 +84,7 @@ namespace Kyoo.Authentication
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of APIs (this is used to create Audiences)
|
||||
/// </summary>
|
||||
|
@ -14,12 +14,12 @@ namespace Kyoo.Authentication.Models
|
||||
/// The options for certificates
|
||||
/// </summary>
|
||||
public CertificateOption Certificate { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Options for permissions
|
||||
/// </summary>
|
||||
public PermissionOption Permissions { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Root path of user's profile pictures.
|
||||
/// </summary>
|
||||
|
@ -9,7 +9,7 @@ namespace Kyoo.Authentication.Models
|
||||
/// The path to get this option from the root configuration.
|
||||
/// </summary>
|
||||
public const string Path = "authentication:certificate";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of the certificate file.
|
||||
/// </summary>
|
||||
|
@ -14,7 +14,7 @@ namespace Kyoo.Authentication.Models
|
||||
/// The default permissions that will be given to a non-connected user.
|
||||
/// </summary>
|
||||
public string[] Default { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Permissions applied to a new user.
|
||||
/// </summary>
|
||||
|
@ -57,8 +57,8 @@ namespace Kyoo.Authentication.Views
|
||||
_files = files;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Register a new user and return a OTAC to connect to it.
|
||||
/// </summary>
|
||||
@ -78,10 +78,10 @@ namespace Kyoo.Authentication.Views
|
||||
}
|
||||
catch (DuplicatedItemException)
|
||||
{
|
||||
return Conflict(new {Errors = new {Duplicate = new[] {"A user with this name already exists"}}});
|
||||
return Conflict(new { Errors = new { Duplicate = new[] { "A user with this name already exists" } } });
|
||||
}
|
||||
|
||||
return Ok(new {Otac = user.ExtraData["otac"]});
|
||||
return Ok(new { Otac = user.ExtraData["otac"] });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -99,7 +99,7 @@ namespace Kyoo.Authentication.Views
|
||||
ExpiresUtc = DateTimeOffset.UtcNow.AddMonths(1)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login the user.
|
||||
/// </summary>
|
||||
@ -117,7 +117,7 @@ namespace Kyoo.Authentication.Views
|
||||
await HttpContext.SignInAsync(user.ToIdentityUser(), StayLogged(login.StayLoggedIn));
|
||||
return Ok(new { RedirectUrl = login.ReturnURL, IsOk = true });
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use a OTAC to login a user.
|
||||
/// </summary>
|
||||
@ -127,22 +127,23 @@ namespace Kyoo.Authentication.Views
|
||||
{
|
||||
// TODO once hstore (Dictionary<string, string> accessor) are supported, use them.
|
||||
// We retrieve all users, this is inefficient.
|
||||
User user = (await _users.GetAll()).FirstOrDefault(x => x.ExtraData.GetValueOrDefault("otac") == otac.Otac);
|
||||
User user = (await _users.GetAll()).FirstOrDefault(x => x.ExtraData.GetValueOrDefault("otac") == otac.Otac);
|
||||
if (user == null)
|
||||
return Unauthorized();
|
||||
if (DateTime.ParseExact(user.ExtraData["otac-expire"], "s", CultureInfo.InvariantCulture) <=
|
||||
DateTime.UtcNow)
|
||||
DateTime.UtcNow)
|
||||
{
|
||||
return BadRequest(new
|
||||
{
|
||||
code = "ExpiredOTAC", description = "The OTAC has expired. Try to login with your password."
|
||||
code = "ExpiredOTAC",
|
||||
description = "The OTAC has expired. Try to login with your password."
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
await HttpContext.SignInAsync(user.ToIdentityUser(), StayLogged(otac.StayLoggedIn));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sign out an user
|
||||
/// </summary>
|
||||
@ -170,7 +171,7 @@ namespace Kyoo.Authentication.Views
|
||||
User user = await _users.GetOrDefault(int.Parse(context.Subject.GetSubjectId()));
|
||||
context.IsActive = user != null;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the user's profile picture.
|
||||
/// </summary>
|
||||
@ -185,7 +186,7 @@ namespace Kyoo.Authentication.Views
|
||||
string path = Path.Combine(_options.Value.ProfilePicturePath, user.ID.ToString());
|
||||
return _files.FileResult(path);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Update profile information (email, username, profile picture...)
|
||||
/// </summary>
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Core
|
||||
/// Should the application restart after a shutdown?
|
||||
/// </summary>
|
||||
private bool _shouldRestart;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The cancellation token source used to allow the app to be shutdown or restarted.
|
||||
/// </summary>
|
||||
@ -48,7 +48,7 @@ namespace Kyoo.Core
|
||||
/// </summary>
|
||||
private ILogger _logger;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Application"/> that will use the specified environment.
|
||||
/// </summary>
|
||||
@ -80,28 +80,28 @@ namespace Kyoo.Core
|
||||
public async Task Start(string[] args, Action<ContainerBuilder> configure)
|
||||
{
|
||||
_dataDir = _SetupDataDir(args);
|
||||
|
||||
|
||||
LoggerConfiguration config = new();
|
||||
_ConfigureLogging(config, null, null);
|
||||
Log.Logger = config.CreateBootstrapLogger();
|
||||
_logger = Log.Logger.ForContext<Application>();
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => Log.CloseAndFlush();
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, ex)
|
||||
AppDomain.CurrentDomain.UnhandledException += (_, ex)
|
||||
=> Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception");
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
IHost host = _CreateWebHostBuilder(args)
|
||||
.ConfigureContainer(configure)
|
||||
.Build();
|
||||
|
||||
|
||||
_tokenSource = new CancellationTokenSource();
|
||||
await _StartWithHost(host, _tokenSource.Token);
|
||||
}
|
||||
}
|
||||
while (_shouldRestart);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Shutdown()
|
||||
{
|
||||
@ -155,7 +155,7 @@ namespace Kyoo.Core
|
||||
.AddCommandLine(args)
|
||||
.Build();
|
||||
|
||||
string path = parsed.GetValue<string>("datadir")
|
||||
string path = parsed.GetValue<string>("datadir")
|
||||
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Kyoo");
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
@ -165,7 +165,7 @@ namespace Kyoo.Core
|
||||
if (!File.Exists(GetConfigFile()))
|
||||
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, GetConfigFile()),
|
||||
GetConfigFile());
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@ -217,7 +217,7 @@ namespace Kyoo.Core
|
||||
.UseStartup(host => PluginsStartup.FromWebHost(host, new LoggerFactory().AddSerilog()))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Register settings.json, environment variables and command lines arguments as configuration.
|
||||
/// </summary>
|
||||
|
@ -17,7 +17,7 @@ namespace Kyoo.Core.Controllers
|
||||
public class ConfigurationManager : IConfigurationManager
|
||||
{
|
||||
/// <summary>
|
||||
/// The configuration to retrieve and edit.
|
||||
/// The configuration to retrieve and edit.
|
||||
/// </summary>
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
@ -58,7 +58,7 @@ namespace Kyoo.Core.Controllers
|
||||
ConfigurationReference config = ConfigurationReference.CreateUntyped(path);
|
||||
_references.Add(config.Path, config.Type);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Register(string path, Type type)
|
||||
{
|
||||
@ -98,7 +98,7 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ArgumentException($"The configuration at {path} is not editable or readable.");
|
||||
throw new ItemNotFoundException($"No configuration exists for the name: {path}");
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public object GetValue(string path)
|
||||
{
|
||||
@ -124,7 +124,7 @@ namespace Kyoo.Core.Controllers
|
||||
$"a resource of type {type.Name}.");
|
||||
return (T)GetValue(path);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task EditValue(string path, object value)
|
||||
{
|
||||
@ -133,7 +133,7 @@ namespace Kyoo.Core.Controllers
|
||||
value = JObject.FromObject(value).ToObject(type);
|
||||
if (value == null)
|
||||
throw new ArgumentException("Invalid value format.");
|
||||
|
||||
|
||||
ExpandoObject config = _ToObject(_configuration);
|
||||
IDictionary<string, object> configDic = config;
|
||||
configDic[path] = value;
|
||||
@ -141,7 +141,7 @@ namespace Kyoo.Core.Controllers
|
||||
await using StreamWriter writer = new(_application.GetConfigFile());
|
||||
await writer.WriteAsync(obj.ToString());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Transform a configuration to a strongly typed object (the root configuration is an <see cref="ExpandoObject"/>
|
||||
/// but child elements are using strong types.
|
||||
@ -169,7 +169,7 @@ namespace Kyoo.Core.Controllers
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -192,4 +192,4 @@ namespace Kyoo.Core.Controllers
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,12 +31,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// (only if the option is set to metadata in show)
|
||||
/// </summary>
|
||||
private readonly ILibraryManager _libraryManager;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Options to check if the metadata should be kept in the show directory or in a kyoo's directory.
|
||||
/// </summary>
|
||||
private readonly IOptionsMonitor<BasicOptions> _options;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="FileSystemComposite"/> from a list of <see cref="IFileSystem"/> mapped to their
|
||||
/// metadata.
|
||||
@ -45,7 +45,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="libraryManager">The library manager used to load shows to retrieve their path.</param>
|
||||
/// <param name="options">The options to use.</param>
|
||||
public FileSystemComposite(ICollection<Meta<Func<IFileSystem>, FileSystemMetadataAttribute>> fileSystems,
|
||||
ILibraryManager libraryManager,
|
||||
ILibraryManager libraryManager,
|
||||
IOptionsMonitor<BasicOptions> options)
|
||||
{
|
||||
_fileSystems = fileSystems;
|
||||
@ -53,7 +53,7 @@ namespace Kyoo.Core.Controllers
|
||||
_options = options;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the file system that should be used for a given path.
|
||||
/// </summary>
|
||||
@ -159,7 +159,7 @@ namespace Kyoo.Core.Controllers
|
||||
return _GetFileSystemForPath(path, out string relativePath)
|
||||
.Exists(relativePath);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> GetExtraDirectory<T>(T resource)
|
||||
{
|
||||
@ -191,7 +191,7 @@ namespace Kyoo.Core.Controllers
|
||||
Season season => await GetExtraDirectory(season.Show),
|
||||
Episode episode => await GetExtraDirectory(episode.Show),
|
||||
Track track => await GetExtraDirectory(track.Episode),
|
||||
IResource res => Combine(_options.CurrentValue.MetadataPath,
|
||||
IResource res => Combine(_options.CurrentValue.MetadataPath,
|
||||
typeof(T).Name.ToLowerInvariant(), res.Slug),
|
||||
_ => Combine(_options.CurrentValue.MetadataPath, typeof(T).Name.ToLowerInvariant())
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A <see cref="IFileSystem"/> for http/https links.
|
||||
/// </summary>
|
||||
[FileSystemMetadata(new [] {"http", "https"})]
|
||||
[FileSystemMetadata(new[] { "http", "https" })]
|
||||
public class HttpFileSystem : IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
@ -30,8 +30,8 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
_clientFactory = factory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IActionResult FileResult(string path, bool rangeSupport = false, string type = null)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace Kyoo.Core.Controllers
|
||||
HttpClient client = _clientFactory.CreateClient();
|
||||
return client.GetStreamAsync(path);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Stream> GetReader(string path, AsyncRef<string> mime)
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A <see cref="IFileSystem"/> for the local filesystem (using System.IO).
|
||||
/// </summary>
|
||||
[FileSystemMetadata(new [] {"", "file"}, StripScheme = true)]
|
||||
[FileSystemMetadata(new[] { "", "file" }, StripScheme = true)]
|
||||
public class LocalFileSystem : IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
@ -51,7 +51,7 @@ namespace Kyoo.Core.Controllers
|
||||
return contentType;
|
||||
throw new NotImplementedException($"Can't get the content type of the file at: {path}");
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IActionResult FileResult(string path, bool rangeSupport = false, string type = null)
|
||||
{
|
||||
@ -72,7 +72,7 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
return Task.FromResult<Stream>(File.OpenRead(path));
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Stream> GetReader(string path, AsyncRef<string> mime)
|
||||
{
|
||||
@ -99,19 +99,19 @@ namespace Kyoo.Core.Controllers
|
||||
Directory.CreateDirectory(path);
|
||||
return Task.FromResult(path);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Combine(params string[] paths)
|
||||
{
|
||||
return Path.Combine(paths);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<string>> ListFiles(string path, SearchOption options = SearchOption.TopDirectoryOnly)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
string[] ret = Directory.Exists(path)
|
||||
string[] ret = Directory.Exists(path)
|
||||
? Directory.GetFiles(path, "*", options)
|
||||
: Array.Empty<string>();
|
||||
return Task.FromResult<ICollection<string>>(ret);
|
||||
@ -122,7 +122,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
return Task.FromResult(File.Exists(path) || Directory.Exists(path));
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<string> GetExtraDirectory<T>(T resource)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// The list of repositories
|
||||
/// </summary>
|
||||
private readonly IBaseRepository[] _repositories;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILibraryRepository LibraryRepository { get; }
|
||||
/// <inheritdoc />
|
||||
@ -41,8 +41,8 @@ namespace Kyoo.Core.Controllers
|
||||
public IProviderRepository ProviderRepository { get; }
|
||||
/// <inheritdoc />
|
||||
public IUserRepository UserRepository { get; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LibraryManager"/> instance with every repository available.
|
||||
/// </summary>
|
||||
@ -82,7 +82,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Get<T>(string slug)
|
||||
public Task<T> Get<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Get(slug);
|
||||
@ -120,19 +120,19 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T> GetOrDefault<T>(int id)
|
||||
public async Task<T> GetOrDefault<T>(int id)
|
||||
where T : class, IResource
|
||||
{
|
||||
return await GetRepository<T>().GetOrDefault(id);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T> GetOrDefault<T>(string slug)
|
||||
public async Task<T> GetOrDefault<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return await GetRepository<T>().GetOrDefault(slug);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where)
|
||||
where T : class, IResource
|
||||
@ -145,19 +145,19 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
||||
{
|
||||
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
@ -173,9 +173,9 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="inverse">A setter function to store the owner of a releated object loaded</param>
|
||||
/// <typeparam name="T1">The type of the owner object</typeparam>
|
||||
/// <typeparam name="T2">The type of the related object</typeparam>
|
||||
private static async Task SetRelation<T1, T2>(T1 obj,
|
||||
Task<ICollection<T2>> loader,
|
||||
Action<T1, ICollection<T2>> setter,
|
||||
private static async Task SetRelation<T1, T2>(T1 obj,
|
||||
Task<ICollection<T2>> loader,
|
||||
Action<T1, ICollection<T2>> setter,
|
||||
Action<T2, T1> inverse)
|
||||
{
|
||||
ICollection<T2> loaded = await loader;
|
||||
@ -230,61 +230,61 @@ namespace Kyoo.Core.Controllers
|
||||
(Library l, nameof(Library.Providers)) => ProviderRepository
|
||||
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
||||
.Then(x => l.Providers = x),
|
||||
|
||||
|
||||
(Library l, nameof(Library.Shows)) => ShowRepository
|
||||
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
||||
.Then(x => l.Shows = x),
|
||||
|
||||
.Then(x => l.Shows = x),
|
||||
|
||||
(Library l, nameof(Library.Collections)) => CollectionRepository
|
||||
.GetAll(x => x.Libraries.Any(y => y.ID == obj.ID))
|
||||
.Then(x => l.Collections = x),
|
||||
|
||||
|
||||
(Collection c, nameof(Collection.ExternalIDs)) => SetRelation(c,
|
||||
.Then(x => l.Collections = x),
|
||||
|
||||
|
||||
(Collection c, nameof(Collection.ExternalIDs)) => SetRelation(c,
|
||||
ProviderRepository.GetMetadataID<Collection>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
|
||||
(Collection c, nameof(Collection.Shows)) => ShowRepository
|
||||
.GetAll(x => x.Collections.Any(y => y.ID == obj.ID))
|
||||
.Then(x => c.Shows = x),
|
||||
|
||||
.Then(x => c.Shows = x),
|
||||
|
||||
(Collection c, nameof(Collection.Libraries)) => LibraryRepository
|
||||
.GetAll(x => x.Collections.Any(y => y.ID == obj.ID))
|
||||
.Then(x => c.Libraries = x),
|
||||
|
||||
|
||||
(Show s, nameof(Show.ExternalIDs)) => SetRelation(s,
|
||||
.Then(x => c.Libraries = x),
|
||||
|
||||
|
||||
(Show s, nameof(Show.ExternalIDs)) => SetRelation(s,
|
||||
ProviderRepository.GetMetadataID<Show>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
|
||||
(Show s, nameof(Show.Genres)) => GenreRepository
|
||||
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||
.Then(x => s.Genres = x),
|
||||
|
||||
|
||||
(Show s, nameof(Show.People)) => PeopleRepository
|
||||
.GetFromShow(obj.ID)
|
||||
.Then(x => s.People = x),
|
||||
|
||||
(Show s, nameof(Show.Seasons)) => SetRelation(s,
|
||||
|
||||
(Show s, nameof(Show.Seasons)) => SetRelation(s,
|
||||
SeasonRepository.GetAll(x => x.Show.ID == obj.ID),
|
||||
(x, y) => x.Seasons = y,
|
||||
(x, y) => { x.Show = y; x.ShowID = y.ID; }),
|
||||
|
||||
(Show s, nameof(Show.Episodes)) => SetRelation(s,
|
||||
|
||||
(Show s, nameof(Show.Episodes)) => SetRelation(s,
|
||||
EpisodeRepository.GetAll(x => x.Show.ID == obj.ID),
|
||||
(x, y) => x.Episodes = y,
|
||||
(x, y) => { x.Show = y; x.ShowID = y.ID; }),
|
||||
|
||||
|
||||
(Show s, nameof(Show.Libraries)) => LibraryRepository
|
||||
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||
.Then(x => s.Libraries = x),
|
||||
|
||||
|
||||
(Show s, nameof(Show.Collections)) => CollectionRepository
|
||||
.GetAll(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||
.Then(x => s.Collections = x),
|
||||
|
||||
|
||||
(Show s, nameof(Show.Studio)) => StudioRepository
|
||||
.GetOrDefault(x => x.Shows.Any(y => y.ID == obj.ID))
|
||||
.Then(x =>
|
||||
@ -292,18 +292,18 @@ namespace Kyoo.Core.Controllers
|
||||
s.Studio = x;
|
||||
s.StudioID = x?.ID ?? 0;
|
||||
}),
|
||||
|
||||
|
||||
(Season s, nameof(Season.ExternalIDs)) => SetRelation(s,
|
||||
|
||||
|
||||
(Season s, nameof(Season.ExternalIDs)) => SetRelation(s,
|
||||
ProviderRepository.GetMetadataID<Season>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
(Season s, nameof(Season.Episodes)) => SetRelation(s,
|
||||
|
||||
(Season s, nameof(Season.Episodes)) => SetRelation(s,
|
||||
EpisodeRepository.GetAll(x => x.Season.ID == obj.ID),
|
||||
(x, y) => x.Episodes = y,
|
||||
(x, y) => { x.Season = y; x.SeasonID = y.ID; }),
|
||||
|
||||
|
||||
(Season s, nameof(Season.Show)) => ShowRepository
|
||||
.GetOrDefault(x => x.Seasons.Any(y => y.ID == obj.ID))
|
||||
.Then(x =>
|
||||
@ -311,18 +311,18 @@ namespace Kyoo.Core.Controllers
|
||||
s.Show = x;
|
||||
s.ShowID = x?.ID ?? 0;
|
||||
}),
|
||||
|
||||
|
||||
(Episode e, nameof(Episode.ExternalIDs)) => SetRelation(e,
|
||||
ProviderRepository.GetMetadataID<Episode>(x => x.ResourceID == obj.ID),
|
||||
|
||||
|
||||
(Episode e, nameof(Episode.ExternalIDs)) => SetRelation(e,
|
||||
ProviderRepository.GetMetadataID<Episode>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
(Episode e, nameof(Episode.Tracks)) => SetRelation(e,
|
||||
|
||||
(Episode e, nameof(Episode.Tracks)) => SetRelation(e,
|
||||
TrackRepository.GetAll(x => x.Episode.ID == obj.ID),
|
||||
(x, y) => x.Tracks = y,
|
||||
(x, y) => { x.Episode = y; x.EpisodeID = y.ID; }),
|
||||
|
||||
|
||||
(Episode e, nameof(Episode.Show)) => ShowRepository
|
||||
.GetOrDefault(x => x.Episodes.Any(y => y.ID == obj.ID))
|
||||
.Then(x =>
|
||||
@ -330,7 +330,7 @@ namespace Kyoo.Core.Controllers
|
||||
e.Show = x;
|
||||
e.ShowID = x?.ID ?? 0;
|
||||
}),
|
||||
|
||||
|
||||
(Episode e, nameof(Episode.Season)) => SeasonRepository
|
||||
.GetOrDefault(x => x.Episodes.Any(y => y.ID == e.ID))
|
||||
.Then(x =>
|
||||
@ -338,8 +338,8 @@ namespace Kyoo.Core.Controllers
|
||||
e.Season = x;
|
||||
e.SeasonID = x?.ID ?? 0;
|
||||
}),
|
||||
|
||||
|
||||
|
||||
|
||||
(Track t, nameof(Track.Episode)) => EpisodeRepository
|
||||
.GetOrDefault(x => x.Tracks.Any(y => y.ID == obj.ID))
|
||||
.Then(x =>
|
||||
@ -347,62 +347,62 @@ namespace Kyoo.Core.Controllers
|
||||
t.Episode = x;
|
||||
t.EpisodeID = x?.ID ?? 0;
|
||||
}),
|
||||
|
||||
|
||||
|
||||
|
||||
(Genre g, nameof(Genre.Shows)) => ShowRepository
|
||||
.GetAll(x => x.Genres.Any(y => y.ID == obj.ID))
|
||||
.Then(x => g.Shows = x),
|
||||
|
||||
|
||||
|
||||
|
||||
(Studio s, nameof(Studio.Shows)) => ShowRepository
|
||||
.GetAll(x => x.Studio.ID == obj.ID)
|
||||
.Then(x => s.Shows = x),
|
||||
|
||||
(Studio s, nameof(Studio.ExternalIDs)) => SetRelation(s,
|
||||
|
||||
(Studio s, nameof(Studio.ExternalIDs)) => SetRelation(s,
|
||||
ProviderRepository.GetMetadataID<Studio>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
|
||||
(People p, nameof(People.ExternalIDs)) => SetRelation(p,
|
||||
|
||||
|
||||
(People p, nameof(People.ExternalIDs)) => SetRelation(p,
|
||||
ProviderRepository.GetMetadataID<People>(x => x.ResourceID == obj.ID),
|
||||
(x, y) => x.ExternalIDs = y,
|
||||
(x, y) => { x.ResourceID = y.ID; }),
|
||||
|
||||
|
||||
(People p, nameof(People.Roles)) => PeopleRepository
|
||||
.GetFromPeople(obj.ID)
|
||||
.Then(x => p.Roles = x),
|
||||
|
||||
|
||||
|
||||
|
||||
(Provider p, nameof(Provider.Libraries)) => LibraryRepository
|
||||
.GetAll(x => x.Providers.Any(y => y.ID == obj.ID))
|
||||
.Then(x => p.Libraries = x),
|
||||
|
||||
|
||||
|
||||
_ => throw new ArgumentException($"Couldn't find a way to load {memberName} of {obj.Slug}.")
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return LibraryItemRepository.GetFromLibrary(id, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return LibraryItemRepository.GetFromLibrary(slug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
@ -411,16 +411,16 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
@ -454,7 +454,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
Pagination limit = default)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().GetAll(where, sort, limit);
|
||||
@ -468,19 +468,19 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> Search<T>(string query)
|
||||
public Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Search(query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Create<T>(T item)
|
||||
public Task<T> Create<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Create(item);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> CreateIfNotExists<T>(T item)
|
||||
where T : class, IResource
|
||||
@ -496,21 +496,21 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(T item)
|
||||
public Task Delete<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(int id)
|
||||
public Task Delete<T>(int id)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(string slug)
|
||||
public Task Delete<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(slug);
|
||||
|
@ -14,7 +14,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
logger.LogWarning("No permission validator has been enabled, all users will have all permissions");
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata Create(PermissionAttribute attribute)
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// The logger used by this class.
|
||||
/// </summary>
|
||||
private readonly ILogger<PluginManager> _logger;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The list of plugins that are currently loaded.
|
||||
/// </summary>
|
||||
@ -93,7 +93,7 @@ namespace Kyoo.Core.Controllers
|
||||
return Array.Empty<IPlugin>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void LoadPlugins(ICollection<IPlugin> plugins)
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ namespace Kyoo.Core.Controllers
|
||||
_providers = providers.ToArray();
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void UseProviders(IEnumerable<Provider> providers)
|
||||
@ -71,9 +71,9 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
ret = Merger.Merge(ret, await provider.Get(ret));
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "The provider {Provider} could not get a {Type}",
|
||||
_logger.LogError(ex, "The provider {Provider} could not get a {Type}",
|
||||
provider.Provider.Name, typeof(T).Name);
|
||||
}
|
||||
}
|
||||
@ -85,16 +85,16 @@ namespace Kyoo.Core.Controllers
|
||||
public override async Task<ICollection<T>> Search<T>(string query)
|
||||
{
|
||||
List<T> ret = new();
|
||||
|
||||
|
||||
foreach (IMetadataProvider provider in _GetProviders())
|
||||
{
|
||||
try
|
||||
{
|
||||
ret.AddRange(await provider.Search<T>(query));
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "The provider {Provider} could not search for {Type}",
|
||||
_logger.LogError(ex, "The provider {Provider} could not search for {Type}",
|
||||
provider.Provider.Name, typeof(T).Name);
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace Kyoo.Core.Controllers
|
||||
.FirstOrDefault();
|
||||
return path[(libraryPath?.Length ?? 0)..];
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<(Collection, Show, Season, Episode)> Identify(string path)
|
||||
{
|
||||
@ -77,21 +77,21 @@ namespace Kyoo.Core.Controllers
|
||||
Slug = Utility.ToSlug(match.Groups["Show"].Value),
|
||||
Title = match.Groups["Show"].Value,
|
||||
Path = Path.GetDirectoryName(path),
|
||||
StartAir = match.Groups["StartYear"].Success
|
||||
? new DateTime(int.Parse(match.Groups["StartYear"].Value), 1, 1)
|
||||
StartAir = match.Groups["StartYear"].Success
|
||||
? new DateTime(int.Parse(match.Groups["StartYear"].Value), 1, 1)
|
||||
: null
|
||||
},
|
||||
season: null,
|
||||
episode: new Episode
|
||||
{
|
||||
SeasonNumber = match.Groups["Season"].Success
|
||||
? int.Parse(match.Groups["Season"].Value)
|
||||
SeasonNumber = match.Groups["Season"].Success
|
||||
? int.Parse(match.Groups["Season"].Value)
|
||||
: null,
|
||||
EpisodeNumber = match.Groups["Episode"].Success
|
||||
? int.Parse(match.Groups["Episode"].Value)
|
||||
EpisodeNumber = match.Groups["Episode"].Success
|
||||
? int.Parse(match.Groups["Episode"].Value)
|
||||
: null,
|
||||
AbsoluteNumber = match.Groups["Absolute"].Success
|
||||
? int.Parse(match.Groups["Absolute"].Value)
|
||||
AbsoluteNumber = match.Groups["Absolute"].Success
|
||||
? int.Parse(match.Groups["Absolute"].Value)
|
||||
: null,
|
||||
Path = path
|
||||
}
|
||||
|
@ -19,12 +19,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A provider repository to handle externalID creation and deletion
|
||||
/// </summary>
|
||||
private readonly IProviderRepository _providers;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Collection, object>> DefaultSort => x => x.Name;
|
||||
|
||||
@ -58,12 +58,12 @@ namespace Kyoo.Core.Controllers
|
||||
await _database.SaveChangesAsync($"Trying to insert a duplicated collection (slug {obj.Slug} already exists).");
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task Validate(Collection resource)
|
||||
{
|
||||
await base.Validate(resource);
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(resource.Slug))
|
||||
throw new ArgumentException("The collection's slug must be set and not empty");
|
||||
if (string.IsNullOrEmpty(resource.Name))
|
||||
@ -72,7 +72,7 @@ namespace Kyoo.Core.Controllers
|
||||
if (resource.ExternalIDs != null)
|
||||
{
|
||||
foreach (MetadataID id in resource.ExternalIDs)
|
||||
{
|
||||
{
|
||||
id.Provider = _database.LocalEntity<Provider>(id.Provider.Slug)
|
||||
?? await _providers.CreateIfNotExists(id.Provider);
|
||||
id.ProviderID = id.Provider.ID;
|
||||
@ -80,12 +80,12 @@ namespace Kyoo.Core.Controllers
|
||||
_database.MetadataIds<Collection>().AttachRange(resource.ExternalIDs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task EditRelations(Collection resource, Collection changed, bool resetOld)
|
||||
{
|
||||
await Validate(changed);
|
||||
|
||||
|
||||
if (changed.ExternalIDs != null || resetOld)
|
||||
{
|
||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
||||
|
@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// A track repository to handle creation and deletion of tracks related to the current episode.
|
||||
/// </summary>
|
||||
private readonly ITrackRepository _tracks;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Episode, object>> DefaultSort => x => x.EpisodeNumber;
|
||||
|
||||
@ -42,27 +42,27 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="tracks">A track repository</param>
|
||||
public EpisodeRepository(DatabaseContext database,
|
||||
IProviderRepository providers,
|
||||
ITrackRepository tracks)
|
||||
ITrackRepository tracks)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_providers = providers;
|
||||
_tracks = tracks;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.EpisodeNumber == episodeNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.EpisodeNumber == episodeNumber);
|
||||
}
|
||||
|
||||
@ -87,14 +87,14 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> GetAbsolute(int showID, int absoluteNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
&& x.AbsoluteNumber == absoluteNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> GetAbsolute(string showSlug, int absoluteNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.AbsoluteNumber == absoluteNumber);
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ namespace Kyoo.Core.Controllers
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Episode> Create(Episode obj)
|
||||
{
|
||||
@ -146,7 +146,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (resource.Tracks == null)
|
||||
return resource;
|
||||
|
||||
|
||||
resource.Tracks = await resource.Tracks.SelectAsync(x =>
|
||||
{
|
||||
x.Episode = resource;
|
||||
@ -156,7 +156,7 @@ namespace Kyoo.Core.Controllers
|
||||
_database.Tracks.AttachRange(resource.Tracks);
|
||||
return resource;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task Validate(Episode resource)
|
||||
{
|
||||
@ -180,17 +180,17 @@ namespace Kyoo.Core.Controllers
|
||||
_database.MetadataIds<Episode>().AttachRange(resource.ExternalIDs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Delete(Episode obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
await obj.Tracks.ForEachAsync(x => _tracks.Delete(x));
|
||||
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ namespace Kyoo.Core.Controllers
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Genre, object>> DefaultSort => x => x.Slug;
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="GenreRepository"/>.
|
||||
/// </summary>
|
||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// </summary>
|
||||
/// <param name="database">The database instance</param>
|
||||
/// <param name="libraries">A lazy loaded library repository</param>
|
||||
public LibraryItemRepository(DatabaseContext database,
|
||||
public LibraryItemRepository(DatabaseContext database,
|
||||
Lazy<ILibraryRepository> libraries)
|
||||
: base(database)
|
||||
{
|
||||
@ -42,13 +42,13 @@ namespace Kyoo.Core.Controllers
|
||||
_libraries = libraries;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> GetOrDefault(int id)
|
||||
{
|
||||
return _database.LibraryItems.FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> GetOrDefault(string slug)
|
||||
{
|
||||
@ -83,27 +83,27 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> Create(LibraryItem obj)
|
||||
public override Task<LibraryItem> Create(LibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj)
|
||||
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task<LibraryItem> Edit(LibraryItem obj, bool resetOld)
|
||||
public override Task<LibraryItem> Edit(LibraryItem obj, bool resetOld)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task Delete(int id)
|
||||
public override Task Delete(int id)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task Delete(string slug)
|
||||
public override Task Delete(string slug)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task Delete(LibraryItem obj)
|
||||
public override Task Delete(LibraryItem obj)
|
||||
=> throw new InvalidOperationException();
|
||||
|
||||
/// <summary>
|
||||
@ -125,8 +125,8 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<LibraryItem>> GetFromLibrary(int id,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<LibraryItem> items = await ApplyFilters(LibraryRelatedQuery(x => x.ID == id),
|
||||
@ -137,11 +137,11 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ItemNotFoundException();
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Expression<Func<LibraryItem, bool>> where = null,
|
||||
Sort<LibraryItem> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<LibraryItem> items = await ApplyFilters(LibraryRelatedQuery(x => x.Slug == slug),
|
||||
|
@ -24,7 +24,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// A provider repository to handle externalID creation and deletion
|
||||
/// </summary>
|
||||
private readonly IProviderRepository _providers;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Library, object>> DefaultSort => x => x.ID;
|
||||
|
||||
@ -41,7 +41,7 @@ namespace Kyoo.Core.Controllers
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Library>> Search(string query)
|
||||
{
|
||||
@ -65,14 +65,14 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task Validate(Library resource)
|
||||
{
|
||||
await base.Validate(resource);
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(resource.Slug))
|
||||
throw new ArgumentException("The library's slug must be set and not empty");
|
||||
if (string.IsNullOrEmpty(resource.Name))
|
||||
throw new ArgumentException("The library's name must be set and not empty");
|
||||
if (resource.Paths == null || !resource.Paths.Any())
|
||||
throw new ArgumentException("The library should have a least one path.");
|
||||
|
||||
|
||||
if (resource.Providers != null)
|
||||
{
|
||||
resource.Providers = await resource.Providers
|
||||
@ -99,7 +99,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ namespace Kyoo.Core.Controllers
|
||||
/// The default sort order that will be used for this resource's type.
|
||||
/// </summary>
|
||||
protected abstract Expression<Func<T, object>> DefaultSort { get; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new base <see cref="LocalRepository{T}"/> with the given database handle.
|
||||
/// </summary>
|
||||
@ -57,7 +57,7 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(int id)
|
||||
{
|
||||
@ -84,19 +84,19 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T> GetOrDefault(int id)
|
||||
{
|
||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.ID == id);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T> GetOrDefault(string slug)
|
||||
{
|
||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T> GetOrDefault(Expression<Func<T, bool>> where)
|
||||
{
|
||||
@ -105,7 +105,7 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract Task<ICollection<T>> Search(string query);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
@ -113,7 +113,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
return ApplyFilters(Database.Set<T>(), where, sort, limit);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Apply filters to a query to ease sort, pagination & where queries for resources of this repository
|
||||
/// </summary>
|
||||
@ -124,12 +124,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// <returns>The filtered query</returns>
|
||||
protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||
Expression<Func<T, bool>> where = null,
|
||||
Sort<T> sort = default,
|
||||
Sort<T> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
return ApplyFilters(query, GetOrDefault, DefaultSort, where, sort, limit);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Apply filters to a query to ease sort, pagination & where queries for any resources types.
|
||||
/// For resources of type <see cref="T"/>, see <see cref="ApplyFilters"/>
|
||||
@ -145,17 +145,17 @@ namespace Kyoo.Core.Controllers
|
||||
Func<int, Task<TValue>> get,
|
||||
Expression<Func<TValue, object>> defaultSort,
|
||||
Expression<Func<TValue, bool>> where = null,
|
||||
Sort<TValue> sort = default,
|
||||
Sort<TValue> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
if (where != null)
|
||||
query = query.Where(where);
|
||||
|
||||
|
||||
Expression<Func<TValue, object>> sortKey = sort.Key ?? defaultSort;
|
||||
Expression sortExpression = sortKey.Body.NodeType == ExpressionType.Convert
|
||||
? ((UnaryExpression)sortKey.Body).Operand
|
||||
: sortKey.Body;
|
||||
|
||||
|
||||
if (typeof(Enum).IsAssignableFrom(sortExpression.Type))
|
||||
throw new ArgumentException("Invalid sort key.");
|
||||
|
||||
@ -205,7 +205,7 @@ namespace Kyoo.Core.Controllers
|
||||
T old = await GetOrDefault(obj.Slug);
|
||||
if (old != null)
|
||||
return old;
|
||||
|
||||
|
||||
return await Create(obj);
|
||||
}
|
||||
catch (DuplicatedItemException)
|
||||
@ -225,7 +225,7 @@ namespace Kyoo.Core.Controllers
|
||||
try
|
||||
{
|
||||
T old = await GetWithTracking(edited.ID);
|
||||
|
||||
|
||||
if (resetOld)
|
||||
old = Merger.Nullify(old);
|
||||
Merger.Complete(old, edited, x => x.GetCustomAttribute<LoadableRelationAttribute>() == null);
|
||||
@ -239,7 +239,7 @@ namespace Kyoo.Core.Controllers
|
||||
Database.ChangeTracker.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// An overridable method to edit relation of a resource.
|
||||
/// </summary>
|
||||
@ -257,7 +257,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
return Validate(resource);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A method called just before saving a new resource to the database.
|
||||
/// It is also called on the default implementation of <see cref="EditRelations"/>
|
||||
@ -278,7 +278,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
MethodInfo setter = typeof(T).GetProperty(nameof(resource.Slug))!.GetSetMethod();
|
||||
if (setter != null)
|
||||
setter.Invoke(resource, new object[] {resource.Slug + '!'});
|
||||
setter.Invoke(resource, new object[] { resource.Slug + '!' });
|
||||
else
|
||||
throw new ArgumentException("Resources slug can't be number only.");
|
||||
}
|
||||
@ -306,7 +306,7 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract Task Delete(T obj);
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task DeleteAll(Expression<Func<T, bool>> where)
|
||||
{
|
||||
|
@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// A lazy loaded show repository to validate requests from shows.
|
||||
/// </summary>
|
||||
private readonly Lazy<IShowRepository> _shows;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<People, object>> DefaultSort => x => x.Name;
|
||||
|
||||
@ -41,14 +41,14 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="shows">A lazy loaded show repository</param>
|
||||
public PeopleRepository(DatabaseContext database,
|
||||
IProviderRepository providers,
|
||||
Lazy<IShowRepository> shows)
|
||||
Lazy<IShowRepository> shows)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
_providers = providers;
|
||||
_shows = shows;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<People>> Search(string query)
|
||||
@ -89,7 +89,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
foreach (PeopleRole role in resource.Roles)
|
||||
{
|
||||
role.Show = _database.LocalEntity<Show>(role.Show.Slug)
|
||||
role.Show = _database.LocalEntity<Show>(role.Show.Slug)
|
||||
?? await _shows.Value.CreateIfNotExists(role.Show);
|
||||
role.ShowID = role.Show.ID;
|
||||
_database.Entry(role).State = EntityState.Added;
|
||||
@ -101,7 +101,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task EditRelations(People resource, People changed, bool resetOld)
|
||||
{
|
||||
await Validate(changed);
|
||||
|
||||
|
||||
if (changed.Roles != null || resetOld)
|
||||
{
|
||||
await Database.Entry(resource).Collection(x => x.Roles).LoadAsync();
|
||||
@ -120,7 +120,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
obj.ExternalIDs.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
||||
obj.Roles.ForEach(x => _database.Entry(x).State = EntityState.Deleted);
|
||||
@ -128,9 +128,9 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
public async Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
||||
@ -151,7 +151,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<PeopleRole> people = await ApplyFilters(_database.PeopleRoles
|
||||
@ -169,11 +169,11 @@ namespace Kyoo.Core.Controllers
|
||||
role.ForPeople = true;
|
||||
return people;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
||||
@ -188,11 +188,11 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ItemNotFoundException();
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>> where = null,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Sort<PeopleRole> sort = default,
|
||||
Pagination limit = default)
|
||||
{
|
||||
ICollection<PeopleRole> roles = await ApplyFilters(_database.PeopleRoles
|
||||
|
@ -50,7 +50,7 @@ namespace Kyoo.Core.Controllers
|
||||
throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Season> Get(string showSlug, int seasonNumber)
|
||||
{
|
||||
@ -63,14 +63,14 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc/>
|
||||
public Task<Season> GetOrDefault(int showID, int seasonNumber)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowID == showID
|
||||
&& x.SeasonNumber == seasonNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<Season> GetOrDefault(string showSlug, int seasonNumber)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.Show.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber);
|
||||
}
|
||||
|
||||
@ -121,14 +121,14 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task EditRelations(Season resource, Season changed, bool resetOld)
|
||||
{
|
||||
await Validate(changed);
|
||||
|
||||
|
||||
if (changed.ExternalIDs != null || resetOld)
|
||||
{
|
||||
await Database.Entry(resource).Collection(x => x.ExternalIDs).LoadAsync();
|
||||
resource.ExternalIDs = changed.ExternalIDs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task Delete(Season obj)
|
||||
{
|
||||
@ -139,4 +139,4 @@ namespace Kyoo.Core.Controllers
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="providers">A provider repository</param>
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
IPeopleRepository people,
|
||||
IGenreRepository genres,
|
||||
IPeopleRepository people,
|
||||
IGenreRepository genres,
|
||||
IProviderRepository providers)
|
||||
: base(database)
|
||||
{
|
||||
@ -61,7 +61,7 @@ namespace Kyoo.Core.Controllers
|
||||
_genres = genres;
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Show>> Search(string query)
|
||||
@ -82,7 +82,7 @@ namespace Kyoo.Core.Controllers
|
||||
await _database.SaveChangesAsync($"Trying to insert a duplicated show (slug {obj.Slug} already exists).");
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task Validate(Show resource)
|
||||
{
|
||||
@ -128,7 +128,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task EditRelations(Show resource, Show changed, bool resetOld)
|
||||
{
|
||||
await Validate(changed);
|
||||
|
||||
|
||||
if (changed.Aliases != null || resetOld)
|
||||
resource.Aliases = changed.Aliases;
|
||||
|
||||
@ -137,7 +137,7 @@ namespace Kyoo.Core.Controllers
|
||||
await Database.Entry(resource).Reference(x => x.Studio).LoadAsync();
|
||||
resource.Studio = changed.Studio;
|
||||
}
|
||||
|
||||
|
||||
if (changed.Genres != null || resetOld)
|
||||
{
|
||||
await Database.Entry(resource).Collection(x => x.Genres).LoadAsync();
|
||||
@ -177,7 +177,7 @@ namespace Kyoo.Core.Controllers
|
||||
await _database.SaveIfNoDuplicates();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<string> GetSlug(int showID)
|
||||
{
|
||||
@ -185,7 +185,7 @@ namespace Kyoo.Core.Controllers
|
||||
.Select(x => x.Slug)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Delete(Show obj)
|
||||
{
|
||||
|
@ -19,12 +19,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A provider repository to handle externalID creation and deletion
|
||||
/// </summary>
|
||||
private readonly IProviderRepository _providers;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Studio, object>> DefaultSort => x => x.Name;
|
||||
|
||||
@ -40,7 +40,7 @@ namespace Kyoo.Core.Controllers
|
||||
_database = database;
|
||||
_providers = providers;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Studio>> Search(string query)
|
||||
{
|
||||
@ -59,7 +59,7 @@ namespace Kyoo.Core.Controllers
|
||||
await _database.SaveChangesAsync($"Trying to insert a duplicated studio (slug {obj.Slug} already exists).");
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task Validate(Studio resource)
|
||||
{
|
||||
@ -75,7 +75,7 @@ namespace Kyoo.Core.Controllers
|
||||
_database.MetadataIds<Studio>().AttachRange(resource.ExternalIDs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task EditRelations(Studio resource, Studio changed, bool resetOld)
|
||||
{
|
||||
@ -93,7 +93,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<Track, object>> DefaultSort => x => x.TrackIndex;
|
||||
|
||||
@ -27,7 +27,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// Create a new <see cref="TrackRepository"/>.
|
||||
/// </summary>
|
||||
/// <param name="database">The database handle</param>
|
||||
public TrackRepository(DatabaseContext database)
|
||||
public TrackRepository(DatabaseContext database)
|
||||
: base(database)
|
||||
{
|
||||
_database = database;
|
||||
@ -69,7 +69,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
@ -19,11 +19,11 @@ namespace Kyoo.Core.Controllers
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Expression<Func<User, object>> DefaultSort => x => x.Username;
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="UserRepository"/>
|
||||
/// </summary>
|
||||
@ -33,7 +33,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<User>> Search(string query)
|
||||
{
|
||||
@ -43,7 +43,7 @@ namespace Kyoo.Core.Controllers
|
||||
.Take(20)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<User> Create(User obj)
|
||||
{
|
||||
@ -58,7 +58,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException(nameof(obj));
|
||||
|
||||
|
||||
_database.Entry(obj).State = EntityState.Deleted;
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// The metadata for this task (the slug, and other useful information).
|
||||
/// </summary>
|
||||
public TaskMetadataAttribute Metadata { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The function used to create the task object.
|
||||
/// </summary>
|
||||
@ -53,23 +53,23 @@ namespace Kyoo.Core.Controllers
|
||||
/// The task currently queued.
|
||||
/// </summary>
|
||||
public ManagedTask Task { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The progress reporter that this task should use.
|
||||
/// </summary>
|
||||
public IProgress<float> ProgressReporter { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The arguments to give to run the task with.
|
||||
/// </summary>
|
||||
public Dictionary<string, object> Arguments { get; init; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A token informing the task that it should be cancelled or not.
|
||||
/// </summary>
|
||||
public CancellationToken? CancellationToken { get; init; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration instance used to get schedule information
|
||||
/// </summary>
|
||||
@ -115,14 +115,14 @@ namespace Kyoo.Core.Controllers
|
||||
Metadata = x.Metadata,
|
||||
ScheduledDate = GetNextTaskDate(x.Metadata.Slug)
|
||||
}).ToList();
|
||||
|
||||
|
||||
if (_tasks.Any())
|
||||
_logger.LogTrace("Task manager initiated with: {Tasks}", _tasks.Select(x => x.Metadata.Name));
|
||||
else
|
||||
_logger.LogInformation("Task manager initiated without any tasks");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the application host is ready to start the service.
|
||||
/// </summary>
|
||||
@ -133,7 +133,7 @@ namespace Kyoo.Core.Controllers
|
||||
Task.Run(() => base.StartAsync(cancellationToken), CancellationToken.None);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
@ -148,7 +148,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_EnqueueStartupTasks();
|
||||
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (_queuedTasks.Any())
|
||||
@ -160,12 +160,12 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
catch (TaskFailedException ex)
|
||||
{
|
||||
_logger.LogWarning("The task \"{Task}\" failed: {Message}",
|
||||
_logger.LogWarning("The task \"{Task}\" failed: {Message}",
|
||||
task.Task.Metadata.Name, ex.Message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "An unhandled exception occured while running the task {Task}",
|
||||
_logger.LogError(e, "An unhandled exception occured while running the task {Task}",
|
||||
task.Task.Metadata.Name);
|
||||
}
|
||||
}
|
||||
@ -188,7 +188,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// If the number of arguments is invalid, if an argument can't be converted or if the task finds the argument
|
||||
/// invalid.
|
||||
/// </exception>
|
||||
private async Task _RunTask(ManagedTask task,
|
||||
private async Task _RunTask(ManagedTask task,
|
||||
[NotNull] IProgress<float> progress,
|
||||
Dictionary<string, object> arguments,
|
||||
CancellationToken? cancellationToken = null)
|
||||
@ -220,14 +220,14 @@ namespace Kyoo.Core.Controllers
|
||||
return x.CreateValue(value ?? x.DefaultValue);
|
||||
}));
|
||||
|
||||
_logger.LogInformation("Task starting: {Task} ({Parameters})",
|
||||
_logger.LogInformation("Task starting: {Task} ({Parameters})",
|
||||
task.Metadata.Name, args.ToDictionary(x => x.Name, x => x.As<object>()));
|
||||
|
||||
|
||||
CancellationToken token = cancellationToken != null
|
||||
? CancellationTokenSource.CreateLinkedTokenSource(_taskToken.Token, cancellationToken.Value).Token
|
||||
: _taskToken.Token;
|
||||
await taskObj.Value.Run(args, progress, token);
|
||||
|
||||
|
||||
_logger.LogInformation("Task finished: {Task}", task.Metadata.Name);
|
||||
_runningTask = null;
|
||||
}
|
||||
@ -261,13 +261,13 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void StartTask(string taskSlug,
|
||||
public void StartTask(string taskSlug,
|
||||
IProgress<float> progress,
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null)
|
||||
{
|
||||
arguments ??= new Dictionary<string, object>();
|
||||
|
||||
|
||||
int index = _tasks.FindIndex(x => x.Metadata.Slug == taskSlug);
|
||||
if (index == -1)
|
||||
throw new ItemNotFoundException($"No task found with the slug {taskSlug}");
|
||||
@ -276,13 +276,13 @@ namespace Kyoo.Core.Controllers
|
||||
Task = _tasks[index],
|
||||
ProgressReporter = progress,
|
||||
Arguments = arguments,
|
||||
CancellationToken = cancellationToken
|
||||
CancellationToken = cancellationToken
|
||||
});
|
||||
_tasks[index].ScheduledDate = GetNextTaskDate(taskSlug);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void StartTask<T>(IProgress<float> progress,
|
||||
public void StartTask<T>(IProgress<float> progress,
|
||||
Dictionary<string, object> arguments = null,
|
||||
CancellationToken? cancellationToken = null)
|
||||
where T : ITask
|
||||
@ -304,12 +304,12 @@ namespace Kyoo.Core.Controllers
|
||||
return DateTime.Now + delay;
|
||||
return DateTime.MaxValue;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<(TaskMetadataAttribute, ITask)> GetRunningTasks()
|
||||
{
|
||||
return _runningTask == null
|
||||
? ArraySegment<(TaskMetadataAttribute, ITask)>.Empty
|
||||
return _runningTask == null
|
||||
? ArraySegment<(TaskMetadataAttribute, ITask)>.Empty
|
||||
: new[] { _runningTask.Value };
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// </summary>
|
||||
/// <param name="files">The file manager to use.</param>
|
||||
/// <param name="logger">A logger to report errors</param>
|
||||
public ThumbnailsManager(IFileSystem files,
|
||||
public ThumbnailsManager(IFileSystem files,
|
||||
ILogger<ThumbnailsManager> logger)
|
||||
{
|
||||
_files = files;
|
||||
@ -66,7 +66,7 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
||||
public async Task<bool> DownloadImages<T>(T item, bool alwaysDownload = false)
|
||||
where T : IThumbnails
|
||||
{
|
||||
if (item == null)
|
||||
@ -84,7 +84,7 @@ namespace Kyoo.Core.Controllers
|
||||
if (alwaysDownload || !await _files.Exists(localPath))
|
||||
ret |= await _DownloadImage(image, localPath, $"The image n°{id} of {name}");
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
|
||||
|
||||
string directory = await _files.GetExtraDirectory(item);
|
||||
string imageName = imageID switch
|
||||
{
|
||||
@ -109,7 +109,7 @@ namespace Kyoo.Core.Controllers
|
||||
Images.Trailer => "trailer",
|
||||
_ => $"{imageID}"
|
||||
};
|
||||
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case Season season:
|
||||
@ -123,7 +123,7 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
return _files.Combine(directory, imageName);
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> GetImagePath<T>(T item, int imageID)
|
||||
where T : IThumbnails
|
||||
|
@ -13,8 +13,8 @@ using Stream = Kyoo.Core.Models.Watch.Stream;
|
||||
|
||||
namespace Kyoo.Core.Controllers
|
||||
{
|
||||
public class BadTranscoderException : Exception {}
|
||||
|
||||
public class BadTranscoderException : Exception { }
|
||||
|
||||
public class Transcoder : ITranscoder
|
||||
{
|
||||
private static class TranscoderAPI
|
||||
@ -26,7 +26,7 @@ namespace Kyoo.Core.Controllers
|
||||
|
||||
public static int Init() => init();
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
|
||||
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
private static extern int transmux(string path, string outpath, out float playableDuration);
|
||||
|
||||
@ -37,9 +37,9 @@ namespace Kyoo.Core.Controllers
|
||||
return transmux(path, outPath, out playableDuration);
|
||||
}
|
||||
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
|
||||
[DllImport(TranscoderPath, CallingConvention = CallingConvention.Cdecl,
|
||||
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
private static extern IntPtr extract_infos(string path,
|
||||
private static extern IntPtr extract_infos(string path,
|
||||
string outpath,
|
||||
out uint length,
|
||||
out uint trackCount,
|
||||
@ -53,12 +53,12 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
path = path.Replace('\\', '/');
|
||||
outPath = outPath.Replace('\\', '/');
|
||||
|
||||
|
||||
int size = Marshal.SizeOf<Models.Watch.Stream>();
|
||||
IntPtr ptr = extract_infos(path, outPath, out uint arrayLength, out uint trackCount, reextract);
|
||||
IntPtr streamsPtr = ptr;
|
||||
Track[] tracks;
|
||||
|
||||
|
||||
if (trackCount > 0 && ptr != IntPtr.Zero)
|
||||
{
|
||||
tracks = new Track[trackCount];
|
||||
@ -113,7 +113,7 @@ namespace Kyoo.Core.Controllers
|
||||
{
|
||||
if (!File.Exists(episode.Path))
|
||||
throw new ArgumentException("Path does not exists. Can't transcode.");
|
||||
|
||||
|
||||
string folder = Path.Combine(_options.Value.TransmuxPath, episode.Slug);
|
||||
string manifest = Path.Combine(folder, episode.Slug + ".m3u8");
|
||||
float playableDuration = 0;
|
||||
@ -130,7 +130,7 @@ namespace Kyoo.Core.Controllers
|
||||
await Console.Error.WriteLineAsync($"Access to the path {manifest} is denied. Please change your transmux path in the config.");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
transmuxFailed = TranscoderAPI.Transmux(episode.Path, manifest, out playableDuration) != 0;
|
||||
|
@ -29,10 +29,10 @@ namespace Kyoo.Core
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string Slug => "core";
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => "Core";
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Description => "The core module containing default implementations.";
|
||||
|
||||
@ -66,11 +66,11 @@ namespace Kyoo.Core
|
||||
public void Configure(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterModule<AttributedMetadataModule>();
|
||||
|
||||
|
||||
builder.RegisterComposite<FileSystemComposite, IFileSystem>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<LocalFileSystem>().As<IFileSystem>().SingleInstance();
|
||||
builder.RegisterType<HttpFileSystem>().As<IFileSystem>().SingleInstance();
|
||||
|
||||
|
||||
builder.RegisterType<TaskManager>().As<ITaskManager>().As<IHostedService>().SingleInstance();
|
||||
|
||||
builder.RegisterType<ConfigurationManager>().As<IConfigurationManager>().SingleInstance();
|
||||
@ -78,7 +78,7 @@ namespace Kyoo.Core
|
||||
builder.RegisterType<ThumbnailsManager>().As<IThumbnailsManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<RegexIdentifier>().As<IIdentifier>().SingleInstance();
|
||||
|
||||
|
||||
builder.RegisterComposite<ProviderComposite, IMetadataProvider>();
|
||||
builder.Register(x => (AProviderComposite)x.Resolve<IMetadataProvider>());
|
||||
|
||||
@ -106,7 +106,7 @@ namespace Kyoo.Core
|
||||
|
||||
builder.RegisterType<PassthroughPermissionValidator>().As<IPermissionValidator>()
|
||||
.IfNotRegistered(typeof(IPermissionValidator));
|
||||
|
||||
|
||||
builder.RegisterType<FileExtensionContentTypeProvider>().As<IContentTypeProvider>().SingleInstance()
|
||||
.OnActivating(x =>
|
||||
{
|
||||
@ -117,7 +117,7 @@ namespace Kyoo.Core
|
||||
x.Instance.Mappings[".m3u8"] = "application/x-mpegurl";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IServiceCollection services)
|
||||
{
|
||||
@ -130,12 +130,12 @@ namespace Kyoo.Core
|
||||
x.SerializerSettings.ContractResolver = new JsonPropertyIgnorer(publicUrl);
|
||||
x.SerializerSettings.Converters.Add(new PeopleRoleConverter());
|
||||
});
|
||||
|
||||
|
||||
services.AddResponseCompression(x =>
|
||||
{
|
||||
x.EnableForHttps = true;
|
||||
});
|
||||
|
||||
|
||||
services.AddHttpClient();
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace Kyoo.Core.Models.Watch
|
||||
".mkv",
|
||||
".flv",
|
||||
".vob",
|
||||
".ogg",
|
||||
".ogg",
|
||||
".ogv",
|
||||
".avi",
|
||||
".mts",
|
||||
@ -25,7 +25,7 @@ namespace Kyoo.Core.Models.Watch
|
||||
".ts",
|
||||
".mov",
|
||||
".qt",
|
||||
".asf",
|
||||
".asf",
|
||||
".mp4",
|
||||
".m4p",
|
||||
".m4v",
|
||||
@ -48,11 +48,11 @@ namespace Kyoo.Core.Models.Watch
|
||||
{
|
||||
return VideoExtensions.Contains(Path.GetExtension(filePath));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary of known subtitles extensions and the name of the subtitle codec.
|
||||
/// </summary>
|
||||
public static readonly ImmutableDictionary<string, string> SubtitleExtensions = new Dictionary<string, string>
|
||||
public static readonly ImmutableDictionary<string, string> SubtitleExtensions = new Dictionary<string, string>
|
||||
{
|
||||
{".ass", "ass"},
|
||||
{".str", "subrip"}
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Core.Models.Options
|
||||
/// The temporary folder to cache transmuxed file.
|
||||
/// </summary>
|
||||
public string TransmuxPath { get; set; } = "cached/transmux";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The temporary folder to cache transcoded file.
|
||||
/// </summary>
|
||||
|
@ -9,12 +9,12 @@ namespace Kyoo.Core.Models.Options
|
||||
/// The path of this options
|
||||
/// </summary>
|
||||
public const string Path = "Media";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A regex for episodes
|
||||
/// </summary>
|
||||
public string[] Regex { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A regex for subtitles
|
||||
/// </summary>
|
||||
|
@ -13,7 +13,7 @@ namespace Kyoo.Core.Models.Options
|
||||
/// The path of this options
|
||||
/// </summary>
|
||||
public const string Path = "Tasks";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The number of tasks that can be run concurrently.
|
||||
/// </summary>
|
||||
|
@ -14,17 +14,17 @@ namespace Kyoo.Core.Models.Watch
|
||||
/// The title of the stream.
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The language of this stream (as a ISO-639-2 language code)
|
||||
/// </summary>
|
||||
public string Language { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The codec of this stream.
|
||||
/// </summary>
|
||||
public string Codec { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Is this stream the default one of it's type?
|
||||
/// </summary>
|
||||
@ -34,12 +34,12 @@ namespace Kyoo.Core.Models.Watch
|
||||
/// Is this stream tagged as forced?
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.I1)] public bool IsForced;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The path of this track.
|
||||
/// </summary>
|
||||
[SerializeIgnore] public string Path { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The type of this stream.
|
||||
/// </summary>
|
||||
|
@ -69,7 +69,7 @@ namespace Kyoo.Core
|
||||
{
|
||||
foreach (IPlugin plugin in _plugins.GetAllPlugins())
|
||||
plugin.Configure(services);
|
||||
|
||||
|
||||
IEnumerable<KeyValuePair<string, Type>> configTypes = _plugins.GetAllPlugins()
|
||||
.SelectMany(x => x.Configuration)
|
||||
.Where(x => x.Value != null);
|
||||
@ -92,7 +92,7 @@ namespace Kyoo.Core
|
||||
{
|
||||
builder.RegisterInstance(_plugins).As<IPluginManager>().ExternallyOwned();
|
||||
builder.RegisterTask<PluginInitializer>();
|
||||
|
||||
|
||||
foreach (IPlugin plugin in _plugins.GetAllPlugins())
|
||||
plugin.Configure(builder);
|
||||
}
|
||||
@ -125,8 +125,8 @@ namespace Kyoo.Core
|
||||
foreach ((string path, Type type) in pluginConfig)
|
||||
config.Register(path, type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="PluginsStartup"/> from a webhost.
|
||||
/// This is meant to be used from <see cref="WebHostBuilderExtensions.UseStartup"/>.
|
||||
@ -136,7 +136,7 @@ namespace Kyoo.Core
|
||||
/// The logger factory used to log while the application is setting itself up.
|
||||
/// </param>
|
||||
/// <returns>A new <see cref="PluginsStartup"/>.</returns>
|
||||
public static PluginsStartup FromWebHost(WebHostBuilderContext host,
|
||||
public static PluginsStartup FromWebHost(WebHostBuilderContext host,
|
||||
ILoggerFactory logger)
|
||||
{
|
||||
HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger);
|
||||
@ -147,7 +147,7 @@ namespace Kyoo.Core
|
||||
);
|
||||
return new PluginsStartup(plugins, host.Configuration);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A simple host service provider used to activate plugins instance.
|
||||
/// The same services as a generic host are available and an <see cref="ILoggerFactory"/> has been added.
|
||||
@ -158,18 +158,18 @@ namespace Kyoo.Core
|
||||
/// The host environment that could be used by plugins to configure themself.
|
||||
/// </summary>
|
||||
private readonly IWebHostEnvironment _hostEnvironment;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The configuration context.
|
||||
/// </summary>
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A logger factory used to create a logger for the plugin manager.
|
||||
/// </summary>
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="HostServiceProvider"/> that will return given services when asked.
|
||||
/// </summary>
|
||||
|
@ -52,8 +52,8 @@ namespace Kyoo.Core.Tasks
|
||||
_taskManager = taskManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public TaskParameters GetParameters()
|
||||
{
|
||||
@ -67,9 +67,9 @@ namespace Kyoo.Core.Tasks
|
||||
public async Task Run(TaskParameters arguments, IProgress<float> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
string argument = arguments["slug"].As<string>();
|
||||
ICollection<Library> libraries = argument == null
|
||||
ICollection<Library> libraries = argument == null
|
||||
? await _libraryManager.GetAll<Library>()
|
||||
: new [] { await _libraryManager.GetOrDefault<Library>(argument)};
|
||||
: new[] { await _libraryManager.GetOrDefault<Library>(argument) };
|
||||
|
||||
if (argument != null && libraries.First() == null)
|
||||
throw new ArgumentException($"No library found with the name {argument}");
|
||||
@ -79,7 +79,7 @@ namespace Kyoo.Core.Tasks
|
||||
|
||||
progress.Report(0);
|
||||
float percent = 0;
|
||||
|
||||
|
||||
ICollection<Episode> episodes = await _libraryManager.GetAll<Episode>();
|
||||
ICollection<Track> tracks = await _libraryManager.GetAll<Track>();
|
||||
foreach (Library library in libraries)
|
||||
@ -91,15 +91,15 @@ namespace Kyoo.Core.Tasks
|
||||
});
|
||||
await Scan(library, episodes, tracks, reporter, cancellationToken);
|
||||
percent += 100f / libraries.Count;
|
||||
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private async Task Scan(Library library,
|
||||
private async Task Scan(Library library,
|
||||
IEnumerable<Episode> episodes,
|
||||
IEnumerable<Track> tracks,
|
||||
IProgress<float> progress,
|
||||
@ -109,7 +109,7 @@ namespace Kyoo.Core.Tasks
|
||||
foreach (string path in library.Paths)
|
||||
{
|
||||
ICollection<string> files = await _fileSystem.ListFiles(path, SearchOption.AllDirectories);
|
||||
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
@ -121,8 +121,8 @@ namespace Kyoo.Core.Tasks
|
||||
.Where(x => episodes.All(y => y.Path != x))
|
||||
.GroupBy(Path.GetDirectoryName)
|
||||
.ToList();
|
||||
|
||||
|
||||
|
||||
|
||||
string[] paths = shows.Select(x => x.First())
|
||||
.Concat(shows.SelectMany(x => x.Skip(1)))
|
||||
.ToArray();
|
||||
@ -132,7 +132,7 @@ namespace Kyoo.Core.Tasks
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
progress.Report((percent + x / paths.Length - 10) / library.Paths.Length);
|
||||
});
|
||||
|
||||
|
||||
foreach (string episodePath in paths)
|
||||
{
|
||||
_taskManager.StartTask<RegisterEpisode>(reporter, new Dictionary<string, object>
|
||||
@ -143,7 +143,7 @@ namespace Kyoo.Core.Tasks
|
||||
percent += 100f / paths.Length;
|
||||
}
|
||||
|
||||
|
||||
|
||||
string[] subtitles = files
|
||||
.Where(FileExtensions.IsSubtitle)
|
||||
.Where(x => !x.Contains("Extra"))
|
||||
@ -155,7 +155,7 @@ namespace Kyoo.Core.Tasks
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
progress.Report((90 + (percent + x / subtitles.Length)) / library.Paths.Length);
|
||||
});
|
||||
|
||||
|
||||
foreach (string trackPath in subtitles)
|
||||
{
|
||||
_taskManager.StartTask<RegisterSubtitle>(reporter, new Dictionary<string, object>
|
||||
|
@ -57,10 +57,10 @@ namespace Kyoo.Core.Tasks
|
||||
{
|
||||
progress.Report(count / delCount * 100);
|
||||
count++;
|
||||
|
||||
|
||||
if (await _fileSystem.Exists(show.Path))
|
||||
continue;
|
||||
_logger.LogWarning("Show {Name}'s folder has been deleted (was {Path}), removing it from kyoo",
|
||||
_logger.LogWarning("Show {Name}'s folder has been deleted (was {Path}), removing it from kyoo",
|
||||
show.Title, show.Path);
|
||||
await _libraryManager.Delete(show);
|
||||
}
|
||||
@ -69,14 +69,14 @@ namespace Kyoo.Core.Tasks
|
||||
{
|
||||
progress.Report(count / delCount * 100);
|
||||
count++;
|
||||
|
||||
|
||||
if (await _fileSystem.Exists(episode.Path))
|
||||
continue;
|
||||
_logger.LogWarning("Episode {Slug}'s file has been deleted (was {Path}), removing it from kyoo",
|
||||
_logger.LogWarning("Episode {Slug}'s file has been deleted (was {Path}), removing it from kyoo",
|
||||
episode.Slug, episode.Path);
|
||||
await _libraryManager.Delete(episode);
|
||||
}
|
||||
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ namespace Kyoo.Core.Tasks
|
||||
/// <param name="metadataProviders">
|
||||
/// The list of metadata providers to register.
|
||||
/// </param>
|
||||
public MetadataProviderLoader(IProviderRepository providers,
|
||||
public MetadataProviderLoader(IProviderRepository providers,
|
||||
IThumbnailsManager thumbnails,
|
||||
ICollection<IMetadataProvider> metadataProviders)
|
||||
{
|
||||
@ -61,7 +61,7 @@ namespace Kyoo.Core.Tasks
|
||||
{
|
||||
float percent = 0;
|
||||
progress.Report(0);
|
||||
|
||||
|
||||
foreach (IMetadataProvider provider in _metadataProviders)
|
||||
{
|
||||
if (string.IsNullOrEmpty(provider.Provider.Slug))
|
||||
|
@ -10,7 +10,7 @@ namespace Kyoo.Core.Tasks
|
||||
/// <summary>
|
||||
/// A task run on Kyoo's startup to initialize plugins
|
||||
/// </summary>
|
||||
[TaskMetadata("plugin-init", "Plugin Initializer", "A task to initialize plugins.",
|
||||
[TaskMetadata("plugin-init", "Plugin Initializer", "A task to initialize plugins.",
|
||||
RunOnStartup = true, Priority = int.MaxValue, IsHidden = true)]
|
||||
public class PluginInitializer : ITask
|
||||
{
|
||||
@ -33,14 +33,14 @@ namespace Kyoo.Core.Tasks
|
||||
_pluginManager = pluginManager;
|
||||
_provider = provider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public TaskParameters GetParameters()
|
||||
{
|
||||
return new();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Run(TaskParameters arguments, IProgress<float> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
@ -51,11 +51,11 @@ namespace Kyoo.Core.Tasks
|
||||
foreach (IPlugin plugin in plugins)
|
||||
{
|
||||
plugin.Initialize(_provider);
|
||||
|
||||
|
||||
progress.Report(count / plugins.Count * 100);
|
||||
count++;
|
||||
}
|
||||
|
||||
|
||||
progress.Report(100);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ namespace Kyoo.Core.Tasks
|
||||
TaskParameter.CreateRequired<Library>("library", "The library in witch the episode is")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Run(TaskParameters arguments, IProgress<float> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
@ -148,7 +148,7 @@ namespace Kyoo.Core.Tasks
|
||||
throw new TaskFailedException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the equivalent item if it already exists in the database,
|
||||
/// if it does not, fill metadata using the metadata provider, download images and register the item to the
|
||||
@ -172,7 +172,7 @@ namespace Kyoo.Core.Tasks
|
||||
|
||||
item = await _metadataProvider.Get(item);
|
||||
await _thumbnailsManager.DownloadImages(item);
|
||||
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case Show show when show.People != null:
|
||||
|
@ -42,7 +42,7 @@ namespace Kyoo.Core.Tasks
|
||||
TaskParameter.CreateRequired<string>("path", "The path of the subtitle file")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task Run(TaskParameters arguments, IProgress<float> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
|
@ -22,17 +22,17 @@ namespace Kyoo.Core.Api
|
||||
private readonly IFileSystem _files;
|
||||
private readonly IThumbnailsManager _thumbs;
|
||||
|
||||
public CollectionApi(ILibraryManager libraryManager,
|
||||
IFileSystem files,
|
||||
public CollectionApi(ILibraryManager libraryManager,
|
||||
IFileSystem files,
|
||||
IThumbnailsManager thumbs,
|
||||
IOptions<BasicOptions> options)
|
||||
IOptions<BasicOptions> options)
|
||||
: base(libraryManager.CollectionRepository, options.Value.PublicUrl)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
_files = files;
|
||||
_thumbs = thumbs;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{id:int}/show")]
|
||||
[HttpGet("{id:int}/shows")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -55,10 +55,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/show")]
|
||||
[HttpGet("{slug}/shows")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -81,10 +81,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{id:int}/library")]
|
||||
[HttpGet("{id:int}/libraries")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -107,10 +107,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/library")]
|
||||
[HttpGet("{slug}/libraries")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -133,10 +133,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/poster")]
|
||||
public async Task<IActionResult> GetPoster(string slug)
|
||||
{
|
||||
@ -150,7 +150,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/logo")]
|
||||
public async Task<IActionResult> GetLogo(string slug)
|
||||
{
|
||||
@ -164,7 +164,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/backdrop")]
|
||||
[HttpGet("{slug}/thumbnail")]
|
||||
public async Task<IActionResult> GetBackdrop(string slug)
|
||||
|
@ -25,7 +25,7 @@ namespace Kyoo.Core.Api
|
||||
public EpisodeApi(ILibraryManager libraryManager,
|
||||
IOptions<BasicOptions> options,
|
||||
IFileSystem files,
|
||||
IThumbnailsManager thumbnails)
|
||||
IThumbnailsManager thumbnails)
|
||||
: base(libraryManager.EpisodeRepository, options.Value.PublicUrl)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
@ -37,12 +37,12 @@ namespace Kyoo.Core.Api
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Show>> GetShow(int episodeID)
|
||||
{
|
||||
Show ret = await _libraryManager.GetOrDefault<Show>(x => x.Episodes.Any(y => y.ID == episodeID));
|
||||
Show ret = await _libraryManager.GetOrDefault<Show>(x => x.Episodes.Any(y => y.ID == episodeID));
|
||||
if (ret == null)
|
||||
return NotFound();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/show")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Show>> GetShow(string showSlug, int seasonNumber, int episodeNumber)
|
||||
@ -52,7 +52,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/show")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Show>> GetShow(int showID, int seasonNumber, int episodeNumber)
|
||||
@ -62,7 +62,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{episodeID:int}/season")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Season>> GetSeason(int episodeID)
|
||||
@ -72,7 +72,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/season")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Season>> GetSeason(string showSlug, int seasonNumber, int episodeNumber)
|
||||
@ -86,7 +86,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/season")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public async Task<ActionResult<Season>> GetSeason(int showID, int seasonNumber, int episodeNumber)
|
||||
@ -100,7 +100,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{episodeID:int}/track")]
|
||||
[HttpGet("{episodeID:int}/tracks")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -123,10 +123,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{showID:int}-s{seasonNumber:int}e{episodeNumber:int}/track")]
|
||||
[HttpGet("{showID:int}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -141,7 +141,7 @@ namespace Kyoo.Core.Api
|
||||
try
|
||||
{
|
||||
ICollection<Track> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere<Track>(where, x => x.Episode.ShowID == showID
|
||||
ApiHelper.ParseWhere<Track>(where, x => x.Episode.ShowID == showID
|
||||
&& x.Episode.SeasonNumber == seasonNumber
|
||||
&& x.Episode.EpisodeNumber == episodeNumber),
|
||||
new Sort<Track>(sortBy),
|
||||
@ -153,10 +153,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}-s{seasonNumber:int}e{episodeNumber:int}/track")]
|
||||
[HttpGet("{slug}-s{seasonNumber:int}e{episodeNumber:int}/tracks")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -171,7 +171,7 @@ namespace Kyoo.Core.Api
|
||||
try
|
||||
{
|
||||
ICollection<Track> resources = await _libraryManager.GetAll(
|
||||
ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == slug
|
||||
ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == slug
|
||||
&& x.Episode.SeasonNumber == seasonNumber
|
||||
&& x.Episode.EpisodeNumber == episodeNumber),
|
||||
new Sort<Track>(sortBy),
|
||||
@ -183,10 +183,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{id:int}/thumbnail")]
|
||||
[HttpGet("{id:int}/backdrop")]
|
||||
public async Task<IActionResult> GetThumb(int id)
|
||||
@ -201,7 +201,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/thumbnail")]
|
||||
[HttpGet("{slug}/backdrop")]
|
||||
public async Task<IActionResult> GetThumb(string slug)
|
||||
@ -217,4 +217,4 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace Kyoo.Core.Api
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{id:int}/show")]
|
||||
[HttpGet("{id:int}/shows")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -47,10 +47,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{slug}/show")]
|
||||
[HttpGet("{slug}/shows")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
@ -73,7 +73,7 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
return operand(left, right);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> ParseWhere<T>(Dictionary<string, string> where,
|
||||
|
||||
public static Expression<Func<T, bool>> ParseWhere<T>(Dictionary<string, string> where,
|
||||
Expression<Func<T, bool>> defaultWhere = null)
|
||||
{
|
||||
if (where == null || where.Count == 0)
|
||||
@ -35,7 +35,7 @@ namespace Kyoo.Core.Api
|
||||
{
|
||||
if (key == null || desired == null)
|
||||
throw new ArgumentException("Invalid key/value pair. Can't be null.");
|
||||
|
||||
|
||||
string value = desired;
|
||||
string operand = "eq";
|
||||
if (desired.Contains(':'))
|
||||
@ -68,15 +68,15 @@ namespace Kyoo.Core.Api
|
||||
|
||||
valueExpr = Expression.Constant(val, property.PropertyType);
|
||||
}
|
||||
|
||||
|
||||
Expression condition = operand switch
|
||||
{
|
||||
"eq" when isList => ContainsResourceExpression(propertyExpr, value),
|
||||
"ctn" => ContainsResourceExpression(propertyExpr, value),
|
||||
|
||||
|
||||
"eq" when valueExpr == null => ResourceEqual(propertyExpr, value),
|
||||
"not" when valueExpr == null => ResourceEqual(propertyExpr, value, true),
|
||||
|
||||
|
||||
"eq" => Expression.Equal(propertyExpr, valueExpr),
|
||||
"not" => Expression.NotEqual(propertyExpr, valueExpr!),
|
||||
"lt" => StringCompatibleExpression(Expression.LessThan, propertyExpr, valueExpr),
|
||||
@ -110,11 +110,11 @@ namespace Kyoo.Core.Api
|
||||
valueConst = Expression.Constant(value);
|
||||
}
|
||||
|
||||
return notEqual
|
||||
? Expression.NotEqual(field, valueConst)
|
||||
return notEqual
|
||||
? Expression.NotEqual(field, valueConst)
|
||||
: Expression.Equal(field, valueConst);
|
||||
}
|
||||
|
||||
|
||||
private static Expression ContainsResourceExpression(MemberExpression xProperty, string value)
|
||||
{
|
||||
// x => x.PROPERTY.Any(y => y.Slug == value)
|
||||
|
@ -54,10 +54,10 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[PartialPermission(Kind.Read)]
|
||||
public virtual async Task<ActionResult<Page<T>>> GetAll([FromQuery] string sortBy,
|
||||
@ -75,7 +75,7 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +98,7 @@ namespace Kyoo.Core.Api
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new {Error = ex.Message});
|
||||
return BadRequest(new { Error = ex.Message });
|
||||
}
|
||||
catch (DuplicatedItemException)
|
||||
{
|
||||
@ -106,7 +106,7 @@ namespace Kyoo.Core.Api
|
||||
return Conflict(existing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpPut]
|
||||
[PartialPermission(Kind.Write)]
|
||||
public virtual async Task<ActionResult<T>> Edit([FromQuery] bool resetOld, [FromBody] T resource)
|
||||
@ -140,7 +140,7 @@ namespace Kyoo.Core.Api
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("{slug}")]
|
||||
[PartialPermission(Kind.Write)]
|
||||
public virtual async Task<ActionResult<T>> Edit(string slug, [FromQuery] bool resetOld, [FromBody] T resource)
|
||||
@ -172,7 +172,7 @@ namespace Kyoo.Core.Api
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{slug}")]
|
||||
[PartialPermission(Kind.Delete)]
|
||||
public virtual async Task<IActionResult> Delete(string slug)
|
||||
@ -188,7 +188,7 @@ namespace Kyoo.Core.Api
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
[PartialPermission(Kind.Delete)]
|
||||
public virtual async Task<IActionResult> Delete(Dictionary<string, string> where)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace Kyoo.Core.Api
|
||||
value.Show.People = null;
|
||||
if (value.People != null)
|
||||
value.People.Roles = null;
|
||||
|
||||
|
||||
JObject obj = JObject.FromObject((value.ForPeople ? value.People : value.Show)!, serializer);
|
||||
obj.Add("role", value.Role);
|
||||
obj.Add("type", value.Type);
|
||||
@ -93,7 +93,7 @@ namespace Kyoo.Core.Api
|
||||
value.People.Roles = oldRoles;
|
||||
}
|
||||
|
||||
public override PeopleRole ReadJson(JsonReader reader,
|
||||
public override PeopleRole ReadJson(JsonReader reader,
|
||||
Type objectType,
|
||||
PeopleRole existingValue,
|
||||
bool hasExistingValue,
|
||||
@ -113,7 +113,7 @@ namespace Kyoo.Core.Api
|
||||
_format = format;
|
||||
_host = host.TrimEnd('/');
|
||||
}
|
||||
|
||||
|
||||
public object GetValue(object target)
|
||||
{
|
||||
return Regex.Replace(_format, @"(?<!{){(\w+)(:(\w+))?}", x =>
|
||||
@ -123,7 +123,7 @@ namespace Kyoo.Core.Api
|
||||
|
||||
if (value == "HOST")
|
||||
return _host;
|
||||
|
||||
|
||||
PropertyInfo properties = target.GetType()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.FirstOrDefault(y => y.Name == value);
|
||||
@ -147,7 +147,7 @@ namespace Kyoo.Core.Api
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
// Values are ignored and should not be editable, except if the internal value is set.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user