Reworking the whole watch api and creating a /count endpoint for crud items

This commit is contained in:
Zoe Roux 2020-10-10 02:33:34 +02:00
parent 423c0cd658
commit cdf5acbbe9
9 changed files with 146 additions and 50 deletions

View File

@ -190,7 +190,18 @@ namespace Kyoo.Controllers
Pagination limit = default Pagination limit = default
) => GetProviders(where, new Sort<ProviderID>(sort), limit); ) => GetProviders(where, new Sort<ProviderID>(sort), limit);
// 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);
// Search // Search
Task<ICollection<Library>> SearchLibraries(string searchQuery); Task<ICollection<Library>> SearchLibraries(string searchQuery);
Task<ICollection<Collection>> SearchCollections(string searchQuery); Task<ICollection<Collection>> SearchCollections(string searchQuery);

View File

@ -90,6 +90,9 @@ namespace Kyoo.Controllers
Expression<Func<T, object>> sort, Expression<Func<T, object>> sort,
Pagination limit = default Pagination limit = default
) => GetAll(where, new Sort<T>(sort), limit); ) => GetAll(where, new Sort<T>(sort), limit);
Task<int> GetCount(Expression<Func<T, bool>> where = null);
Task<T> Create([NotNull] T obj); Task<T> Create([NotNull] T obj);
Task<T> CreateIfNotExists([NotNull] T obj); Task<T> CreateIfNotExists([NotNull] T obj);

View File

@ -338,6 +338,51 @@ namespace Kyoo.Controllers
return PeopleRepository.GetFromPeople(slug, where, sort, limit); return PeopleRepository.GetFromPeople(slug, where, sort, limit);
} }
public Task<int> GetLibrariesCount(Expression<Func<Library, bool>> where = null)
{
return LibraryRepository.GetCount(where);
}
public Task<int> GetCollectionsCount(Expression<Func<Collection, bool>> where = null)
{
return CollectionRepository.GetCount(where);
}
public Task<int> GetShowsCount(Expression<Func<Show, bool>> where = null)
{
return ShowRepository.GetCount(where);
}
public Task<int> GetSeasonsCount(Expression<Func<Season, bool>> where = null)
{
return SeasonRepository.GetCount(where);
}
public Task<int> GetEpisodesCount(Expression<Func<Episode, bool>> where = null)
{
return EpisodeRepository.GetCount(where);
}
public Task<int> GetTracksCount(Expression<Func<Track, bool>> where = null)
{
return TrackRepository.GetCount(where);
}
public Task<int> GetGenresCount(Expression<Func<Genre, bool>> where = null)
{
return GenreRepository.GetCount(where);
}
public Task<int> GetStudiosCount(Expression<Func<Studio, bool>> where = null)
{
return StudioRepository.GetCount(where);
}
public Task<int> GetPeopleCount(Expression<Func<People, bool>> where = null)
{
return PeopleRepository.GetCount(where);
}
public Task AddShowLink(int showID, int? libraryID, int? collectionID) public Task AddShowLink(int showID, int? libraryID, int? collectionID)
{ {
return ShowRepository.AddShowLink(showID, libraryID, collectionID); return ShowRepository.AddShowLink(showID, libraryID, collectionID);

View File

@ -1,7 +1,8 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models.Watch; using Kyoo.Models.Watch;
namespace Kyoo.Models namespace Kyoo.Models
@ -59,53 +60,55 @@ namespace Kyoo.Models
string title, string title,
DateTime? releaseDate, DateTime? releaseDate,
string path, string path,
Track video,
IEnumerable<Track> audios, IEnumerable<Track> audios,
IEnumerable<Track> subtitles, IEnumerable<Track> subtitles)
Track video)
: this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path) : this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path)
{ {
Video = video;
Audios = audios; Audios = audios;
Subtitles = subtitles; Subtitles = subtitles;
Video = video;
} }
public WatchItem(Episode episode) public static async Task<WatchItem> FromEpisode(Episode ep, ILibraryManager library)
: 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))
{ {
if (episode.Show.IsMovie) Show show = await library.GetShow(ep.ShowID); // TODO load only the title, the slug & the IsMovie with the library manager.
{ Episode previous = null;
IsMovie = true; Episode next = null;
return;
}
if (EpisodeNumber > 1) if (!show.IsMovie)
PreviousEpisode = episode.Season.Episodes.FirstOrDefault(x => x.EpisodeNumber == EpisodeNumber - 1);
else if (SeasonNumber > 1)
{ {
Season previousSeason = episode.Show.Seasons if (ep.EpisodeNumber > 1)
.FirstOrDefault(x => x.SeasonNumber == SeasonNumber - 1); previous = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber - 1);
PreviousEpisode = previousSeason?.Episodes else if (ep.SeasonNumber > 1)
.FirstOrDefault(x => x.EpisodeNumber == previousSeason.Episodes.Count()); {
} 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()) if (ep.EpisodeNumber >= await library.GetEpisodesCount(x => x.SeasonID == ep.SeasonID))
{ next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber + 1, 1);
NextEpisode = episode.Show.Seasons else
.FirstOrDefault(x => x.SeasonNumber == SeasonNumber + 1)?.Episodes next = await library.GetEpisode(ep.ShowID, ep.SeasonNumber, ep.EpisodeNumber + 1);
.FirstOrDefault(x => x.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
};
} }
} }
} }

