Reworking the LibraryManager's interface

This commit is contained in:
Zoe Roux 2021-04-18 02:17:15 +02:00
parent 5f1b45b207
commit 7dbb84780c
33 changed files with 1008 additions and 1067 deletions

View File

@ -5,284 +5,454 @@ using System.Runtime.InteropServices;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
namespace Kyoo.Controllers
{
/// <summary>
/// An interface to interract with the database. Every repository is mapped through here.
/// </summary>
public interface ILibraryManager : IDisposable, IAsyncDisposable
{
// Repositories
/// <summary>
/// Get the repository corresponding to the T item.
/// </summary>
/// <typeparam name="T">The type you want</typeparam>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The repository corresponding</returns>
IRepository<T> GetRepository<T>() where T : class, IResource;
/// <summary>
/// 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; }
// Get by id
Task<Library> GetLibrary(int id);
Task<Collection> GetCollection(int id);
Task<Show> GetShow(int id);
Task<Season> GetSeason(int id);
Task<Season> GetSeason(int showID, int seasonNumber);
Task<Episode> GetEpisode(int id);
Task<Episode> GetEpisode(int showID, int seasonNumber, int episodeNumber);
Task<Genre> GetGenre(int id);
Task<Track> GetTrack(int id);
Task<Studio> GetStudio(int id);
Task<People> GetPeople(int id);
Task<ProviderID> GetProvider(int id);
/// <summary>
/// Get the resource by it's ID
/// </summary>
/// <param name="id">The id of the resource</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The resource found</returns>
Task<T> Get<T>(int id) where T : class, IResource;
// Get by slug
Task<Library> GetLibrary(string slug);
Task<Collection> GetCollection(string slug);
Task<Show> GetShow(string slug);
Task<Season> GetSeason(string slug);
Task<Season> GetSeason(string showSlug, int seasonNumber);
Task<Episode> GetEpisode(string slug);
Task<Episode> GetEpisode(string showSlug, int seasonNumber, int episodeNumber);
Task<Episode> GetMovieEpisode(string movieSlug);
/// <summary>
/// Get the resource by it's slug
/// </summary>
/// <param name="slug">The slug of the resource</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The resource found</returns>
Task<T> Get<T>(string slug) where T : class, IResource;
/// <summary>
/// Get the resource by a filter function.
/// </summary>
/// <param name="where">The filter function.</param>
/// <typeparam name="T">The type of the resource</typeparam>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The first resource found that match the where function</returns>
Task<T> Get<T>(Expression<Func<T, bool>> where) where T : class, IResource;
/// <summary>
/// Get a season from it's showID and it's seasonNumber
/// </summary>
/// <param name="showID">The id of the show</param>
/// <param name="seasonNumber">The season's number</param>
/// <exception cref="ItemNotFound">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>
/// <param name="showSlug">The slug of the show</param>
/// <param name="seasonNumber">The season's number</param>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The season found</returns>
Task<Season> Get(string showSlug, int seasonNumber);
/// <summary>
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
/// </summary>
/// <param name="showID">The id of the show</param>
/// <param name="seasonNumber">The season's number</param>
/// <param name="episodeNumber">The episode's number</param>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The episode found</returns>
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>
/// <param name="showSlug">The slug of the show</param>
/// <param name="seasonNumber">The season's number</param>
/// <param name="episodeNumber">The episode's number</param>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The episode found</returns>
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
/// <summary>
/// Get a tracck from it's slug and it's type.
/// </summary>
/// <param name="slug">The slug of the track</param>
/// <param name="type">The type (Video, Audio or Subtitle)</param>
/// <exception cref="ItemNotFound">If the item is not found</exception>
/// <returns>The tracl found</returns>
Task<Track> GetTrack(string slug, StreamType type = StreamType.Unknown);
Task<Genre> GetGenre(string slug);
Task<Studio> GetStudio(string slug);
Task<People> GetPeople(string slug);
Task<ProviderID> GetProvider(string slug);
// Get by predicate
Task<Library> GetLibrary(Expression<Func<Library, bool>> where);
Task<Collection> GetCollection(Expression<Func<Collection, bool>> where);
Task<Show> GetShow(Expression<Func<Show, bool>> where);
Task<Season> GetSeason(Expression<Func<Season, bool>> where);
Task<Episode> GetEpisode(Expression<Func<Episode, bool>> where);
Task<Track> GetTrack(Expression<Func<Track, bool>> where);
Task<Genre> GetGenre(Expression<Func<Genre, bool>> where);
Task<Studio> GetStudio(Expression<Func<Studio, bool>> where);
Task<People> GetPerson(Expression<Func<People, bool>> where);
/// <summary>
/// Load a related resource
/// </summary>
/// <param name="obj">The source object.</param>
/// <param name="member">A getter function for the member to load</param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <typeparam name="T2">The related resource's type</typeparam>
/// <returns>The param <see cref="obj"/></returns>
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, T2>> member)
where T : class, IResource
where T2 : class, IResource, new();
/// <summary>
/// Load a collection of related resource
/// </summary>
/// <param name="obj">The source object.</param>
/// <param name="member">A getter function for the member to load</param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <typeparam name="T2">The related resource's type</typeparam>
/// <returns>The param <see cref="obj"/></returns>
Task<T> Load<T, T2>([NotNull] T obj, Expression<Func<T, ICollection<T2>>> member)
where T : class, IResource
where T2 : class, new();
/// <summary>
/// Load a related resource by it's name
/// </summary>
/// <param name="obj">The source object.</param>
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
/// <typeparam name="T">The type of the source object</typeparam>
/// <returns>The param <see cref="obj"/></returns>
Task<T> Load<T>([NotNull] T obj, string memberName)
where T : class, IResource;
/// <summary>
/// Load a related resource without specifing it's type.
/// </summary>
/// <param name="obj">The source object.</param>
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
Task Load([NotNull] IResource obj, string memberName);
// Library Items relations
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// </summary>
/// <param name="id">The ID of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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<LibraryItem>> GetItemsFromLibrary(int id,
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>
/// <param name="id">The ID of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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<LibraryItem>> GetItemsFromLibrary(int id,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// </summary>
/// <param name="slug">The slug of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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<LibraryItem>> GetItemsFromLibrary(string slug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
/// <summary>
/// Get items (A wrapper arround shows or collections) from a library.
/// </summary>
/// <param name="slug">The slug of the library</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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<LibraryItem>> GetItemsFromLibrary(string slug,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetItemsFromLibrary(librarySlug, where, new Sort<LibraryItem>(sort), limit);
) => GetItemsFromLibrary(slug, where, new Sort<LibraryItem>(sort), limit);
// People Role relations
/// <summary>
/// Get people's roles from a show.
/// </summary>
/// <param name="showID">The ID of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a show.
/// </summary>
/// <param name="showID">The ID of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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,
[Optional] Expression<Func<PeopleRole, bool>> where,
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>
/// <param name="showSlug">The slug of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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,
Sort<PeopleRole> sort = default,
Pagination limit = default);
/// <summary>
/// Get people's roles from a show.
/// </summary>
/// <param name="showSlug">The slug of the show</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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,
[Optional] Expression<Func<PeopleRole, bool>> where,
Expression<Func<PeopleRole, object>> sort,
Pagination limit = default
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleRole>(sort), limit);
// Show Role relations
Task<ICollection<PeopleRole>> GetRolesFromPeople(int showID,
/// <summary>
/// Get people's roles from a person.
/// </summary>
/// <param name="id">The id of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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,
Sort<PeopleRole> sort = default,
Pagination limit = default);
Task<ICollection<PeopleRole>> GetRolesFromPeople(int showID,
/// <summary>
/// Get people's roles from a person.
/// </summary>
/// <param name="id">The id of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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,
[Optional] Expression<Func<PeopleRole, bool>> where,
Expression<Func<PeopleRole, object>> sort,
Pagination limit = default
) => GetRolesFromPeople(showID, where, new Sort<PeopleRole>(sort), limit);
) => GetRolesFromPeople(id, where, new Sort<PeopleRole>(sort), limit);
Task<ICollection<PeopleRole>> GetRolesFromPeople(string showSlug,
/// <summary>
/// Get people's roles from a person.
/// </summary>
/// <param name="slug">The slug of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <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,
Sort<PeopleRole> sort = default,
Pagination limit = default);
Task<ICollection<PeopleRole>> GetRolesFromPeople(string showSlug,
/// <summary>
/// Get people's roles from a person.
/// </summary>
/// <param name="slug">The slug of the person</param>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by method</param>
/// <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,
[Optional] Expression<Func<PeopleRole, bool>> where,
Expression<Func<PeopleRole, object>> sort,
Pagination limit = default
) => GetRolesFromPeople(showSlug, where, new Sort<PeopleRole>(sort), limit);
) => GetRolesFromPeople(slug, where, new Sort<PeopleRole>(sort), limit);
// Helpers
/// <summary>
/// Setup relations between a show, a library and a collection
/// </summary>
/// <param name="showID">The show's ID to setup relations with</param>
/// <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>
/// <param name="show">The show to setup relations with</param>
/// <param name="library">The library to setup relations with (optional)</param>
/// <param name="collection">The collection to setup relations with (optional)</param>
Task AddShowLink([NotNull] Show show, Library library, Collection collection);
// Get all
Task<ICollection<Library>> GetLibraries(Expression<Func<Library, bool>> where = null,
Sort<Library> sort = default,
Pagination limit = default);
Task<ICollection<Collection>> GetCollections(Expression<Func<Collection, bool>> where = null,
Sort<Collection> sort = default,
Pagination limit = default);
Task<ICollection<Show>> GetShows(Expression<Func<Show, bool>> where = null,
Sort<Show> sort = default,
Pagination limit = default);
Task<ICollection<Season>> GetSeasons(Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default,
Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default,
Pagination limit = default);
Task<ICollection<Track>> GetTracks(Expression<Func<Track, bool>> where = null,
Sort<Track> sort = default,
Pagination limit = default);
Task<ICollection<Studio>> GetStudios(Expression<Func<Studio, bool>> where = null,
Sort<Studio> sort = default,
Pagination limit = default);
Task<ICollection<People>> GetPeople(Expression<Func<People, bool>> where = null,
Sort<People> sort = default,
Pagination limit = default);
Task<ICollection<Genre>> GetGenres(Expression<Func<Genre, bool>> where = null,
Sort<Genre> sort = default,
Pagination limit = default);
Task<ICollection<ProviderID>> GetProviders(Expression<Func<ProviderID, bool>> where = null,
Sort<ProviderID> sort = default,
Pagination limit = default);
/// <summary>
/// Get all resources with filters
/// </summary>
/// <param name="where">A filter function</param>
/// <param name="sort">Sort informations (sort order & sort by)</param>
/// <param name="limit">How many items to return and where to start</param>
/// <typeparam name="T">The type of resources to load</typeparam>
/// <returns>A list of resources that match every filters</returns>
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default) where T : class, IResource;
Task<ICollection<Library>> GetLibraries([Optional] Expression<Func<Library, bool>> where,
Expression<Func<Library, object>> sort,
Pagination limit = default
) => GetLibraries(where, new Sort<Library>(sort), limit);
Task<ICollection<Collection>> GetCollections([Optional] Expression<Func<Collection, bool>> where,
Expression<Func<Collection, object>> sort,
Pagination limit = default
) => GetCollections(where, new Sort<Collection>(sort), limit);
Task<ICollection<Show>> GetShows([Optional] Expression<Func<Show, bool>> where,
Expression<Func<Show, object>> sort,
Pagination limit = default
) => GetShows(where, new Sort<Show>(sort), limit);
Task<ICollection<Track>> GetTracks([Optional] Expression<Func<Track, bool>> where,
Expression<Func<Track, object>> sort,
Pagination limit = default
) => GetTracks(where, new Sort<Track>(sort), limit);
Task<ICollection<Studio>> GetStudios([Optional] Expression<Func<Studio, bool>> where,
Expression<Func<Studio, object>> sort,
Pagination limit = default
) => GetStudios(where, new Sort<Studio>(sort), limit);
Task<ICollection<People>> GetPeople([Optional] Expression<Func<People, bool>> where,
Expression<Func<People, object>> sort,
Pagination limit = default
) => GetPeople(where, new Sort<People>(sort), limit);
Task<ICollection<Genre>> GetGenres([Optional] Expression<Func<Genre, bool>> where,
Expression<Func<Genre, object>> sort,
Pagination limit = default
) => GetGenres(where, new Sort<Genre>(sort), limit);
Task<ICollection<ProviderID>> GetProviders([Optional] Expression<Func<ProviderID, bool>> where,
Expression<Func<ProviderID, object>> sort,
Pagination limit = default
) => GetProviders(where, new Sort<ProviderID>(sort), limit);
/// <summary>
/// Get all resources with filters
/// </summary>
/// <param name="where">A filter function</param>
/// <param name="sort">A sort by function</param>
/// <param name="limit">How many items to return and where to start</param>
/// <typeparam name="T">The type of resources to load</typeparam>
/// <returns>A list of resources that match every filters</returns>
Task<ICollection<T>> GetAll<T>([Optional] Expression<Func<T, bool>> where,
Expression<Func<T, object>> sort,
Pagination limit = default) where T : class, IResource
{
return GetAll(where, new Sort<T>(sort), limit);
}
/// <summary>
/// Get the count of resources that match the filter
/// </summary>
/// <param name="where">A filter function</param>
/// <typeparam name="T">The type of resources to load</typeparam>
/// <returns>A list of resources that match every filters</returns>
Task<int> GetCount<T>(Expression<Func<T, bool>> where = null) where T : class, IResource;
// Counts
Task<int> GetLibrariesCount(Expression<Func<Library, bool>> where = null);
Task<int> GetCollectionsCount(Expression<Func<Collection, bool>> where = null);
Task<int> GetShowsCount(Expression<Func<Show, bool>> where = null);
Task<int> GetSeasonsCount(Expression<Func<Season, bool>> where = null);
Task<int> GetEpisodesCount(Expression<Func<Episode, bool>> where = null);
Task<int> GetTracksCount(Expression<Func<Track, bool>> where = null);
Task<int> GetGenresCount(Expression<Func<Genre, bool>> where = null);
Task<int> GetStudiosCount(Expression<Func<Studio, bool>> where = null);
Task<int> GetPeopleCount(Expression<Func<People, bool>> where = null);
/// <summary>
/// Search for a resource
/// </summary>
/// <param name="query">The search query</param>
/// <typeparam name="T">The type of resources</typeparam>
/// <returns>A list of 20 items that match the search query</returns>
Task<ICollection<T>> Search<T>(string query) where T : class, IResource;
// Search
Task<ICollection<Library>> SearchLibraries(string searchQuery);
Task<ICollection<Collection>> SearchCollections(string searchQuery);
Task<ICollection<Show>> SearchShows(string searchQuery);
Task<ICollection<Season>> SearchSeasons(string searchQuery);
Task<ICollection<Episode>> SearchEpisodes(string searchQuery);
Task<ICollection<Genre>> SearchGenres(string searchQuery);
Task<ICollection<Studio>> SearchStudios(string searchQuery);
Task<ICollection<People>> SearchPeople(string searchQuery);
/// <summary>
/// Create a new resource.
/// </summary>
/// <param name="item">The item to register</param>
/// <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>(T item) where T : class, IResource;
//Register values
Task<Library> RegisterLibrary(Library library);
Task<Collection> RegisterCollection(Collection collection);
Task<Show> RegisterShow(Show show);
Task<Season> RegisterSeason(Season season);
Task<Episode> RegisterEpisode(Episode episode);
Task<Track> RegisterTrack(Track track);
Task<Genre> RegisterGenre(Genre genre);
Task<Studio> RegisterStudio(Studio studio);
Task<People> RegisterPeople(People people);
/// <summary>
/// Edit a resource
/// </summary>
/// <param name="item">The resourcce to edit, it's ID can't change.</param>
/// <param name="resetOld">Should old properties of the resource be discarded or should null values considered as not changed?</param>
/// <typeparam name="T">The type of resources</typeparam>
/// <returns>The resource edited and completed by database's informations (related items & so on)</returns>
Task<T> Edit<T>(T item, bool resetOld) where T : class, IResource;
// Edit values
Task<Library> EditLibrary(Library library, bool resetOld);
Task<Collection> EditCollection(Collection collection, bool resetOld);
Task<Show> EditShow(Show show, bool resetOld);
Task<Season> EditSeason(Season season, bool resetOld);
Task<Episode> EditEpisode(Episode episode, bool resetOld);
Task<Track> EditTrack(Track track, bool resetOld);
Task<Genre> EditGenre(Genre genre, bool resetOld);
Task<Studio> EditStudio(Studio studio, bool resetOld);
Task<People> EditPeople(People people, bool resetOld);
/// <summary>
/// Delete a resource.
/// </summary>
/// <param name="item">The resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
Task Delete<T>(T item) where T : class, IResource;
// Delete values
Task DeleteLibrary(Library library);
Task DeleteCollection(Collection collection);
Task DeleteShow(Show show);
Task DeleteSeason(Season season);
Task DeleteEpisode(Episode episode);
Task DeleteTrack(Track track);
Task DeleteGenre(Genre genre);
Task DeleteStudio(Studio studio);
Task DeletePeople(People people);
/// <summary>
/// Delete a resource by it's ID.
/// </summary>
/// <param name="id">The id of the resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
Task Delete<T>(int id) where T : class, IResource;
//Delete by slug
Task DeleteLibrary(string slug);
Task DeleteCollection(string slug);
Task DeleteShow(string slug);
Task DeleteSeason(string slug);
Task DeleteEpisode(string slug);
Task DeleteTrack(string slug);
Task DeleteGenre(string slug);
Task DeleteStudio(string slug);
Task DeletePeople(string slug);
//Delete by id
Task DeleteLibrary(int id);
Task DeleteCollection(int id);
Task DeleteShow(int id);
Task DeleteSeason(int id);
Task DeleteEpisode(int id);
Task DeleteTrack(int id);
Task DeleteGenre(int id);
Task DeleteStudio(int id);
Task DeletePeople(int id);
/// <summary>
/// Delete a resource by it's slug.
/// </summary>
/// <param name="slug">The slug of the resource to delete</param>
/// <typeparam name="T">The type of resource to delete</typeparam>
Task Delete<T>(string slug) where T : class, IResource;
}
}

