diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index 8e4ac262..0a849ec7 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -190,7 +190,18 @@ namespace Kyoo.Controllers Pagination limit = default ) => GetProviders(where, new Sort(sort), limit); - + + // Counts + Task GetLibrariesCount(Expression> where = null); + Task GetCollectionsCount(Expression> where = null); + Task GetShowsCount(Expression> where = null); + Task GetSeasonsCount(Expression> where = null); + Task GetEpisodesCount(Expression> where = null); + Task GetTracksCount(Expression> where = null); + Task GetGenresCount(Expression> where = null); + Task GetStudiosCount(Expression> where = null); + Task GetPeopleCount(Expression> where = null); + // Search Task> SearchLibraries(string searchQuery); Task> SearchCollections(string searchQuery); diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs index 21ff1478..3aee67c4 100644 --- a/Kyoo.Common/Controllers/IRepository.cs +++ b/Kyoo.Common/Controllers/IRepository.cs @@ -90,6 +90,9 @@ namespace Kyoo.Controllers Expression> sort, Pagination limit = default ) => GetAll(where, new Sort(sort), limit); + + Task GetCount(Expression> where = null); + Task Create([NotNull] T obj); Task CreateIfNotExists([NotNull] T obj); diff --git a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs index 4ef27fb1..87e9b383 100644 --- a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs +++ b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs @@ -338,6 +338,51 @@ namespace Kyoo.Controllers return PeopleRepository.GetFromPeople(slug, where, sort, limit); } + public Task GetLibrariesCount(Expression> where = null) + { + return LibraryRepository.GetCount(where); + } + + public Task GetCollectionsCount(Expression> where = null) + { + return CollectionRepository.GetCount(where); + } + + public Task GetShowsCount(Expression> where = null) + { + return ShowRepository.GetCount(where); + } + + public Task GetSeasonsCount(Expression> where = null) + { + return SeasonRepository.GetCount(where); + } + + public Task GetEpisodesCount(Expression> where = null) + { + return EpisodeRepository.GetCount(where); + } + + public Task GetTracksCount(Expression> where = null) + { + return TrackRepository.GetCount(where); + } + + public Task GetGenresCount(Expression> where = null) + { + return GenreRepository.GetCount(where); + } + + public Task GetStudiosCount(Expression> where = null) + { + return StudioRepository.GetCount(where); + } + + public Task GetPeopleCount(Expression> where = null) + { + return PeopleRepository.GetCount(where); + } + public Task AddShowLink(int showID, int? libraryID, int? collectionID) { return ShowRepository.AddShowLink(showID, libraryID, collectionID); diff --git a/Kyoo.Common/Models/WatchItem.cs b/Kyoo.Common/Models/WatchItem.cs index 141b139c..4e1bfbcc 100644 --- a/Kyoo.Common/Models/WatchItem.cs +++ b/Kyoo.Common/Models/WatchItem.cs @@ -1,7 +1,8 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Linq; +using System.Threading.Tasks; +using Kyoo.Controllers; using Kyoo.Models.Watch; namespace Kyoo.Models @@ -59,53 +60,55 @@ namespace Kyoo.Models string title, DateTime? releaseDate, string path, + Track video, IEnumerable audios, - IEnumerable subtitles, - Track video) + IEnumerable subtitles) : this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path) { + Video = video; Audios = audios; Subtitles = subtitles; - Video = video; } - public WatchItem(Episode episode) - : this(episode.ID, - episode.Show.Title, - episode.Show.Slug, - episode.SeasonNumber, - episode.EpisodeNumber, - episode.Title, - episode.ReleaseDate, - episode.Path, - episode.Tracks.Where(x => x.Type == StreamType.Audio), - episode.Tracks.Where(x => x.Type == StreamType.Subtitle), - episode.Tracks.FirstOrDefault(x => x.Type == StreamType.Video)) + public static async Task FromEpisode(Episode ep, ILibraryManager library) { - if (episode.Show.IsMovie) - { - IsMovie = true; - return; - } + Show show = await library.GetShow(ep.ShowID); // TODO load only the title, the slug & the IsMovie with the library manager. + Episode previous = null; + Episode next = null; - if (EpisodeNumber > 1) - PreviousEpisode = episode.Season.Episodes.FirstOrDefault(x => x.EpisodeNumber == EpisodeNumber - 1); - else if (SeasonNumber > 1) + if (!show.IsMovie) { - Season previousSeason = episode.Show.Seasons - .FirstOrDefault(x => x.SeasonNumber == SeasonNumber - 1); - PreviousEpisode = previousSeason?.Episodes - .FirstOrDefault(x => x.EpisodeNumber == previousSeason.Episodes.Count()); - } + if (ep.EpisodeNumber > 1) + previous = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1); + else if (ep.SeasonNumber > 1) + { + int count = await library.GetEpisodesCount(x => x.ShowID == ep.ShowID + && x.SeasonNumber == ep.SeasonNumber - 1); + previous = await library.GetEpisode(ep.ShowID, ep.SeasonNumber - 1, count); + } - if (EpisodeNumber >= episode.Season.Episodes.Count()) - { - NextEpisode = episode.Show.Seasons - .FirstOrDefault(x => x.SeasonNumber == SeasonNumber + 1)?.Episodes - .FirstOrDefault(x => x.EpisodeNumber == 1); + if (ep.EpisodeNumber >= await library.GetEpisodesCount(x => x.SeasonID == ep.SeasonID)) + next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber + 1, 1); + else + next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1); } - else - NextEpisode = episode.Season.Episodes.FirstOrDefault(x => x.EpisodeNumber == EpisodeNumber + 1); + + return new WatchItem(ep.ID, + show.Title, + show.Slug, + ep.SeasonNumber, + ep.EpisodeNumber, + ep.Title, + ep.ReleaseDate, + ep.Path, + await library.GetTrack(x => x.EpisodeID == ep.ID && x.Type == StreamType.Video), + await library.GetTracks(x => x.EpisodeID == ep.ID && x.Type == StreamType.Audio), + await library.GetTracks(x => x.EpisodeID == ep.ID && x.Type == StreamType.Subtitle)) + { + IsMovie = show.IsMovie, + PreviousEpisode = previous, + NextEpisode = next + }; } } } diff --git a/Kyoo.CommonAPI/CrudApi.cs b/Kyoo.CommonAPI/CrudApi.cs index 9f01a9ca..dffcb7b3 100644 --- a/Kyoo.CommonAPI/CrudApi.cs +++ b/Kyoo.CommonAPI/CrudApi.cs @@ -47,6 +47,20 @@ namespace Kyoo.CommonApi return resource; } + [HttpGet("count")] + [Authorize(Policy = "Read")] + public virtual async Task> GetCount([FromQuery] Dictionary where) + { + try + { + return await _repository.GetCount(ApiHelper.ParseWhere(where)); + } + catch (ArgumentException ex) + { + return BadRequest(new {Error = ex.Message}); + } + } + [HttpGet] [Authorize(Policy = "Read")] public virtual async Task>> GetAll([FromQuery] string sortBy, diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs index 2c7fa9ec..b106bf96 100644 --- a/Kyoo.CommonAPI/LocalRepository.cs +++ b/Kyoo.CommonAPI/LocalRepository.cs @@ -101,6 +101,14 @@ namespace Kyoo.Controllers return await query.ToListAsync(); } + public virtual Task GetCount(Expression> where = null) + { + IQueryable query = Database.Set(); + if (where != null) + query = query.Where(where); + return query.CountAsync(); + } + public virtual async Task Create([NotNull] T obj) { if (obj == null) @@ -258,6 +266,14 @@ namespace Kyoo.Controllers return items.ToList(); } + + public virtual Task GetCount(Expression> where = null) + { + IQueryable query = Database.Set(); + if (where != null) + query = query.Where(where.Convert>()); + return query.CountAsync(); + } Task IRepository.Create(T item) { diff --git a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs index faf0feaf..07f0251e 100644 --- a/Kyoo/Controllers/Repositories/LibraryItemRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryItemRepository.cs @@ -83,6 +83,14 @@ namespace Kyoo.Controllers return ApplyFilters(ItemsQuery, where, sort, limit); } + public override Task GetCount(Expression> where = null) + { + IQueryable query = ItemsQuery; + if (where != null) + query = query.Where(where); + return query.CountAsync(); + } + public async Task> Search(string query) { return await ItemsQuery diff --git a/Kyoo/Views/API/CollectionApi.cs b/Kyoo/Views/API/CollectionApi.cs index 741d75eb..254be6b6 100644 --- a/Kyoo/Views/API/CollectionApi.cs +++ b/Kyoo/Views/API/CollectionApi.cs @@ -6,7 +6,6 @@ using Kyoo.Models; using Microsoft.AspNetCore.Mvc; using System.Threading.Tasks; using Kyoo.CommonApi; -using Kyoo.Models.Exceptions; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Configuration; diff --git a/Kyoo/Views/API/WatchAPI.cs b/Kyoo/Views/API/WatchApi.cs similarity index 58% rename from Kyoo/Views/API/WatchAPI.cs rename to Kyoo/Views/API/WatchApi.cs index 5166fac5..9aba42d1 100644 --- a/Kyoo/Views/API/WatchAPI.cs +++ b/Kyoo/Views/API/WatchApi.cs @@ -6,38 +6,35 @@ using Microsoft.AspNetCore.Mvc; namespace Kyoo.Api { - [Route("api/[controller]")] + [Route("api/watch")] [ApiController] - public class WatchController : ControllerBase + public class WatchApi : ControllerBase { private readonly ILibraryManager _libraryManager; - public WatchController(ILibraryManager libraryManager) + public WatchApi(ILibraryManager libraryManager) { _libraryManager = libraryManager; } [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [Authorize(Policy="Read")] - public async Task> Index(string showSlug, int seasonNumber, int episodeNumber) + public async Task> GetWatchItem(string showSlug, int seasonNumber, int episodeNumber) { Episode item = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber); - - if(item == null) + if (item == null) return NotFound(); - - return new WatchItem(item); + return await WatchItem.FromEpisode(item, _libraryManager); } [HttpGet("{movieSlug}")] [Authorize(Policy="Read")] - public async Task> Index(string movieSlug) + public async Task> GetWatchItem(string movieSlug) { Episode item = await _libraryManager.GetMovieEpisode(movieSlug); - - if(item == null) + if (item == null) return NotFound(); - return new WatchItem(item); + return await WatchItem.FromEpisode(item, _libraryManager); } } }