Adding shows/people route & GetPeopleByShow

This commit is contained in:
Zoe Roux 2020-07-25 03:47:30 +02:00
parent c47a4b2e15
commit b73be95f11
18 changed files with 312 additions and 105 deletions

View File

@ -36,44 +36,44 @@ namespace Kyoo.Controllers
Task<People> GetPeople(string slug); Task<People> GetPeople(string slug);
// Get by relations // Get by relations
Task<ICollection<Season>> GetSeasons(int showID, Task<ICollection<Season>> GetSeasonsFromShow(int showID,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Season>> GetSeasons(int showID, Task<ICollection<Season>> GetSeasonsFromShow(int showID,
[Optional] Expression<Func<Season, bool>> where, [Optional] Expression<Func<Season, bool>> where,
Expression<Func<Season, object>> sort, Expression<Func<Season, object>> sort,
Pagination limit = default Pagination limit = default
) => GetSeasons(showID, where, new Sort<Season>(sort), limit); ) => GetSeasonsFromShow(showID, where, new Sort<Season>(sort), limit);
Task<ICollection<Season>> GetSeasons(string showSlug, Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Season>> GetSeasons(string showSlug, Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
[Optional] Expression<Func<Season, bool>> where, [Optional] Expression<Func<Season, bool>> where,
Expression<Func<Season, object>> sort, Expression<Func<Season, object>> sort,
Pagination limit = default Pagination limit = default
) => GetSeasons(showSlug, where, new Sort<Season>(sort), limit); ) => GetSeasonsFromShow(showSlug, where, new Sort<Season>(sort), limit);
Task<ICollection<Episode>> GetEpisodes(int showID, Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(int showID, Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodes(showID, where, new Sort<Episode>(sort), limit); ) => GetEpisodesFromShow(showID, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodes(string showSlug, Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(string showSlug, Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodes(showSlug, where, new Sort<Episode>(sort), limit); ) => GetEpisodesFromShow(showSlug, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID, Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
@ -109,6 +109,26 @@ namespace Kyoo.Controllers
Pagination limit = default Pagination limit = default
) => GetEpisodesFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit); ) => GetEpisodesFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit);
Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default);
Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
[Optional] Expression<Func<PeopleLink, bool>> where,
Expression<Func<PeopleLink, object>> sort,
Pagination limit = default
) => GetPeopleFromShow(showID, where, new Sort<PeopleLink>(sort), limit);
Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default);
Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
[Optional] Expression<Func<PeopleLink, bool>> where,
Expression<Func<PeopleLink, object>> sort,
Pagination limit = default
) => GetPeopleFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit);
// Helpers // Helpers
Task AddShowLink(int showID, int? libraryID, int? collectionID); Task AddShowLink(int showID, int? libraryID, int? collectionID);
@ -124,10 +144,10 @@ namespace Kyoo.Controllers
Task<ICollection<Show>> GetShows(Expression<Func<Show, bool>> where = null, Task<ICollection<Show>> GetShows(Expression<Func<Show, bool>> where = null,
Sort<Show> sort = default, Sort<Show> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Season>> GetSeasons(Expression<Func<Season, bool>> where = null, Task<ICollection<Season>> GetSeasonsFromShow(Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(Expression<Func<Episode, bool>> where = null, Task<ICollection<Episode>> GetEpisodesFromShow(Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Track>> GetTracks(Expression<Func<Track, bool>> where = null, Task<ICollection<Track>> GetTracks(Expression<Func<Track, bool>> where = null,
@ -158,14 +178,14 @@ namespace Kyoo.Controllers
Expression<Func<Show, object>> sort, Expression<Func<Show, object>> sort,
Pagination limit = default Pagination limit = default
) => GetShows(where, new Sort<Show>(sort), limit); ) => GetShows(where, new Sort<Show>(sort), limit);
Task<ICollection<Season>> GetSeasons([Optional] Expression<Func<Season, bool>> where, Task<ICollection<Season>> GetSeasonsFromShow([Optional] Expression<Func<Season, bool>> where,
Expression<Func<Season, object>> sort, Expression<Func<Season, object>> sort,
Pagination limit = default Pagination limit = default
) => GetSeasons(where, new Sort<Season>(sort), limit); ) => GetSeasonsFromShow(where, new Sort<Season>(sort), limit);
Task<ICollection<Episode>> GetEpisodes([Optional] Expression<Func<Episode, bool>> where, Task<ICollection<Episode>> GetEpisodesFromShow([Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodes(where, new Sort<Episode>(sort), limit); ) => GetEpisodesFromShow(where, new Sort<Episode>(sort), limit);
Task<ICollection<Track>> GetTracks([Optional] Expression<Func<Track, bool>> where, Task<ICollection<Track>> GetTracks([Optional] Expression<Func<Track, bool>> where,
Expression<Func<Track, object>> sort, Expression<Func<Track, object>> sort,
Pagination limit = default Pagination limit = default

View File

@ -23,10 +23,10 @@ namespace Kyoo.Controllers
public static implicit operator Pagination(int limit) => new Pagination(limit); public static implicit operator Pagination(int limit) => new Pagination(limit);
} }
public readonly struct Sort<T> public struct Sort<T>
{ {
public Expression<Func<T, object>> Key { get; } public Expression<Func<T, object>> Key;
public bool Descendant { get; } public bool Descendant;
public Sort(Expression<Func<T, object>> key, bool descendant = false) public Sort(Expression<Func<T, object>> key, bool descendant = false)
{ {
@ -110,25 +110,25 @@ namespace Kyoo.Controllers
Task<Season> Get(string showSlug, int seasonNumber); Task<Season> Get(string showSlug, int seasonNumber);
Task Delete(string showSlug, int seasonNumber); Task Delete(string showSlug, int seasonNumber);
Task<ICollection<Season>> GetSeasons(int showID, Task<ICollection<Season>> GetFromShow(int showID,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Season>> GetSeasons(int showID, Task<ICollection<Season>> GetFromShow(int showID,
[Optional] Expression<Func<Season, bool>> where, [Optional] Expression<Func<Season, bool>> where,
Expression<Func<Season, object>> sort, Expression<Func<Season, object>> sort,
Pagination limit = default Pagination limit = default
) => GetSeasons(showID, where, new Sort<Season>(sort), limit); ) => GetFromShow(showID, where, new Sort<Season>(sort), limit);
Task<ICollection<Season>> GetSeasons(string showSlug, Task<ICollection<Season>> GetFromShow(string showSlug,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Season>> GetSeasons(string showSlug, Task<ICollection<Season>> GetFromShow(string showSlug,
[Optional] Expression<Func<Season, bool>> where, [Optional] Expression<Func<Season, bool>> where,
Expression<Func<Season, object>> sort, Expression<Func<Season, object>> sort,
Pagination limit = default Pagination limit = default
) => GetSeasons(showSlug, where, new Sort<Season>(sort), limit); ) => GetFromShow(showSlug, where, new Sort<Season>(sort), limit);
} }
public interface IEpisodeRepository : IRepository<Episode> public interface IEpisodeRepository : IRepository<Episode>
@ -136,57 +136,57 @@ namespace Kyoo.Controllers
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber); Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
Task Delete(string showSlug, int seasonNumber, int episodeNumber); Task Delete(string showSlug, int seasonNumber, int episodeNumber);
Task<ICollection<Episode>> GetEpisodes(int showID, Task<ICollection<Episode>> GetFromShow(int showID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(int showID, Task<ICollection<Episode>> GetFromShow(int showID,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodes(showID, where, new Sort<Episode>(sort), limit); ) => GetFromShow(showID, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodes(string showSlug, Task<ICollection<Episode>> GetFromShow(string showSlug,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodes(string showSlug, Task<ICollection<Episode>> GetFromShow(string showSlug,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodes(showSlug, where, new Sort<Episode>(sort), limit); ) => GetFromShow(showSlug, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID, Task<ICollection<Episode>> GetFromSeason(int seasonID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID, Task<ICollection<Episode>> GetFromSeason(int seasonID,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodesFromSeason(seasonID, where, new Sort<Episode>(sort), limit); ) => GetFromSeason(seasonID, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodesFromSeason(int showID, Task<ICollection<Episode>> GetFromSeason(int showID,
int seasonNumber, int seasonNumber,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodesFromSeason(int showID, Task<ICollection<Episode>> GetFromSeason(int showID,
int seasonNumber, int seasonNumber,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodesFromSeason(showID, seasonNumber, where, new Sort<Episode>(sort), limit); ) => GetFromSeason(showID, seasonNumber, where, new Sort<Episode>(sort), limit);
Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug, Task<ICollection<Episode>> GetFromSeason(string showSlug,
int seasonNumber, int seasonNumber,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default); Pagination limit = default);
Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug, Task<ICollection<Episode>> GetFromSeason(string showSlug,
int seasonNumber, int seasonNumber,
[Optional] Expression<Func<Episode, bool>> where, [Optional] Expression<Func<Episode, bool>> where,
Expression<Func<Episode, object>> sort, Expression<Func<Episode, object>> sort,
Pagination limit = default Pagination limit = default
) => GetEpisodesFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit); ) => GetFromSeason(showSlug, seasonNumber, where, new Sort<Episode>(sort), limit);
} }
public interface ITrackRepository : IRepository<Track> public interface ITrackRepository : IRepository<Track>
@ -197,6 +197,28 @@ namespace Kyoo.Controllers
public interface ICollectionRepository : IRepository<Collection> {} public interface ICollectionRepository : IRepository<Collection> {}
public interface IGenreRepository : IRepository<Genre> {} public interface IGenreRepository : IRepository<Genre> {}
public interface IStudioRepository : IRepository<Studio> {} public interface IStudioRepository : IRepository<Studio> {}
public interface IPeopleRepository : IRepository<People> {}
public interface IPeopleRepository : IRepository<People>
{
Task<ICollection<PeopleLink>> GetFromShow(int showID,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default);
Task<ICollection<PeopleLink>> GetFromShow(int showID,
[Optional] Expression<Func<PeopleLink, bool>> where,
Expression<Func<PeopleLink, object>> sort,
Pagination limit = default
) => GetFromShow(showID, where, new Sort<PeopleLink>(sort), limit);
Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default);
Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
[Optional] Expression<Func<PeopleLink, bool>> where,
Expression<Func<PeopleLink, object>> sort,
Pagination limit = default
) => GetFromShow(showSlug, where, new Sort<PeopleLink>(sort), limit);
}
public interface IProviderRepository : IRepository<ProviderID> {} public interface IProviderRepository : IRepository<ProviderID> {}
} }

View File

@ -148,14 +148,14 @@ namespace Kyoo.Controllers
return ShowRepository.GetAll(where, sort, limit); return ShowRepository.GetAll(where, sort, limit);
} }
public Task<ICollection<Season>> GetSeasons(Expression<Func<Season, bool>> where = null, public Task<ICollection<Season>> GetSeasonsFromShow(Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination page = default) Pagination page = default)
{ {
return SeasonRepository.GetAll(where, sort, page); return SeasonRepository.GetAll(where, sort, page);
} }
public Task<ICollection<Episode>> GetEpisodes(Expression<Func<Episode, bool>> where = null, public Task<ICollection<Episode>> GetEpisodesFromShow(Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination page = default) Pagination page = default)
{ {
@ -197,36 +197,36 @@ namespace Kyoo.Controllers
return ProviderRepository.GetAll(where, sort, page); return ProviderRepository.GetAll(where, sort, page);
} }
public Task<ICollection<Season>> GetSeasons(int showID, public Task<ICollection<Season>> GetSeasonsFromShow(int showID,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return SeasonRepository.GetSeasons(showID, where, sort, limit); return SeasonRepository.GetFromShow(showID, where, sort, limit);
} }
public Task<ICollection<Season>> GetSeasons(string showSlug, public Task<ICollection<Season>> GetSeasonsFromShow(string showSlug,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return SeasonRepository.GetSeasons(showSlug, where, sort, limit); return SeasonRepository.GetFromShow(showSlug, where, sort, limit);
} }
public Task<ICollection<Episode>> GetEpisodes(int showID, public Task<ICollection<Episode>> GetEpisodesFromShow(int showID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return EpisodeRepository.GetEpisodes(showID, where, sort, limit); return EpisodeRepository.GetFromShow(showID, where, sort, limit);
} }
public Task<ICollection<Episode>> GetEpisodes(string showSlug, public Task<ICollection<Episode>> GetEpisodesFromShow(string showSlug,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return EpisodeRepository.GetEpisodes(showSlug, where, sort, limit); return EpisodeRepository.GetFromShow(showSlug, where, sort, limit);
} }
public Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID, public Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID,
@ -234,7 +234,7 @@ namespace Kyoo.Controllers
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return EpisodeRepository.GetEpisodesFromSeason(seasonID, where, sort, limit); return EpisodeRepository.GetFromSeason(seasonID, where, sort, limit);
} }
public Task<ICollection<Episode>> GetEpisodesFromSeason(int showID, public Task<ICollection<Episode>> GetEpisodesFromSeason(int showID,
@ -243,7 +243,7 @@ namespace Kyoo.Controllers
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return EpisodeRepository.GetEpisodesFromSeason(showID, seasonNumber, where, sort, limit); return EpisodeRepository.GetFromSeason(showID, seasonNumber, where, sort, limit);
} }
public Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug, public Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug,
@ -252,7 +252,23 @@ namespace Kyoo.Controllers
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
{ {
return EpisodeRepository.GetEpisodesFromSeason(showSlug, seasonNumber, where, sort, limit); return EpisodeRepository.GetFromSeason(showSlug, seasonNumber, where, sort, limit);
}
public Task<ICollection<PeopleLink>> GetPeopleFromShow(int showID,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default)
{
return PeopleRepository.GetFromShow(showID, where, sort, limit);
}
public Task<ICollection<PeopleLink>> GetPeopleFromShow(string showSlug,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default)
{
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
} }
public Task AddShowLink(int showID, int? libraryID, int? collectionID) public Task AddShowLink(int showID, int? libraryID, int? collectionID)

View File

@ -3,7 +3,7 @@ using Newtonsoft.Json;
namespace Kyoo.Models namespace Kyoo.Models
{ {
public class PeopleLink public class PeopleLink : IRessource
{ {
[JsonIgnore] public int ID { get; set; } [JsonIgnore] public int ID { get; set; }
[JsonIgnore] public int PeopleID { get; set; } [JsonIgnore] public int PeopleID { get; set; }

View File

@ -5,15 +5,23 @@ namespace Kyoo.Models
public class ProviderID : IRessource public class ProviderID : IRessource
{ {
[JsonIgnore] public int ID { get; set; } [JsonIgnore] public int ID { get; set; }
public string Slug => Name; public string Slug { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Logo { get; set; } public string Logo { get; set; }
public ProviderID() { } public ProviderID() { }
public ProviderID(string name, string logo)
{
Slug = Utility.ToSlug(name);
Name = name;
Logo = logo;
}
public ProviderID(int id, string name, string logo) public ProviderID(int id, string name, string logo)
{ {
ID = id; ID = id;
Slug = Utility.ToSlug(name);
Name = name; Name = name;
Logo = logo; Logo = logo;
} }

View File

@ -52,24 +52,34 @@ namespace Kyoo.Controllers
return ApplyFilters(_database.Set<T>(), where, sort, limit); return ApplyFilters(_database.Set<T>(), where, sort, limit);
} }
protected async Task<ICollection<T>> ApplyFilters(IQueryable<T> query, protected Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> where = null,
Sort<T> sort = default, Sort<T> sort = default,
Pagination limit = default) Pagination limit = default)
{
return ApplyFilters(query, Get, DefaultSort, where, sort, limit);
}
protected async Task<ICollection<TValue>> ApplyFilters<TValue>(IQueryable<TValue> query,
Func<int, Task<TValue>> get,
Expression<Func<TValue, object>> defaultSort,
Expression<Func<TValue, bool>> where = null,
Sort<TValue> sort = default,
Pagination limit = default)
{ {
if (where != null) if (where != null)
query = query.Where(where); query = query.Where(where);
Expression<Func<T, object>> sortKey = sort.Key ?? DefaultSort; Expression<Func<TValue, object>> sortKey = sort.Key ?? defaultSort;
query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey); query = sort.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey);
if (limit.AfterID != 0) if (limit.AfterID != 0)
{ {
T after = await Get(limit.AfterID); TValue after = await get(limit.AfterID);
object afterObj = sortKey.Compile()(after); object afterObj = sortKey.Compile()(after);
query = query.Where(Expression.Lambda<Func<T, bool>>( query = query.Where(Expression.Lambda<Func<TValue, bool>>(
ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortKey.Body, Expression.Constant(afterObj)), ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortKey.Body, Expression.Constant(afterObj)),
(ParameterExpression)((MemberExpression)sortKey.Body).Expression sortKey.Parameters.First()
)); ));
} }
if (limit.Count > 0) if (limit.Count > 0)

View File

@ -21,7 +21,7 @@ namespace Kyoo.Controllers
T ret = new T(); T ret = new T();
IEnumerable<IMetadataProvider> providers = library?.Providers IEnumerable<IMetadataProvider> providers = library?.Providers
.Select(x => _providers.FirstOrDefault(y => y.Provider.Name == x.Name)) .Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
.Where(x => x != null) .Where(x => x != null)
?? _providers; ?? _providers;
@ -47,7 +47,7 @@ namespace Kyoo.Controllers
List<T> ret = new List<T>(); List<T> ret = new List<T>();
IEnumerable<IMetadataProvider> providers = library?.Providers IEnumerable<IMetadataProvider> providers = library?.Providers
.Select(x => _providers.FirstOrDefault(y => y.Provider.Name == x.Name)) .Select(x => _providers.FirstOrDefault(y => y.Provider.Slug == x.Slug))
.Where(x => x != null) .Where(x => x != null)
?? _providers; ?? _providers;

View File

@ -113,7 +113,7 @@ namespace Kyoo.Controllers
} }
} }
public async Task<ICollection<Episode>> GetEpisodes(int showID, public async Task<ICollection<Episode>> GetFromShow(int showID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
@ -127,7 +127,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
public async Task<ICollection<Episode>> GetEpisodes(string showSlug, public async Task<ICollection<Episode>> GetFromShow(string showSlug,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
@ -141,7 +141,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
public async Task<ICollection<Episode>> GetEpisodesFromSeason(int seasonID, public async Task<ICollection<Episode>> GetFromSeason(int seasonID,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
Pagination limit = default) Pagination limit = default)
@ -155,7 +155,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
public async Task<ICollection<Episode>> GetEpisodesFromSeason(int showID, public async Task<ICollection<Episode>> GetFromSeason(int showID,
int seasonNumber, int seasonNumber,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,
@ -171,7 +171,7 @@ namespace Kyoo.Controllers
return episodes; return episodes;
} }
public async Task<ICollection<Episode>> GetEpisodesFromSeason(string showSlug, public async Task<ICollection<Episode>> GetFromSeason(string showSlug,
int seasonNumber, int seasonNumber,
Expression<Func<Episode, bool>> where = null, Expression<Func<Episode, bool>> where = null,
Sort<Episode> sort = default, Sort<Episode> sort = default,

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Kyoo.Models; using Kyoo.Models;
using Kyoo.Models.Exceptions; using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
@ -13,12 +14,15 @@ namespace Kyoo.Controllers
{ {
private readonly DatabaseContext _database; private readonly DatabaseContext _database;
private readonly IProviderRepository _providers; private readonly IProviderRepository _providers;
private readonly Lazy<IShowRepository> _shows;
protected override Expression<Func<People, object>> DefaultSort => x => x.Name; protected override Expression<Func<People, object>> DefaultSort => x => x.Name;
public PeopleRepository(DatabaseContext database, IProviderRepository providers) : base(database) public PeopleRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
: base(database)
{ {
_database = database; _database = database;
_providers = providers; _providers = providers;
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
} }
@ -26,17 +30,21 @@ namespace Kyoo.Controllers
{ {
_database.Dispose(); _database.Dispose();
_providers.Dispose(); _providers.Dispose();
if (_shows.IsValueCreated)
_shows.Value.Dispose();
} }
public override async ValueTask DisposeAsync() public override async ValueTask DisposeAsync()
{ {
await _database.DisposeAsync(); await _database.DisposeAsync();
await _providers.DisposeAsync(); await _providers.DisposeAsync();
if (_shows.IsValueCreated)
await _shows.Value.DisposeAsync();
} }
public override async Task<ICollection<People>> Search(string query) public override async Task<ICollection<People>> Search(string query)
{ {
return await _database.Peoples return await _database.People
.Where(people => EF.Functions.ILike(people.Name, $"%{query}%")) .Where(people => EF.Functions.ILike(people.Name, $"%{query}%"))
.Take(20) .Take(20)
.ToListAsync(); .ToListAsync();
@ -89,5 +97,57 @@ namespace Kyoo.Controllers
_database.Entry(link).State = EntityState.Deleted; _database.Entry(link).State = EntityState.Deleted;
await _database.SaveChangesAsync(); await _database.SaveChangesAsync();
} }
public async Task<ICollection<PeopleLink>> GetFromShow(int showID,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default)
{
if (sort.Key?.Body is MemberExpression member)
{
sort.Key = member.Member.Name switch
{
"Name" => x => x.People.Name,
"Slug" => x => x.People.Slug,
_ => sort.Key
};
}
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleLinks.Where(x => x.ShowID == showID),
id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name,
where,
sort,
limit);
if (!people.Any() && await _shows.Value.Get(showID) == null)
throw new ItemNotFound();
return people;
}
public async Task<ICollection<PeopleLink>> GetFromShow(string showSlug,
Expression<Func<PeopleLink, bool>> where = null,
Sort<PeopleLink> sort = default,
Pagination limit = default)
{
if (sort.Key?.Body is MemberExpression member)
{
sort.Key = member.Member.Name switch
{
"Name" => x => x.People.Name,
"Slug" => x => x.People.Slug,
_ => sort.Key
};
}
ICollection<PeopleLink> people = await ApplyFilters(_database.PeopleLinks.Where(x => x.Show.Slug == showSlug),
id => _database.PeopleLinks.FirstOrDefaultAsync(x => x.ID == id),
x => x.People.Name,
where,
sort,
limit);
if (!people.Any() && await _shows.Value.Get(showSlug) == null)
throw new ItemNotFound();
return people;
}
} }
} }

View File

@ -43,7 +43,7 @@ namespace Kyoo.Controllers
{ {
_database.DiscardChanges(); _database.DiscardChanges();
if (IsDuplicateException(ex)) if (IsDuplicateException(ex))
throw new DuplicatedItemException($"Trying to insert a duplicated provider (name {obj.Name} already exists)."); throw new DuplicatedItemException($"Trying to insert a duplicated provider (slug {obj.Slug} already exists).");
throw; throw;
} }

View File

@ -116,7 +116,7 @@ namespace Kyoo.Controllers
} }
} }
public async Task<ICollection<Season>> GetSeasons(int showID, public async Task<ICollection<Season>> GetFromShow(int showID,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default) Pagination limit = default)
@ -130,7 +130,7 @@ namespace Kyoo.Controllers
return seasons; return seasons;
} }
public async Task<ICollection<Season>> GetSeasons(string showSlug, public async Task<ICollection<Season>> GetFromShow(string showSlug,
Expression<Func<Season, bool>> where = null, Expression<Func<Season, bool>> where = null,
Sort<Season> sort = default, Sort<Season> sort = default,
Pagination limit = default) Pagination limit = default)

View File

@ -60,7 +60,7 @@ namespace Kyoo
public DbSet<Episode> Episodes { get; set; } public DbSet<Episode> Episodes { get; set; }
public DbSet<Track> Tracks { get; set; } public DbSet<Track> Tracks { get; set; }
public DbSet<Genre> Genres { get; set; } public DbSet<Genre> Genres { get; set; }
public DbSet<People> Peoples { get; set; } public DbSet<People> People { get; set; }
public DbSet<Studio> Studios { get; set; } public DbSet<Studio> Studios { get; set; }
public DbSet<ProviderID> Providers { get; set; } public DbSet<ProviderID> Providers { get; set; }
public DbSet<MetadataID> MetadataIds { get; set; } public DbSet<MetadataID> MetadataIds { get; set; }
@ -167,7 +167,7 @@ namespace Kyoo
.HasIndex(x => x.Slug) .HasIndex(x => x.Slug)
.IsUnique(); .IsUnique();
modelBuilder.Entity<ProviderID>() modelBuilder.Entity<ProviderID>()
.HasIndex(x => x.Name) .HasIndex(x => x.Slug)
.IsUnique(); .IsUnique();
modelBuilder.Entity<Season>() modelBuilder.Entity<Season>()
.HasIndex(x => new {x.ShowID, x.SeasonNumber}) .HasIndex(x => new {x.ShowID, x.SeasonNumber})

View File

@ -10,7 +10,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Kyoo.Models.DatabaseMigrations.Internal namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
[DbContext(typeof(DatabaseContext))] [DbContext(typeof(DatabaseContext))]
[Migration("20200623233713_Initial")] [Migration("20200724211017_Initial")]
partial class Initial partial class Initial
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
@ -274,7 +274,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("Slug") b.HasIndex("Slug")
.IsUnique(); .IsUnique();
b.ToTable("Peoples"); b.ToTable("People");
}); });
modelBuilder.Entity("Kyoo.Models.PeopleLink", b => modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
@ -318,9 +318,12 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Slug")
.HasColumnType("text");
b.HasKey("ID"); b.HasKey("ID");
b.HasIndex("Name") b.HasIndex("Slug")
.IsUnique(); .IsUnique();
b.ToTable("Providers"); b.ToTable("Providers");

View File

@ -55,7 +55,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Peoples", name: "People",
columns: table => new columns: table => new
{ {
ID = table.Column<int>(nullable: false) ID = table.Column<int>(nullable: false)
@ -66,7 +66,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
}, },
constraints: table => constraints: table =>
{ {
table.PrimaryKey("PK_Peoples", x => x.ID); table.PrimaryKey("PK_People", x => x.ID);
}); });
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
@ -75,6 +75,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
ID = table.Column<int>(nullable: false) ID = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Slug = table.Column<string>(nullable: true),
Name = table.Column<string>(nullable: true), Name = table.Column<string>(nullable: true),
Logo = table.Column<string>(nullable: true) Logo = table.Column<string>(nullable: true)
}, },
@ -253,9 +254,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
{ {
table.PrimaryKey("PK_PeopleLinks", x => x.ID); table.PrimaryKey("PK_PeopleLinks", x => x.ID);
table.ForeignKey( table.ForeignKey(
name: "FK_PeopleLinks_Peoples_PeopleID", name: "FK_PeopleLinks_People_PeopleID",
column: x => x.PeopleID, column: x => x.PeopleID,
principalTable: "Peoples", principalTable: "People",
principalColumn: "ID", principalColumn: "ID",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
table.ForeignKey( table.ForeignKey(
@ -349,9 +350,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
principalColumn: "ID", principalColumn: "ID",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
table.ForeignKey( table.ForeignKey(
name: "FK_MetadataIds_Peoples_PeopleID", name: "FK_MetadataIds_People_PeopleID",
column: x => x.PeopleID, column: x => x.PeopleID,
principalTable: "Peoples", principalTable: "People",
principalColumn: "ID", principalColumn: "ID",
onDelete: ReferentialAction.Cascade); onDelete: ReferentialAction.Cascade);
table.ForeignKey( table.ForeignKey(
@ -485,6 +486,12 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
table: "MetadataIds", table: "MetadataIds",
column: "ShowID"); column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_People_Slug",
table: "People",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_PeopleLinks_PeopleID", name: "IX_PeopleLinks_PeopleID",
table: "PeopleLinks", table: "PeopleLinks",
@ -495,12 +502,6 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
table: "PeopleLinks", table: "PeopleLinks",
column: "ShowID"); column: "ShowID");
migrationBuilder.CreateIndex(
name: "IX_Peoples_Slug",
table: "Peoples",
column: "Slug",
unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_ProviderLinks_LibraryID", name: "IX_ProviderLinks_LibraryID",
table: "ProviderLinks", table: "ProviderLinks",
@ -512,9 +513,9 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
column: "ProviderID"); column: "ProviderID");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Providers_Name", name: "IX_Providers_Slug",
table: "Providers", table: "Providers",
column: "Name", column: "Slug",
unique: true); unique: true);
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
@ -576,7 +577,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
name: "Collections"); name: "Collections");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Peoples"); name: "People");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Libraries"); name: "Libraries");