View File

@ -47,6 +47,20 @@ namespace Kyoo.CommonApi
return resource; return resource;
} }
[HttpGet("count")]
[Authorize(Policy = "Read")]
public virtual async Task<ActionResult<int>> GetCount([FromQuery] Dictionary<string, string> where)
{
try
{
return await _repository.GetCount(ApiHelper.ParseWhere<T>(where));
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
[HttpGet] [HttpGet]
[Authorize(Policy = "Read")] [Authorize(Policy = "Read")]
public virtual async Task<ActionResult<Page<T>>> GetAll([FromQuery] string sortBy, public virtual async Task<ActionResult<Page<T>>> GetAll([FromQuery] string sortBy,

View File

@ -101,6 +101,14 @@ namespace Kyoo.Controllers
return await query.ToListAsync(); return await query.ToListAsync();
} }
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
{
IQueryable<T> query = Database.Set<T>();
if (where != null)
query = query.Where(where);
return query.CountAsync();
}
public virtual async Task<T> Create([NotNull] T obj) public virtual async Task<T> Create([NotNull] T obj)
{ {
if (obj == null) if (obj == null)
@ -258,6 +266,14 @@ namespace Kyoo.Controllers
return items.ToList<T>(); return items.ToList<T>();
} }
public virtual Task<int> GetCount(Expression<Func<T, bool>> where = null)
{
IQueryable<TInternal> query = Database.Set<TInternal>();
if (where != null)
query = query.Where(where.Convert<Func<TInternal, bool>>());
return query.CountAsync();
}
Task<T> IRepository<T>.Create(T item) Task<T> IRepository<T>.Create(T item)
{ {

View File

@ -83,6 +83,14 @@ namespace Kyoo.Controllers
return ApplyFilters(ItemsQuery, where, sort, limit); return ApplyFilters(ItemsQuery, where, sort, limit);
} }
public override Task<int> GetCount(Expression<Func<LibraryItem, bool>> where = null)
{
IQueryable<LibraryItem> query = ItemsQuery;
if (where != null)
query = query.Where(where);
return query.CountAsync();
}
public async Task<ICollection<LibraryItem>> Search(string query) public async Task<ICollection<LibraryItem>> Search(string query)
{ {
return await ItemsQuery return await ItemsQuery

View File

@ -6,7 +6,6 @@ using Kyoo.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks; using System.Threading.Tasks;
using Kyoo.CommonApi; using Kyoo.CommonApi;
using Kyoo.Models.Exceptions;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;

View File

@ -6,38 +6,35 @@ using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Api namespace Kyoo.Api
{ {
[Route("api/[controller]")] [Route("api/watch")]
[ApiController] [ApiController]
public class WatchController : ControllerBase public class WatchApi : ControllerBase
{ {
private readonly ILibraryManager _libraryManager; private readonly ILibraryManager _libraryManager;
public WatchController(ILibraryManager libraryManager) public WatchApi(ILibraryManager libraryManager)
{ {
_libraryManager = libraryManager; _libraryManager = libraryManager;
} }
[HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")] [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}")]
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
public async Task<ActionResult<WatchItem>> Index(string showSlug, int seasonNumber, int episodeNumber) public async Task<ActionResult<WatchItem>> GetWatchItem(string showSlug, int seasonNumber, int episodeNumber)
{ {
Episode item = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber); Episode item = await _libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
if (item == null)
if(item == null)
return NotFound(); return NotFound();
return await WatchItem.FromEpisode(item, _libraryManager);
return new WatchItem(item);
} }
[HttpGet("{movieSlug}")] [HttpGet("{movieSlug}")]
[Authorize(Policy="Read")] [Authorize(Policy="Read")]
public async Task<ActionResult<WatchItem>> Index(string movieSlug) public async Task<ActionResult<WatchItem>> GetWatchItem(string movieSlug)
{ {
Episode item = await _libraryManager.GetMovieEpisode(movieSlug); Episode item = await _libraryManager.GetMovieEpisode(movieSlug);
if (item == null)
if(item == null)
return NotFound(); return NotFound();
return new WatchItem(item); return await WatchItem.FromEpisode(item, _libraryManager);
} }
} }
} }