View File

@ -6,7 +6,7 @@ namespace Kyoo.Controllers
{
public interface IMetadataProvider
{
ProviderID Provider { get; }
Provider Provider { get; }
Task<Collection> GetCollectionFromName(string name);

View File

@ -23,10 +23,10 @@ namespace Kyoo.Controllers
public static implicit operator Pagination(int limit) => new(limit);
}
public struct Sort<T>
public readonly struct Sort<T>
{
public Expression<Func<T, object>> Key;
public bool Descendant;
public Expression<Func<T, object>> Key { get; }
public bool Descendant { get; }
public Sort(Expression<Func<T, object>> key, bool descendant = false)
{
@ -46,8 +46,8 @@ namespace Kyoo.Controllers
return;
}
string key = sortBy.Contains(':') ? sortBy.Substring(0, sortBy.IndexOf(':')) : sortBy;
string order = sortBy.Contains(':') ? sortBy.Substring(sortBy.IndexOf(':') + 1) : null;
string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
ParameterExpression param = Expression.Parameter(typeof(T), "x");
MemberExpression property = Expression.Property(param, key);
@ -65,7 +65,12 @@ namespace Kyoo.Controllers
}
}
public interface IRepository<T> : IDisposable, IAsyncDisposable where T : class, IResource
public interface IBaseRepository : IDisposable, IAsyncDisposable
{
Type RepositoryType { get; }
}
public interface IRepository<T> : IBaseRepository where T : class, IResource
{
Task<T> Get(int id);
Task<T> Get(string slug);
@ -204,7 +209,7 @@ namespace Kyoo.Controllers
) => GetFromPeople(showSlug, where, new Sort<PeopleRole>(sort), limit);
}
public interface IProviderRepository : IRepository<ProviderID>
public interface IProviderRepository : IRepository<Provider>
{
Task<ICollection<MetadataID>> GetMetadataID(Expression<Func<MetadataID, bool>> where = null,
Sort<MetadataID> sort = default,

View File

@ -11,7 +11,7 @@ namespace Kyoo.Controllers
Task Validate(Season season, bool alwaysDownload = false);
Task Validate(Episode episode, bool alwaysDownload = false);
Task Validate(People actors, bool alwaysDownload = false);
Task Validate(ProviderID actors, bool alwaysDownload = false);
Task Validate(Provider actors, bool alwaysDownload = false);
Task<string> GetShowPoster([NotNull] Show show);
Task<string> GetShowLogo([NotNull] Show show);
@ -19,6 +19,6 @@ namespace Kyoo.Controllers
Task<string> GetSeasonPoster([NotNull] Season season);
Task<string> GetEpisodeThumb([NotNull] Episode episode);
Task<string> GetPeoplePoster([NotNull] People people);
Task<string> GetProviderLogo([NotNull] ProviderID provider);
Task<string> GetProviderLogo([NotNull] Provider provider);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ namespace Kyoo.Models
{
[SerializeIgnore] public int ID { get; set; }
[SerializeIgnore] public int ProviderID { get; set; }
public virtual ProviderID Provider {get; set; }
public virtual Provider Provider {get; set; }
[SerializeIgnore] public int? ShowID { get; set; }
[SerializeIgnore] public virtual Show Show { get; set; }
@ -25,7 +25,7 @@ namespace Kyoo.Models
public MetadataID() { }
public MetadataID(ProviderID provider, string dataID, string link)
public MetadataID(Provider provider, string dataID, string link)
{
Provider = provider;
DataID = dataID;

View File

@ -11,20 +11,20 @@ namespace Kyoo.Models
public string Name { get; set; }
public string[] Paths { get; set; }
[EditableRelation] [LoadableRelation] public virtual ICollection<ProviderID> Providers { get; set; }
[EditableRelation] [LoadableRelation] public virtual ICollection<Provider> Providers { get; set; }
[LoadableRelation] public virtual ICollection<Show> Shows { get; set; }
[LoadableRelation] public virtual ICollection<Collection> Collections { get; set; }
#if ENABLE_INTERNAL_LINKS
[SerializeIgnore] public virtual ICollection<Link<Library, ProviderID>> ProviderLinks { get; set; }
[SerializeIgnore] public virtual ICollection<Link<Library, Provider>> ProviderLinks { get; set; }
[SerializeIgnore] public virtual ICollection<Link<Library, Show>> ShowLinks { get; set; }
[SerializeIgnore] public virtual ICollection<Link<Library, Collection>> CollectionLinks { get; set; }
#endif
public Library() { }
public Library(string slug, string name, IEnumerable<string> paths, IEnumerable<ProviderID> providers)
public Library(string slug, string name, IEnumerable<string> paths, IEnumerable<Provider> providers)
{
Slug = slug;
Name = name;

View File

@ -3,7 +3,7 @@ using Kyoo.Models.Attributes;
namespace Kyoo.Models
{
public class ProviderID : IResource
public class Provider : IResource
{
public int ID { get; set; }
public string Slug { get; set; }
@ -13,20 +13,20 @@ namespace Kyoo.Models
[LoadableRelation] public virtual ICollection<Library> Libraries { get; set; }
#if ENABLE_INTERNAL_LINKS
[SerializeIgnore] public virtual ICollection<Link<Library, ProviderID>> LibraryLinks { get; set; }
[SerializeIgnore] public virtual ICollection<Link<Library, Provider>> LibraryLinks { get; set; }
[SerializeIgnore] public virtual ICollection<MetadataID> MetadataLinks { get; set; }
#endif
public ProviderID() { }
public Provider() { }
public ProviderID(string name, string logo)
public Provider(string name, string logo)
{
Slug = Utility.ToSlug(name);
Name = name;
Logo = logo;
}
public ProviderID(int id, string name, string logo)
public Provider(int id, string name, string logo)
{
ID = id;
Slug = Utility.ToSlug(name);

View File

@ -109,18 +109,18 @@ namespace Kyoo.Models
if (!ep.Show.IsMovie)
{
if (ep.EpisodeNumber > 1)
previous = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1);
previous = await library.Get(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1);
else if (ep.SeasonNumber > 1)
{
int count = await library.GetEpisodesCount(x => x.ShowID == ep.ShowID
int count = await library.GetCount<Episode>(x => x.ShowID == ep.ShowID
&& x.SeasonNumber == ep.SeasonNumber - 1);
previous = await library.GetEpisode(ep.ShowID, ep.SeasonNumber - 1, count);
previous = await library.Get(ep.ShowID, ep.SeasonNumber - 1, count);
}
if (ep.EpisodeNumber >= await library.GetEpisodesCount(x => x.SeasonID == ep.SeasonID))
next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber + 1, 1);
if (ep.EpisodeNumber >= await library.GetCount<Episode>(x => x.SeasonID == ep.SeasonID))
next = await library.Get(ep.ShowID, ep.SeasonNumber + 1, 1);
else
next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1);
next = await library.Get(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1);
}
return new WatchItem(ep.ID,

View File

@ -25,6 +25,8 @@ namespace Kyoo.Controllers
Database = database;
}
public Type RepositoryType => typeof(T);
public virtual void Dispose()
{
Database.Dispose();

@ -1 +1 @@
Subproject commit ddf3337acb766ae9e0987044ae38130d94fe60ad
Subproject commit da35a725a3e47db0994a697595aec4a10a4886e3

View File

@ -8,10 +8,10 @@ using Microsoft.EntityFrameworkCore;
namespace Kyoo.Controllers
{
public class ProviderRepository : LocalRepository<ProviderID>, IProviderRepository
public class ProviderRepository : LocalRepository<Provider>, IProviderRepository
{
private readonly DatabaseContext _database;
protected override Expression<Func<ProviderID, object>> DefaultSort => x => x.Slug;
protected override Expression<Func<Provider, object>> DefaultSort => x => x.Slug;
public ProviderRepository(DatabaseContext database) : base(database)
@ -19,7 +19,7 @@ namespace Kyoo.Controllers
_database = database;
}
public override async Task<ICollection<ProviderID>> Search(string query)
public override async Task<ICollection<Provider>> Search(string query)
{
return await _database.Providers
.Where(x => EF.Functions.ILike(x.Name, $"%{query}%"))
@ -28,7 +28,7 @@ namespace Kyoo.Controllers
.ToListAsync();
}
public override async Task<ProviderID> Create(ProviderID obj)
public override async Task<Provider> Create(Provider obj)
{
await base.Create(obj);
_database.Entry(obj).State = EntityState.Added;
@ -36,7 +36,7 @@ namespace Kyoo.Controllers
return obj;
}
public override async Task Delete(ProviderID obj)
public override async Task Delete(Provider obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));

View File

@ -92,7 +92,7 @@ namespace Kyoo.Controllers
await DownloadImage(episode.Thumb, localPath, $"The thumbnail of {episode.Slug}");
}
public async Task Validate(ProviderID provider, bool alwaysDownload)
public async Task Validate(Provider provider, bool alwaysDownload)
{
if (provider.Logo == null)
return;
@ -145,7 +145,7 @@ namespace Kyoo.Controllers
return Task.FromResult(thumbPath.StartsWith(_peoplePath) ? thumbPath : null);
}
public Task<string> GetProviderLogo(ProviderID provider)
public Task<string> GetProviderLogo(Provider provider)
{
if (provider == null)
throw new ArgumentNullException(nameof(provider));

View File

@ -27,7 +27,7 @@ namespace Kyoo
public DbSet<Genre> Genres { get; set; }
public DbSet<People> People { get; set; }
public DbSet<Studio> Studios { get; set; }
public DbSet<ProviderID> Providers { get; set; }
public DbSet<Provider> Providers { get; set; }
public DbSet<MetadataID> MetadataIds { get; set; }
public DbSet<PeopleRole> PeopleRoles { get; set; }
@ -74,17 +74,17 @@ namespace Kyoo
.Property(t => t.IsForced)
.ValueGeneratedNever();
modelBuilder.Entity<ProviderID>()
modelBuilder.Entity<Provider>()
.HasMany(x => x.Libraries)
.WithMany(x => x.Providers)
.UsingEntity<Link<Library, ProviderID>>(
.UsingEntity<Link<Library, Provider>>(
y => y
.HasOne(x => x.First)
.WithMany(x => x.ProviderLinks),
y => y
.HasOne(x => x.Second)
.WithMany(x => x.LibraryLinks),
y => y.HasKey(Link<Library, ProviderID>.PrimaryKey));
y => y.HasKey(Link<Library, Provider>.PrimaryKey));
modelBuilder.Entity<Collection>()
.HasMany(x => x.Libraries)
@ -160,7 +160,7 @@ namespace Kyoo
modelBuilder.Entity<Genre>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<Library>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<People>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<ProviderID>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<Provider>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<Show>().Property(x => x.Slug).IsRequired();
modelBuilder.Entity<Studio>().Property(x => x.Slug).IsRequired();
@ -182,7 +182,7 @@ namespace Kyoo
modelBuilder.Entity<Studio>()
.HasIndex(x => x.Slug)
.IsUnique();
modelBuilder.Entity<ProviderID>()
modelBuilder.Entity<Provider>()
.HasIndex(x => x.Slug)
.IsUnique();
modelBuilder.Entity<Season>()

View File

@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.Internal
{
[DbContext(typeof(DatabaseContext))]
[Migration("20210325184215_Initial")]
[Migration("20210417232515_Initial")]
partial class Initial
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -179,7 +179,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.ToTable("Link<Library, Collection>");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.ProviderID>", b =>
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Provider>", b =>
{
b.Property<int>("FirstID")
.HasColumnType("integer");
@ -191,7 +191,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("SecondID");
b.ToTable("Link<Library, ProviderID>");
b.ToTable("Link<Library, Provider>");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Show>", b =>
@ -320,7 +320,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.ToTable("PeopleRoles");
});
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
modelBuilder.Entity("Kyoo.Models.Provider", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
@ -563,7 +563,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Navigation("Second");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.ProviderID>", b =>
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Provider>", b =>
{
b.HasOne("Kyoo.Models.Library", "First")
.WithMany("ProviderLinks")
@ -571,7 +571,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Kyoo.Models.ProviderID", "Second")
b.HasOne("Kyoo.Models.Provider", "Second")
.WithMany("LibraryLinks")
.HasForeignKey("SecondID")
.OnDelete(DeleteBehavior.Cascade)
@ -632,7 +632,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasForeignKey("PeopleID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Kyoo.Models.ProviderID", "Provider")
b.HasOne("Kyoo.Models.Provider", "Provider")
.WithMany("MetadataLinks")
.HasForeignKey("ProviderID")
.OnDelete(DeleteBehavior.Cascade)
@ -744,7 +744,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Navigation("Roles");
});
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
modelBuilder.Entity("Kyoo.Models.Provider", b =>
{
b.Navigation("LibraryLinks");

View File

@ -128,7 +128,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
});
migrationBuilder.CreateTable(
name: "Link<Library, ProviderID>",
name: "Link<Library, Provider>",
columns: table => new
{
FirstID = table.Column<int>(type: "integer", nullable: false),
@ -136,15 +136,15 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
},
constraints: table =>
{
table.PrimaryKey("PK_Link<Library, ProviderID>", x => new { x.FirstID, x.SecondID });
table.PrimaryKey("PK_Link<Library, Provider>", x => new { x.FirstID, x.SecondID });
table.ForeignKey(
name: "FK_Link<Library, ProviderID>_Libraries_FirstID",
name: "FK_Link<Library, Provider>_Libraries_FirstID",
column: x => x.FirstID,
principalTable: "Libraries",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_Link<Library, ProviderID>_Providers_SecondID",
name: "FK_Link<Library, Provider>_Providers_SecondID",
column: x => x.SecondID,
principalTable: "Providers",
principalColumn: "ID",
@ -459,8 +459,8 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
column: "SecondID");
migrationBuilder.CreateIndex(
name: "IX_Link<Library, ProviderID>_SecondID",
table: "Link<Library, ProviderID>",
name: "IX_Link<Library, Provider>_SecondID",
table: "Link<Library, Provider>",
column: "SecondID");
migrationBuilder.CreateIndex(
@ -559,7 +559,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Link<Library, Collection>");
migrationBuilder.DropTable(
name: "Link<Library, ProviderID>");
name: "Link<Library, Provider>");
migrationBuilder.DropTable(
name: "Link<Library, Show>");

View File

@ -177,7 +177,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.ToTable("Link<Library, Collection>");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.ProviderID>", b =>
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Provider>", b =>
{
b.Property<int>("FirstID")
.HasColumnType("integer");
@ -189,7 +189,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("SecondID");
b.ToTable("Link<Library, ProviderID>");
b.ToTable("Link<Library, Provider>");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Show>", b =>
@ -318,7 +318,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.ToTable("PeopleRoles");
});
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
modelBuilder.Entity("Kyoo.Models.Provider", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
@ -561,7 +561,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Navigation("Second");
});
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.ProviderID>", b =>
modelBuilder.Entity("Kyoo.Models.Link<Kyoo.Models.Library, Kyoo.Models.Provider>", b =>
{
b.HasOne("Kyoo.Models.Library", "First")
.WithMany("ProviderLinks")
@ -569,7 +569,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Kyoo.Models.ProviderID", "Second")
b.HasOne("Kyoo.Models.Provider", "Second")
.WithMany("LibraryLinks")
.HasForeignKey("SecondID")
.OnDelete(DeleteBehavior.Cascade)
@ -630,7 +630,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
.HasForeignKey("PeopleID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Kyoo.Models.ProviderID", "Provider")
b.HasOne("Kyoo.Models.Provider", "Provider")
.WithMany("MetadataLinks")
.HasForeignKey("ProviderID")
.OnDelete(DeleteBehavior.Cascade)
@ -742,7 +742,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Navigation("Roles");
});
modelBuilder.Entity("Kyoo.Models.ProviderID", b =>
modelBuilder.Entity("Kyoo.Models.Provider", b =>
{
b.Navigation("LibraryLinks");

View File

@ -147,6 +147,20 @@ namespace Kyoo
});
// TODO Add custom method to the service container and expose those methods to the plugin
// TODO Add for example a AddRepository that will automatically register the complex interface, the IRepository<T> and the IBaseRepository
services.AddScoped<IBaseRepository, LibraryRepository>();
services.AddScoped<IBaseRepository, LibraryItemRepository>();
services.AddScoped<IBaseRepository, CollectionRepository>();
services.AddScoped<IBaseRepository, ShowRepository>();
services.AddScoped<IBaseRepository, SeasonRepository>();
services.AddScoped<IBaseRepository, EpisodeRepository>();
services.AddScoped<IBaseRepository, TrackRepository>();
services.AddScoped<IBaseRepository, PeopleRepository>();
services.AddScoped<IBaseRepository, StudioRepository>();
services.AddScoped<IBaseRepository, GenreRepository>();
services.AddScoped<IBaseRepository, ProviderRepository>();
services.AddScoped<ILibraryRepository, LibraryRepository>();
services.AddScoped<ILibraryItemRepository, LibraryItemRepository>();
services.AddScoped<ICollectionRepository, CollectionRepository>();

View File

@ -33,7 +33,7 @@ namespace Kyoo.Controllers
{
using IServiceScope serviceScope = _serviceProvider.CreateScope();
await using ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
return (await libraryManager!.GetLibraries()).Select(x => x.Slug);
return (await libraryManager!.GetAll<Library>()).Select(x => x.Slug);
}
public int? Progress()
@ -58,23 +58,23 @@ namespace Kyoo.Controllers
using IServiceScope serviceScope = _serviceProvider.CreateScope();
await using ILibraryManager libraryManager = serviceScope.ServiceProvider.GetService<ILibraryManager>();
foreach (Show show in await libraryManager!.GetShows())
foreach (Show show in await libraryManager!.GetAll<Show>())
if (!Directory.Exists(show.Path))
await libraryManager.DeleteShow(show);
await libraryManager.Delete(show);
ICollection<Episode> episodes = await libraryManager.GetEpisodes();
ICollection<Episode> episodes = await libraryManager.GetAll<Episode>();
foreach (Episode episode in episodes)
if (!File.Exists(episode.Path))
await libraryManager.DeleteEpisode(episode);
await libraryManager.Delete(episode);
ICollection<Track> tracks = await libraryManager.GetTracks();
ICollection<Track> tracks = await libraryManager.GetAll<Track>();
foreach (Track track in tracks)
if (!File.Exists(track.Path))
await libraryManager.DeleteTrack(track);
await libraryManager.Delete(track);
ICollection<Library> libraries = argument == null
? await libraryManager.GetLibraries()
: new [] { await libraryManager.GetLibrary(argument)};
? await libraryManager.GetAll<Library>()
: new [] { await libraryManager.Get<Library>(argument)};
if (argument != null && libraries.First() == null)
throw new ArgumentException($"No library found with the name {argument}");
@ -160,7 +160,7 @@ namespace Kyoo.Controllers
}
string episodePath = match.Groups["Episode"].Value;
Episode episode = await libraryManager!.GetEpisode(x => x.Path.StartsWith(episodePath));
Episode episode = await libraryManager!.Get<Episode>(x => x.Path.StartsWith(episodePath));
if (episode == null)
{
@ -180,7 +180,7 @@ namespace Kyoo.Controllers
Episode = episode
};
await libraryManager.RegisterTrack(track);
await libraryManager.Create(track);
Console.WriteLine($"Registering subtitle at: {path}.");
}
@ -215,7 +215,7 @@ namespace Kyoo.Controllers
bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1;
Show show = await GetShow(libraryManager, showName, showPath, isMovie, library);
if (isMovie)
await libraryManager!.RegisterEpisode(await GetMovie(show, path));
await libraryManager!.Create(await GetMovie(show, path));
else
{
Season season = await GetSeason(libraryManager, show, seasonNumber, library);
@ -226,7 +226,7 @@ namespace Kyoo.Controllers
absoluteNumber,
path,
library);
await libraryManager!.RegisterEpisode(episode);
await libraryManager!.Create(episode);
}
await libraryManager.AddShowLink(show, library, collection);
@ -250,19 +250,19 @@ namespace Kyoo.Controllers
{
if (string.IsNullOrEmpty(collectionName))
return null;
Collection collection = await libraryManager.GetCollection(Utility.ToSlug(collectionName));
Collection collection = await libraryManager.Get<Collection>(Utility.ToSlug(collectionName));
if (collection != null)
return collection;
collection = await _metadataProvider.GetCollectionFromName(collectionName, library);
try
{
await libraryManager.RegisterCollection(collection);
await libraryManager.Create(collection);
return collection;
}
catch (DuplicatedItemException)
{
return await libraryManager.GetCollection(collection.Slug);
return await libraryManager.Get<Collection>(collection.Slug);
}
}
@ -272,7 +272,7 @@ namespace Kyoo.Controllers
bool isMovie,
Library library)
{
Show old = await libraryManager.GetShow(x => x.Path == showPath);
Show old = await libraryManager.Get<Show>(x => x.Path == showPath);
if (old != null)
{
await libraryManager.Load(old, x => x.ExternalIDs);
@ -284,18 +284,18 @@ namespace Kyoo.Controllers
try
{
show = await libraryManager.RegisterShow(show);
show = await libraryManager.Create(show);
}
catch (DuplicatedItemException)
{
old = await libraryManager.GetShow(show.Slug);
old = await libraryManager.Get<Show>(show.Slug);
if (old.Path == showPath)
{
await libraryManager.Load(old, x => x.ExternalIDs);
return old;
}
show.Slug += $"-{show.StartYear}";
await libraryManager.RegisterShow(show);
await libraryManager.Create(show);
}
await _thumbnailsManager.Validate(show);
return show;
@ -308,18 +308,18 @@ namespace Kyoo.Controllers
{
if (seasonNumber == -1)
return default;
Season season = await libraryManager.GetSeason(show.Slug, seasonNumber);
Season season = await libraryManager.Get(show.Slug, seasonNumber);
if (season == null)
{
season = await _metadataProvider.GetSeason(show, seasonNumber, library);
try
{
await libraryManager.RegisterSeason(season);
await libraryManager.Create(season);
await _thumbnailsManager.Validate(season);
}
catch (DuplicatedItemException)
{
season = await libraryManager.GetSeason(show.Slug, season.SeasonNumber);
season = await libraryManager.Get(show.Slug, season.SeasonNumber);
}
}
season.Show = show;

View File

@ -45,22 +45,22 @@ namespace Kyoo.Tasks
case "show":
case "shows":
Show show = await (int.TryParse(slug, out id)
? _library!.GetShow(id)
: _library!.GetShow(slug));
? _library!.Get<Show>(id)
: _library!.Get<Show>(slug));
await ExtractShow(show, thumbs, subs, token);
break;
case "season":
case "seasons":
Season season = await (int.TryParse(slug, out id)
? _library!.GetSeason(id)
: _library!.GetSeason(slug));
? _library!.Get<Season>(id)
: _library!.Get<Season>(slug));
await ExtractSeason(season, thumbs, subs, token);
break;
case "episode":
case "episodes":
Episode episode = await (int.TryParse(slug, out id)
? _library!.GetEpisode(id)
: _library!.GetEpisode(slug));
? _library!.Get<Episode>(id)
: _library!.Get<Episode>(slug));
await ExtractEpisode(episode, thumbs, subs);
break;
}
@ -105,7 +105,7 @@ namespace Kyoo.Tasks
.Where(x => x.Type != StreamType.Attachment)
.Concat(episode.Tracks.Where(x => x.IsExternal))
.ToList();
await _library.EditEpisode(episode, false);
await _library.Edit(episode, false);
}
}

View File

@ -35,12 +35,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Collections.Any(y => y.ID == id)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetCollection(id) == null)
if (!resources.Any() && await _libraryManager.Get<Collection>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -61,12 +61,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Collections.Any(y => y.Slug == slug)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetCollection(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Collection>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -87,12 +87,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Library> resources = await _libraryManager.GetLibraries(
ICollection<Library> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Library>(where, x => x.Collections.Any(y => y.ID == id)),
new Sort<Library>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetCollection(id) == null)
if (!resources.Any() && await _libraryManager.Get<Collection>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -113,12 +113,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Library> resources = await _libraryManager.GetLibraries(
ICollection<Library> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Library>(where, x => x.Collections.Any(y => y.Slug == slug)),
new Sort<Library>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetCollection(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Collection>(slug) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -35,42 +35,42 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(int episodeID)
{
return await _libraryManager.GetShow(x => x.Episodes.Any(y => y.ID == episodeID));
return await _libraryManager.Get<Show>(x => x.Episodes.Any(y => y.ID == episodeID));
}
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/show")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(string showSlug)
public async Task<ActionResult<Show>> GetShow(string showSlug, int seasonNumber, int episodeNumber)
{
return await _libraryManager.GetShow(showSlug);
return await _libraryManager.Get<Show>(showSlug);
}
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/show")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(int showID, int _)
public async Task<ActionResult<Show>> GetShow(int showID, int seasonNumber, int episodeNumber)
{
return await _libraryManager.GetShow(showID);
return await _libraryManager.Get<Show>(showID);
}
[HttpGet("{episodeID:int}/season")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Season>> GetSeason(int episodeID)
{
return await _libraryManager.GetSeason(x => x.Episodes.Any(y => y.ID == episodeID));
return await _libraryManager.Get<Season>(x => x.Episodes.Any(y => y.ID == episodeID));
}
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/season")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Season>> GetSeason(string showSlug, int seasonNuber)
public async Task<ActionResult<Season>> GetSeason(string showSlug, int seasonNumber, int episodeNumber)
{
return await _libraryManager.GetSeason(showSlug, seasonNuber);
return await _libraryManager.Get(showSlug, seasonNumber);
}
[HttpGet("{showID:int}-{seasonNumber:int}e{episodeNumber:int}/season")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Season>> GetSeason(int showID, int seasonNumber)
public async Task<ActionResult<Season>> GetSeason(int showID, int seasonNumber, int episodeNumber)
{
return await _libraryManager.GetSeason(showID, seasonNumber);
return await _libraryManager.Get(showID, seasonNumber);
}
[HttpGet("{episodeID:int}/track")]
@ -84,12 +84,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Track> resources = await _libraryManager.GetTracks(
ICollection<Track> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Track>(where, x => x.Episode.ID == episodeID),
new Sort<Track>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetEpisode(episodeID) == null)
if (!resources.Any() && await _libraryManager.Get<Episode>(episodeID) == null)
return NotFound();
return Page(resources, limit);
}
@ -112,14 +112,14 @@ namespace Kyoo.Api
{
try
{
ICollection<Track> resources = await _libraryManager.GetTracks(
ICollection<Track> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Track>(where, x => x.Episode.ShowID == showID
&& x.Episode.SeasonNumber == seasonNumber
&& x.Episode.EpisodeNumber == episodeNumber),
new Sort<Track>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetEpisode(showID, seasonNumber, episodeNumber) == null)
if (!resources.Any() && await _libraryManager.Get(showID, seasonNumber, episodeNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -142,13 +142,14 @@ namespace Kyoo.Api
{
try
{
ICollection<Track> resources = await _libraryManager.GetTracks(ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == showSlug
ICollection<Track> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Track>(where, x => x.Episode.Show.Slug == showSlug
&& x.Episode.SeasonNumber == seasonNumber
&& x.Episode.EpisodeNumber == episodeNumber),
new Sort<Track>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber) == null)
if (!resources.Any() && await _libraryManager.Get(showSlug, seasonNumber, episodeNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -162,7 +163,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetThumb(int id)
{
Episode episode = await _libraryManager.GetEpisode(id);
Episode episode = await _libraryManager.Get<Episode>(id);
if (episode == null)
return NotFound();
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));
@ -172,7 +173,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetThumb(string slug)
{
Episode episode = await _libraryManager.GetEpisode(slug);
Episode episode = await _libraryManager.Get<Episode>(slug);
if (episode == null)
return NotFound();
return _files.FileResult(await _thumbnails.GetEpisodeThumb(episode));

View File

@ -36,12 +36,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Genres.Any(y => y.ID == id)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetGenre(id) == null)
if (!resources.Any() && await _libraryManager.Get<Genre>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -62,12 +62,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Genres.Any(y => y.Slug == slug)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetGenre(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Genre>(slug) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -47,12 +47,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Libraries.Any(y => y.ID == id)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(id) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -73,12 +73,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Libraries.Any(y => y.Slug == slug)),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -99,12 +99,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Collection> resources = await _libraryManager.GetCollections(
ICollection<Collection> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Collection>(where, x => x.Libraries.Any(y => y.ID == id)),
new Sort<Collection>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(id) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -125,12 +125,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Collection> resources = await _libraryManager.GetCollections(
ICollection<Collection> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Collection>(where, x => x.Libraries.Any(y => y.Slug == slug)),
new Sort<Collection>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -156,7 +156,7 @@ namespace Kyoo.Api
new Sort<LibraryItem>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(id) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -182,7 +182,7 @@ namespace Kyoo.Api
new Sort<LibraryItem>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetLibrary(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Library>(slug) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -90,7 +90,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetPeopleIcon(int id)
{
People people = await _libraryManager.GetPeople(id);
People people = await _libraryManager.Get<People>(id);
return _files.FileResult(await _thumbs.GetPeoplePoster(people));
}
@ -98,7 +98,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetPeopleIcon(string slug)
{
People people = await _libraryManager.GetPeople(slug);
People people = await _libraryManager.Get<People>(slug);
return _files.FileResult(await _thumbs.GetPeoplePoster(people));
}
}

View File

@ -11,7 +11,7 @@ namespace Kyoo.Api
[Route("api/provider")]
[Route("api/providers")]
[ApiController]
public class ProviderAPI : CrudApi<ProviderID>
public class ProviderAPI : CrudApi<Provider>
{
private readonly IThumbnailsManager _thumbnails;
private readonly ILibraryManager _libraryManager;
@ -32,7 +32,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetLogo(int id)
{
ProviderID provider = await _libraryManager.GetProvider(id);
Provider provider = await _libraryManager.Get<Provider>(id);
return _files.FileResult(await _thumbnails.GetProviderLogo(provider));
}
@ -40,7 +40,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetLogo(string slug)
{
ProviderID provider = await _libraryManager.GetProvider(slug);
Provider provider = await _libraryManager.Get<Provider>(slug);
return _files.FileResult(await _thumbnails.GetProviderLogo(provider));
}
}

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api
{
[Route("api/search")]
[Route("api/search/{query}")]
[ApiController]
public class SearchApi : ControllerBase
{
@ -18,67 +18,67 @@ namespace Kyoo.Api
_libraryManager = libraryManager;
}
[HttpGet("{query}")]
[HttpGet]
[Authorize(Policy="Read")]
public async Task<ActionResult<SearchResult>> Search(string query)
{
return new SearchResult
{
Query = query,
Collections = await _libraryManager.SearchCollections(query),
Shows = await _libraryManager.SearchShows(query),
Episodes = await _libraryManager.SearchEpisodes(query),
People = await _libraryManager.SearchPeople(query),
Genres = await _libraryManager.SearchGenres(query),
Studios = await _libraryManager.SearchStudios(query)
Collections = await _libraryManager.Search<Collection>(query),
Shows = await _libraryManager.Search<Show>(query),
Episodes = await _libraryManager.Search<Episode>(query),
People = await _libraryManager.Search<People>(query),
Genres = await _libraryManager.Search<Genre>(query),
Studios = await _libraryManager.Search<Studio>(query)
};
}
[HttpGet("{query}/collection")]
[HttpGet("{query}/collections")]
[HttpGet("collection")]
[HttpGet("collections")]
[Authorize(Policy="Read")]
public Task<ICollection<Collection>> SearchCollections(string query)
{
return _libraryManager.SearchCollections(query);
return _libraryManager.Search<Collection>(query);
}
[HttpGet("{query}/show")]
[HttpGet("{query}/shows")]
[HttpGet("show")]
[HttpGet("shows")]
[Authorize(Policy="Read")]
public Task<ICollection<Show>> SearchShows(string query)
{
return _libraryManager.SearchShows(query);
return _libraryManager.Search<Show>(query);
}
[HttpGet("{query}/episode")]
[HttpGet("{query}/episodes")]
[HttpGet("episode")]
[HttpGet("episodes")]
[Authorize(Policy="Read")]
public Task<ICollection<Episode>> SearchEpisodes(string query)
{
return _libraryManager.SearchEpisodes(query);
return _libraryManager.Search<Episode>(query);
}
[HttpGet("{query}/people")]
[HttpGet("people")]
[Authorize(Policy="Read")]
public Task<ICollection<People>> SearchPeople(string query)
{
return _libraryManager.SearchPeople(query);
return _libraryManager.Search<People>(query);
}
[HttpGet("{query}/genre")]
[HttpGet("{query}/genres")]
[HttpGet("genre")]
[HttpGet("genres")]
[Authorize(Policy="Read")]
public Task<ICollection<Genre>> SearchGenres(string query)
{
return _libraryManager.SearchGenres(query);
return _libraryManager.Search<Genre>(query);
}
[HttpGet("{query}/studio")]
[HttpGet("{query}/studios")]
[HttpGet("studio")]
[HttpGet("studios")]
[Authorize(Policy="Read")]
public Task<ICollection<Studio>> SearchStudios(string query)
{
return _libraryManager.SearchStudios(query);
return _libraryManager.Search<Studio>(query);
}
}
}

View File

@ -42,12 +42,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Episode> resources = await _libraryManager.GetEpisodes(
ICollection<Episode> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Episode>(where, x => x.SeasonID == seasonID),
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetSeason(seasonID) == null)
if (!resources.Any() && await _libraryManager.Get<Season>(seasonID) == null)
return NotFound();
return Page(resources, limit);
}
@ -69,13 +69,13 @@ namespace Kyoo.Api
{
try
{
ICollection<Episode> resources = await _libraryManager.GetEpisodes(
ICollection<Episode> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Episode>(where, x => x.Show.Slug == showSlug
&& x.SeasonNumber == seasonNumber),
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetSeason(showSlug, seasonNumber) == null)
if (!resources.Any() && await _libraryManager.Get(showSlug, seasonNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -97,12 +97,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Episode> resources = await _libraryManager.GetEpisodes(
ICollection<Episode> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Episode>(where, x => x.ShowID == showID && x.SeasonNumber == seasonNumber),
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetSeason(showID, seasonNumber) == null)
if (!resources.Any() && await _libraryManager.Get(showID, seasonNumber) == null)
return NotFound();
return Page(resources, limit);
}
@ -116,28 +116,28 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(int seasonID)
{
return await _libraryManager.GetShow(x => x.Seasons.Any(y => y.ID == seasonID));
return await _libraryManager.Get<Show>(x => x.Seasons.Any(y => y.ID == seasonID));
}
[HttpGet("{showSlug}-s{seasonNumber:int}/show")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(string showSlug, int _)
public async Task<ActionResult<Show>> GetShow(string showSlug, int seasonNumber)
{
return await _libraryManager.GetShow(showSlug);
return await _libraryManager.Get<Show>(showSlug);
}
[HttpGet("{showID:int}-s{seasonNumber:int}/show")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Show>> GetShow(int showID, int _)
public async Task<ActionResult<Show>> GetShow(int showID, int seasonNumber)
{
return await _libraryManager.GetShow(showID);
return await _libraryManager.Get<Show>(showID);
}
[HttpGet("{id:int}/thumb")]
[Authorize(Policy="Read")]
public async Task<IActionResult> GetThumb(int id)
{
Season season = await _libraryManager.GetSeason(id);
Season season = await _libraryManager.Get<Season>(id);
await _libraryManager.Load(season, x => x.Show);
return _files.FileResult(await _thumbs.GetSeasonPoster(season));
}
@ -146,7 +146,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetThumb(string slug)
{
Season season = await _libraryManager.GetSeason(slug);
Season season = await _libraryManager.Get<Season>(slug);
await _libraryManager.Load(season, x => x.Show);
return _files.FileResult(await _thumbs.GetSeasonPoster(season));
}

View File

@ -44,12 +44,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Season> resources = await _libraryManager.GetSeasons(
ICollection<Season> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Season>(where, x => x.ShowID == showID),
new Sort<Season>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -70,12 +70,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Season> resources = await _libraryManager.GetSeasons(
ICollection<Season> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Season>(where, x => x.Show.Slug == slug),
new Sort<Season>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -96,12 +96,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Episode> resources = await _libraryManager.GetEpisodes(
ICollection<Episode> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Episode>(where, x => x.ShowID == showID),
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -122,12 +122,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Episode> resources = await _libraryManager.GetEpisodes(
ICollection<Episode> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Episode>(where, x => x.Show.Slug == slug),
new Sort<Episode>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -152,7 +152,7 @@ namespace Kyoo.Api
new Sort<PeopleRole>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -177,7 +177,7 @@ namespace Kyoo.Api
new Sort<PeopleRole>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -198,12 +198,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Genre> resources = await _libraryManager.GetGenres(
ICollection<Genre> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Genre>(where, x => x.Shows.Any(y => y.ID == showID)),
new Sort<Genre>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -224,12 +224,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Genre> resources = await _libraryManager.GetGenres(
ICollection<Genre> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Genre>(where, x => x.Shows.Any(y => y.Slug == slug)),
new Sort<Genre>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -245,7 +245,7 @@ namespace Kyoo.Api
{
try
{
return await _libraryManager.GetStudio(x => x.Shows.Any(y => y.ID == showID));
return await _libraryManager.Get<Studio>(x => x.Shows.Any(y => y.ID == showID));
}
catch (ItemNotFound)
{
@ -259,7 +259,7 @@ namespace Kyoo.Api
{
try
{
return await _libraryManager.GetStudio(x => x.Shows.Any(y => y.Slug == slug));
return await _libraryManager.Get<Studio>(x => x.Shows.Any(y => y.Slug == slug));
}
catch (ItemNotFound)
{
@ -278,12 +278,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Library> resources = await _libraryManager.GetLibraries(
ICollection<Library> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Library>(where, x => x.Shows.Any(y => y.ID == showID)),
new Sort<Library>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -304,12 +304,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Library> resources = await _libraryManager.GetLibraries(
ICollection<Library> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Library>(where, x => x.Shows.Any(y => y.Slug == slug)),
new Sort<Library>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -330,12 +330,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Collection> resources = await _libraryManager.GetCollections(
ICollection<Collection> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Collection>(where, x => x.Shows.Any(y => y.ID == showID)),
new Sort<Collection>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(showID) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(showID) == null)
return NotFound();
return Page(resources, limit);
}
@ -356,12 +356,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Collection> resources = await _libraryManager.GetCollections(
ICollection<Collection> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Collection>(where, x => x.Shows.Any(y => y.Slug == slug)),
new Sort<Collection>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetShow(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Show>(slug) == null)
return NotFound();
return Page(resources, limit);
}
@ -376,7 +376,7 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<ActionResult<Dictionary<string, string>>> GetFonts(string slug)
{
Show show = await _libraryManager.GetShow(slug);
Show show = await _libraryManager.Get<Show>(slug);
if (show == null)
return NotFound();
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments");
@ -390,7 +390,7 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<IActionResult> GetFont(string showSlug, string slug)
{
Show show = await _libraryManager.GetShow(showSlug);
Show show = await _libraryManager.Get<Show>(showSlug);
if (show == null)
return NotFound();
string path = Path.Combine(_files.GetExtraDirectory(show), "Attachments", slug);
@ -401,7 +401,7 @@ namespace Kyoo.Api
[Authorize(Policy = "Read")]
public async Task<IActionResult> GetPoster(string slug)
{
Show show = await _libraryManager.GetShow(slug);
Show show = await _libraryManager.Get<Show>(slug);
if (show == null)
return NotFound();
return _files.FileResult(await _thumbs.GetShowPoster(show));
@ -411,7 +411,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetLogo(string slug)
{
Show show = await _libraryManager.GetShow(slug);
Show show = await _libraryManager.Get<Show>(slug);
if (show == null)
return NotFound();
return _files.FileResult(await _thumbs.GetShowLogo(show));
@ -421,7 +421,7 @@ namespace Kyoo.Api
[Authorize(Policy="Read")]
public async Task<IActionResult> GetBackdrop(string slug)
{
Show show = await _libraryManager.GetShow(slug);
Show show = await _libraryManager.Get<Show>(slug);
if (show == null)
return NotFound();
return _files.FileResult(await _thumbs.GetShowBackdrop(show));

View File

@ -35,12 +35,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.StudioID == id),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetStudio(id) == null)
if (!resources.Any() && await _libraryManager.Get<Studio>(id) == null)
return NotFound();
return Page(resources, limit);
}
@ -61,12 +61,12 @@ namespace Kyoo.Api
{
try
{
ICollection<Show> resources = await _libraryManager.GetShows(
ICollection<Show> resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere<Show>(where, x => x.Studio.Slug == slug),
new Sort<Show>(sortBy),
new Pagination(limit, afterID));
if (!resources.Any() && await _libraryManager.GetStudio(slug) == null)
if (!resources.Any() && await _libraryManager.Get<Studio>(slug) == null)
return NotFound();
return Page(resources, limit);
}

View File

@ -29,7 +29,7 @@ namespace Kyoo.Api
{
try
{
return await _libraryManager.GetEpisode(x => x.Tracks.Any(y => y.ID == id));
return await _libraryManager.Get<Episode>(x => x.Tracks.Any(y => y.ID == id));
}
catch (ItemNotFound)
{
@ -45,7 +45,7 @@ namespace Kyoo.Api
{
// TODO This won't work with the local repository implementation.
// TODO Implement something like this (a dotnet-ef's QueryCompilationContext): https://stackoverflow.com/questions/62687811/how-can-i-convert-a-custom-function-to-a-sql-expression-for-entity-framework-cor
return await _libraryManager.GetEpisode(x => x.Tracks.Any(y => y.Slug == slug));
return await _libraryManager.Get<Episode>(x => x.Tracks.Any(y => y.Slug == slug));
}
catch (ItemNotFound)
{

View File

@ -4,6 +4,7 @@ using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System.Threading.Tasks;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Filters;
@ -41,91 +42,58 @@ namespace Kyoo.Api
}
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}")]
[HttpGet("direct/{showSlug}-s{seasonNumber:int}e{episodeNumber:int}")]
[HttpGet("{slug}")]
[HttpGet("direct/{slug}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> DirectEpisode(string showSlug, int seasonNumber, int episodeNumber)
public async Task<IActionResult> Direct(string slug)
{
if (seasonNumber < 0 || episodeNumber < 0)
return BadRequest(new {error = "Season number or episode number can not be negative."});
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
if (episode == null)
return NotFound();
try
{
Episode episode = await _libraryManager.Get<Episode>(slug);
return _files.FileResult(episode.Path, true);
}
[HttpGet("{movieSlug}")]
[HttpGet("direct/{movieSlug}")]
[Authorize(Policy="Play")]
public async Task<IActionResult> DirectMovie(string movieSlug)
catch (ItemNotFound)
{
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
if (episode == null)
return NotFound();
return _files.FileResult(episode.Path, true);
}
}
[HttpGet("transmux/{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/master.m3u8")]
[HttpGet("transmux/{slug}/master.m3u8")]
[Authorize(Policy="Play")]
public async Task<IActionResult> TransmuxEpisode(string showSlug, int seasonNumber, int episodeNumber)
public async Task<IActionResult> Transmux(string slug)
{
if (seasonNumber < 0 || episodeNumber < 0)
return BadRequest(new {error = "Season number or episode number can not be negative."});
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
if (episode == null)
return NotFound();
try
{
Episode episode = await _libraryManager.Get<Episode>(slug);
string path = await _transcoder.Transmux(episode);
if (path == null)
return StatusCode(500);
return _files.FileResult(path, true);
}
[HttpGet("transmux/{movieSlug}/master.m3u8")]
[Authorize(Policy="Play")]
public async Task<IActionResult> TransmuxMovie(string movieSlug)
catch (ItemNotFound)
{
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
if (episode == null)
return NotFound();
string path = await _transcoder.Transmux(episode);
if (path == null)
return StatusCode(500);
return _files.FileResult(path, true);
}
}
[HttpGet("transcode/{showSlug}-s{seasonNumber:int}e{episodeNumber:int}/master.m3u8")]
[HttpGet("transcode/{slug}/master.m3u8")]
[Authorize(Policy="Play")]
public async Task<IActionResult> TranscodeEpisode(string showSlug, int seasonNumber, int episodeNumber)
public async Task<IActionResult> Transcode(string slug)
{
if (seasonNumber < 0 || episodeNumber < 0)
return BadRequest(new {error = "Season number or episode number can not be negative."});
Episode episode = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
if (episode == null)
return NotFound();
try
{
Episode episode = await _libraryManager.Get<Episode>(slug);
string path = await _transcoder.Transcode(episode);
if (path == null)
return StatusCode(500);
return _files.FileResult(path, true);
}
[HttpGet("transcode/{movieSlug}/master.m3u8")]
[Authorize(Policy="Play")]
public async Task<IActionResult> TranscodeMovie(string movieSlug)
catch (ItemNotFound)
{
Episode episode = await _libraryManager.GetMovieEpisode(movieSlug);
if (episode == null)
return NotFound();
string path = await _transcoder.Transcode(episode);
if (path == null)
return StatusCode(500);
return _files.FileResult(path, true);
}
}

View File

@ -17,21 +17,11 @@ namespace Kyoo.Api
_libraryManager = libraryManager;
}
[HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}")]
[HttpGet("{slug}")]
[Authorize(Policy="Read")]
public async Task<ActionResult<WatchItem>> GetWatchItem(string showSlug, int seasonNumber, int episodeNumber)
public async Task<ActionResult<WatchItem>> GetWatchItem(string slug)
{
Episode item = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
if (item == null)
return NotFound();
return await WatchItem.FromEpisode(item, _libraryManager);
}
[HttpGet("{movieSlug}")]
[Authorize(Policy="Read")]
public async Task<ActionResult<WatchItem>> GetWatchItem(string movieSlug)
{
Episode item = await _libraryManager.GetMovieEpisode(movieSlug);
Episode item = await _libraryManager.Get<Episode>(slug);
if (item == null)
return NotFound();
return await WatchItem.FromEpisode(item, _libraryManager);