View File

@ -272,7 +272,7 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.HasIndex("Slug") b.HasIndex("Slug")
.IsUnique(); .IsUnique();
b.ToTable("Peoples"); b.ToTable("People");
}); });
modelBuilder.Entity("Kyoo.Models.PeopleLink", b => modelBuilder.Entity("Kyoo.Models.PeopleLink", b =>
@ -316,9 +316,12 @@ namespace Kyoo.Models.DatabaseMigrations.Internal
b.Property<string>("Name") b.Property<string>("Name")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("Slug")
.HasColumnType("text");
b.HasKey("ID"); b.HasKey("ID");
b.HasIndex("Name") b.HasIndex("Slug")
.IsUnique(); .IsUnique();
b.ToTable("Providers"); b.ToTable("Providers");

View File

@ -63,7 +63,7 @@ namespace Kyoo.Controllers
if (!Directory.Exists(show.Path)) if (!Directory.Exists(show.Path))
await libraryManager.DeleteShow(show); await libraryManager.DeleteShow(show);
ICollection<Episode> episodes = await libraryManager.GetEpisodes(); ICollection<Episode> episodes = await libraryManager.GetEpisodesFromShow();
ICollection<Library> libraries = argument == null ICollection<Library> libraries = argument == null
? await libraryManager.GetLibraries() ? await libraryManager.GetLibraries()
: new [] { await libraryManager.GetLibrary(argument)}; : new [] { await libraryManager.GetLibrary(argument)};

View File

@ -23,7 +23,7 @@ namespace Kyoo.Tasks
DatabaseContext database = serviceScope.ServiceProvider.GetService<DatabaseContext>(); DatabaseContext database = serviceScope.ServiceProvider.GetService<DatabaseContext>();
IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>(); IPluginManager pluginManager = serviceScope.ServiceProvider.GetService<IPluginManager>();
foreach (IMetadataProvider provider in pluginManager.GetPlugins<IMetadataProvider>()) foreach (IMetadataProvider provider in pluginManager.GetPlugins<IMetadataProvider>())
database.Providers.AddIfNotExist(provider.Provider, x => x.Name == provider.Provider.Name); database.Providers.AddIfNotExist(provider.Provider, x => x.Slug == provider.Provider.Slug);
database.SaveChanges(); database.SaveChanges();
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@ -41,7 +41,7 @@ namespace Kyoo.Api
try try
{ {
ICollection<Season> ressources = await _libraryManager.GetSeasons(showID, ICollection<Season> ressources = await _libraryManager.GetSeasonsFromShow(showID,
ApiHelper.ParseWhere<Season>(where), ApiHelper.ParseWhere<Season>(where),
new Sort<Season>(sortBy), new Sort<Season>(sortBy),
new Pagination(limit, afterID)); new Pagination(limit, afterID));
@ -74,7 +74,7 @@ namespace Kyoo.Api
try try
{ {
ICollection<Season> ressources = await _libraryManager.GetSeasons(slug, ICollection<Season> ressources = await _libraryManager.GetSeasonsFromShow(slug,
ApiHelper.ParseWhere<Season>(where), ApiHelper.ParseWhere<Season>(where),
new Sort<Season>(sortBy), new Sort<Season>(sortBy),
new Pagination(limit, afterID)); new Pagination(limit, afterID));
@ -107,7 +107,7 @@ namespace Kyoo.Api
try try
{ {
ICollection<Episode> ressources = await _libraryManager.GetEpisodes(showID, ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromShow(showID,
ApiHelper.ParseWhere<Episode>(where), ApiHelper.ParseWhere<Episode>(where),
new Sort<Episode>(sortBy), new Sort<Episode>(sortBy),
new Pagination(limit, afterID)); new Pagination(limit, afterID));
@ -131,7 +131,7 @@ namespace Kyoo.Api
[FromQuery] string sortBy, [FromQuery] string sortBy,
[FromQuery] int afterID, [FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where, [FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20) [FromQuery] int limit = 50)
{ {
where.Remove("slug"); where.Remove("slug");
where.Remove("sortBy"); where.Remove("sortBy");
@ -140,7 +140,7 @@ namespace Kyoo.Api
try try
{ {
ICollection<Episode> ressources = await _libraryManager.GetEpisodes(slug, ICollection<Episode> ressources = await _libraryManager.GetEpisodesFromShow(slug,
ApiHelper.ParseWhere<Episode>(where), ApiHelper.ParseWhere<Episode>(where),
new Sort<Episode>(sortBy), new Sort<Episode>(sortBy),
new Pagination(limit, afterID)); new Pagination(limit, afterID));
@ -156,5 +156,69 @@ namespace Kyoo.Api
return BadRequest(new {Error = ex.Message}); return BadRequest(new {Error = ex.Message});
} }
} }
[HttpGet("{showID:int}/people")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Page<PeopleLink>>> GetPeople(int showID,
[FromQuery] string sortBy,
[FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<PeopleLink> ressources = await _libraryManager.GetPeopleFromShow(showID,
ApiHelper.ParseWhere<PeopleLink>(where),
new Sort<PeopleLink>(sortBy),
new Pagination(limit, afterID));
return Page(ressources, limit);
}
catch (ItemNotFound)
{
return NotFound();
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
[HttpGet("{slug}/people")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Page<PeopleLink>>> GetPeople(string slug,
[FromQuery] string sortBy,
[FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<PeopleLink> ressources = await _libraryManager.GetPeopleFromShow(slug,
ApiHelper.ParseWhere<PeopleLink>(where),
new Sort<PeopleLink>(sortBy),
new Pagination(limit, afterID));
return Page(ressources, limit);
}
catch (ItemNotFound)
{
return NotFound();
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
} }
} }