mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
API: Creating a common thumbs api
This commit is contained in:
parent
41cbc50940
commit
9b3eb7fede
@ -19,6 +19,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace Kyoo.Abstractions.Models.Utils
|
namespace Kyoo.Abstractions.Models.Utils
|
||||||
@ -86,6 +87,29 @@ namespace Kyoo.Abstractions.Models.Utils
|
|||||||
: slugFunc(_slug);
|
: slugFunc(_slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return true if this <see cref="Identifier"/> match a resource.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="resource">The resource to match</param>
|
||||||
|
/// <returns>
|
||||||
|
/// <c>true</c> if the <paramref name="resource"/> match this identifier, <c>false</c> otherwise.
|
||||||
|
/// </returns>
|
||||||
|
public bool IsSame(IResource resource)
|
||||||
|
{
|
||||||
|
return Match(
|
||||||
|
id => resource.ID == id,
|
||||||
|
slug => resource.Slug == slug
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<T, bool>> IsSame<T>()
|
||||||
|
where T : IResource
|
||||||
|
{
|
||||||
|
return _id.HasValue
|
||||||
|
? x => x.ID == _id
|
||||||
|
: x => x.Slug == _slug;
|
||||||
|
}
|
||||||
|
|
||||||
public class IdentifierConvertor : TypeConverter
|
public class IdentifierConvertor : TypeConverter
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -31,14 +31,14 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Where to start? Using the given sort.
|
/// Where to start? Using the given sort.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int AfterID { get; }
|
public int? AfterID { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="Pagination"/> instance.
|
/// Create a new <see cref="Pagination"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="count">Set the <see cref="Count"/> value</param>
|
/// <param name="count">Set the <see cref="Count"/> value</param>
|
||||||
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
|
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
|
||||||
public Pagination(int count, int afterID = 0)
|
public Pagination(int count, int? afterID = null)
|
||||||
{
|
{
|
||||||
Count = count;
|
Count = count;
|
||||||
AfterID = afterID;
|
AfterID = afterID;
|
||||||
|
@ -179,9 +179,9 @@ namespace Kyoo.Core.Controllers
|
|||||||
|
|
||||||
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 != null)
|
||||||
{
|
{
|
||||||
TValue after = await get(limit.AfterID);
|
TValue after = await get(limit.AfterID.Value);
|
||||||
Expression key = Expression.Constant(sortKey.Compile()(after), sortExpression.Type);
|
Expression key = Expression.Constant(sortKey.Compile()(after), sortExpression.Type);
|
||||||
query = query.Where(Expression.Lambda<Func<TValue, bool>>(
|
query = query.Where(Expression.Lambda<Func<TValue, bool>>(
|
||||||
ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortExpression, key),
|
ApiHelper.StringCompatibleExpression(Expression.GreaterThan, sortExpression, key),
|
||||||
|
@ -22,7 +22,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Abstractions.Controllers;
|
using Kyoo.Abstractions.Controllers;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
using Kyoo.Abstractions.Models.Exceptions;
|
|
||||||
using Kyoo.Abstractions.Models.Permissions;
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
using Kyoo.Abstractions.Models.Utils;
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
using Kyoo.Core.Models.Options;
|
using Kyoo.Core.Models.Options;
|
||||||
@ -40,111 +39,56 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/collection", Order = AlternativeRoute)]
|
[Route("api/collection", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(CollectionApi))]
|
[PartialPermission(nameof(CollectionApi))]
|
||||||
public class CollectionApi : CrudApi<Collection>
|
public class CollectionApi : CrudThumbsApi<Collection>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The library manager used to modify or retrieve information about the data store.
|
/// The library manager used to modify or retrieve information about the data store.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The file manager used to send images.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IFileSystem _files;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The thumbnail manager used to retrieve images paths.
|
|
||||||
/// </summary>
|
|
||||||
private readonly IThumbnailsManager _thumbs;
|
|
||||||
|
|
||||||
public CollectionApi(ILibraryManager libraryManager,
|
public CollectionApi(ILibraryManager libraryManager,
|
||||||
IFileSystem files,
|
IFileSystem files,
|
||||||
IThumbnailsManager thumbs,
|
IThumbnailsManager thumbs,
|
||||||
IOptions<BasicOptions> options)
|
IOptions<BasicOptions> options)
|
||||||
: base(libraryManager.CollectionRepository, options.Value.PublicUrl)
|
: base(libraryManager.CollectionRepository, files, thumbs, options.Value.PublicUrl)
|
||||||
{
|
{
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
_files = files;
|
|
||||||
_thumbs = thumbs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get shows in collection (via id)
|
/// Get shows in collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Lists the shows that are contained in the collection with the given id.
|
/// Lists the shows that are contained in the collection with the given id or slug.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="id">The ID of the <see cref="Collection"/>.</param>
|
/// <param name="identifier">The ID or slug of the <see cref="Collection"/>.</param>
|
||||||
/// <param name="sortBy">A key to sort shows by.</param>
|
/// <param name="sortBy">A key to sort shows by.</param>
|
||||||
/// <param name="afterID">An optional show's ID to start the query from this specific item.</param>
|
|
||||||
/// <param name="where">An optional list of filters.</param>
|
/// <param name="where">An optional list of filters.</param>
|
||||||
/// <param name="limit">The number of shows to return.</param>
|
/// <param name="limit">The number of shows to return.</param>
|
||||||
|
/// <param name="afterID">An optional show's ID to start the query from this specific item.</param>
|
||||||
/// <returns>A page of shows.</returns>
|
/// <returns>A page of shows.</returns>
|
||||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||||
/// <response code="404">No collection with the given ID could be found.</response>
|
/// <response code="404">No collection with the given ID could be found.</response>
|
||||||
[HttpGet("{id:int}/shows")]
|
[HttpGet("{identifier:id}/shows")]
|
||||||
[HttpGet("{id:int}/show", Order = AlternativeRoute)]
|
[HttpGet("{identifier:id}/show", Order = AlternativeRoute)]
|
||||||
[PartialPermission(Kind.Read)]
|
[PartialPermission(Kind.Read)]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<Page<Show>>> GetShows(int id,
|
public async Task<ActionResult<Page<Show>>> GetShows(Identifier identifier,
|
||||||
[FromQuery] string sortBy,
|
[FromQuery] string sortBy,
|
||||||
[FromQuery] int afterID,
|
|
||||||
[FromQuery] Dictionary<string, string> where,
|
[FromQuery] Dictionary<string, string> where,
|
||||||
[FromQuery] int limit = 30)
|
[FromQuery] int limit = 30,
|
||||||
|
[FromQuery] int? afterID = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere<Show>(where, x => x.Collections.Any(y => y.ID == id)),
|
ApiHelper.ParseWhere<Show>(where, x => x.Collections.Any(identifier.IsSame)),
|
||||||
new Sort<Show>(sortBy),
|
new Sort<Show>(sortBy),
|
||||||
new Pagination(limit, afterID));
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
if (!resources.Any() && await _libraryManager.GetOrDefault<Collection>(id) == null)
|
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Collection>()) == null)
|
||||||
return NotFound();
|
|
||||||
return Page(resources, limit);
|
|
||||||
}
|
|
||||||
catch (ArgumentException ex)
|
|
||||||
{
|
|
||||||
return BadRequest(new RequestError(ex.Message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get shows in collection (via slug)
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Lists the shows that are contained in the collection with the given slug.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="slug">The slug of the <see cref="Collection"/>.</param>
|
|
||||||
/// <param name="sortBy">A key to sort shows by.</param>
|
|
||||||
/// <param name="afterID">An optional show's ID to start the query from this specific item.</param>
|
|
||||||
/// <param name="where">An optional list of filters.</param>
|
|
||||||
/// <param name="limit">The number of shows to return.</param>
|
|
||||||
/// <returns>A page of shows.</returns>
|
|
||||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
|
||||||
/// <response code="404">No collection with the given slug could be found.</response>
|
|
||||||
[HttpGet("{slug}/shows")]
|
|
||||||
[HttpGet("{slug}/show", Order = AlternativeRoute)]
|
|
||||||
[PartialPermission(Kind.Read)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ActionResult<Page<Show>>> GetShows(string slug,
|
|
||||||
[FromQuery] string sortBy,
|
|
||||||
[FromQuery] int afterID,
|
|
||||||
[FromQuery] Dictionary<string, string> where,
|
|
||||||
[FromQuery] int limit = 30)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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.GetOrDefault<Collection>(slug) == null)
|
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return Page(resources, limit);
|
return Page(resources, limit);
|
||||||
}
|
}
|
||||||
@ -158,108 +102,39 @@ namespace Kyoo.Core.Api
|
|||||||
/// Get libraries containing this collection
|
/// Get libraries containing this collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Lists the libraries that contain the collection with the given id.
|
/// Lists the libraries that contain the collection with the given id or slug.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="slug">The slug of the <see cref="Collection"/>.</param>
|
/// <param name="identifier">The ID or slug of the <see cref="Collection"/>.</param>
|
||||||
/// <param name="sortBy">A key to sort shows by.</param>
|
/// <param name="sortBy">A key to sort libraries by.</param>
|
||||||
/// <param name="afterID">An optional show's ID to start the query from this specific item.</param>
|
|
||||||
/// <param name="where">An optional list of filters.</param>
|
/// <param name="where">An optional list of filters.</param>
|
||||||
/// <param name="limit">The number of shows to return.</param>
|
/// <param name="limit">The number of libraries to return.</param>
|
||||||
/// <returns>A page of shows.</returns>
|
/// <param name="afterID">An optional library's ID to start the query from this specific item.</param>
|
||||||
|
/// <returns>A page of libraries.</returns>
|
||||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||||
/// <response code="404">No collection with the given slug could be found.</response>
|
/// <response code="404">No collection with the given ID or slug could be found.</response>
|
||||||
[HttpGet("{id:int}/libraries")]
|
[HttpGet("{identifier:id}/libraries")]
|
||||||
[HttpGet("{id:int}/library", Order = AlternativeRoute)]
|
[HttpGet("{identifier:id}/library", Order = AlternativeRoute)]
|
||||||
[PartialPermission(Kind.Read)]
|
[PartialPermission(Kind.Read)]
|
||||||
public async Task<ActionResult<Page<Library>>> GetLibraries(int id,
|
public async Task<ActionResult<Page<Library>>> GetLibraries(Identifier identifier,
|
||||||
[FromQuery] string sortBy,
|
[FromQuery] string sortBy,
|
||||||
[FromQuery] int afterID,
|
|
||||||
[FromQuery] Dictionary<string, string> where,
|
[FromQuery] Dictionary<string, string> where,
|
||||||
[FromQuery] int limit = 30)
|
[FromQuery] int limit = 30,
|
||||||
|
[FromQuery] int? afterID = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ICollection<Library> resources = await _libraryManager.GetAll(
|
ICollection<Library> resources = await _libraryManager.GetAll(
|
||||||
ApiHelper.ParseWhere<Library>(where, x => x.Collections.Any(y => y.ID == id)),
|
ApiHelper.ParseWhere<Library>(where, x => x.Collections.Any(identifier.IsSame)),
|
||||||
new Sort<Library>(sortBy),
|
new Sort<Library>(sortBy),
|
||||||
new Pagination(limit, afterID));
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
if (!resources.Any() && await _libraryManager.GetOrDefault<Collection>(id) == null)
|
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Collection>()) == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
return Page(resources, limit);
|
return Page(resources, limit);
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
return BadRequest(new { Error = ex.Message });
|
return BadRequest(new RequestError(ex.Message));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}/libraries")]
|
|
||||||
[HttpGet("{slug}/library", Order = AlternativeRoute)]
|
|
||||||
[PartialPermission(Kind.Read)]
|
|
||||||
public async Task<ActionResult<Page<Library>>> GetLibraries(string slug,
|
|
||||||
[FromQuery] string sortBy,
|
|
||||||
[FromQuery] int afterID,
|
|
||||||
[FromQuery] Dictionary<string, string> where,
|
|
||||||
[FromQuery] int limit = 30)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
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.GetOrDefault<Collection>(slug) == null)
|
|
||||||
return NotFound();
|
|
||||||
return Page(resources, limit);
|
|
||||||
}
|
|
||||||
catch (ArgumentException ex)
|
|
||||||
{
|
|
||||||
return BadRequest(new { Error = ex.Message });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}/poster")]
|
|
||||||
public async Task<IActionResult> GetPoster(string slug)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Collection collection = await _libraryManager.Get<Collection>(slug);
|
|
||||||
return _files.FileResult(await _thumbs.GetImagePath(collection, Images.Poster));
|
|
||||||
}
|
|
||||||
catch (ItemNotFoundException)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}/logo")]
|
|
||||||
public async Task<IActionResult> GetLogo(string slug)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Collection collection = await _libraryManager.Get<Collection>(slug);
|
|
||||||
return _files.FileResult(await _thumbs.GetImagePath(collection, Images.Logo));
|
|
||||||
}
|
|
||||||
catch (ItemNotFoundException)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}/backdrop")]
|
|
||||||
[HttpGet("{slug}/thumbnail")]
|
|
||||||
public async Task<IActionResult> GetBackdrop(string slug)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Collection collection = await _libraryManager.Get<Collection>(slug);
|
|
||||||
return _files.FileResult(await _thumbs.GetImagePath(collection, Images.Thumbnail));
|
|
||||||
}
|
|
||||||
catch (ItemNotFoundException)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The repository of the resource, used to retrieve, save and do operations on the baking store.
|
/// The repository of the resource, used to retrieve, save and do operations on the baking store.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IRepository<T> _repository;
|
protected IRepository<T> Repository { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The base URL of Kyoo. This will be used to create links for images and
|
/// The base URL of Kyoo. This will be used to create links for images and
|
||||||
@ -61,7 +61,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// </param>
|
/// </param>
|
||||||
public CrudApi(IRepository<T> repository, Uri baseURL)
|
public CrudApi(IRepository<T> repository, Uri baseURL)
|
||||||
{
|
{
|
||||||
_repository = repository;
|
Repository = repository;
|
||||||
BaseURL = baseURL;
|
BaseURL = baseURL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +100,8 @@ namespace Kyoo.Core.Api
|
|||||||
public async Task<ActionResult<T>> Get(Identifier identifier)
|
public async Task<ActionResult<T>> Get(Identifier identifier)
|
||||||
{
|
{
|
||||||
T ret = await identifier.Match(
|
T ret = await identifier.Match(
|
||||||
id => _repository.GetOrDefault(id),
|
id => Repository.GetOrDefault(id),
|
||||||
slug => _repository.GetOrDefault(slug)
|
slug => Repository.GetOrDefault(slug)
|
||||||
);
|
);
|
||||||
if (ret == null)
|
if (ret == null)
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -125,7 +125,7 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _repository.GetCount(ApiHelper.ParseWhere<T>(where));
|
return await Repository.GetCount(ApiHelper.ParseWhere<T>(where));
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
@ -140,9 +140,9 @@ namespace Kyoo.Core.Api
|
|||||||
/// Get all resources that match the given filter.
|
/// Get all resources that match the given filter.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="sortBy">Sort information about the query (sort by, sort order).</param>
|
/// <param name="sortBy">Sort information about the query (sort by, sort order).</param>
|
||||||
/// <param name="afterID">Where the pagination should start.</param>
|
|
||||||
/// <param name="where">Filter the returned items.</param>
|
/// <param name="where">Filter the returned items.</param>
|
||||||
/// <param name="limit">How many items per page should be returned.</param>
|
/// <param name="limit">How many items per page should be returned.</param>
|
||||||
|
/// <param name="afterID">Where the pagination should start.</param>
|
||||||
/// <returns>A list of resources that match every filters.</returns>
|
/// <returns>A list of resources that match every filters.</returns>
|
||||||
/// <response code="400">Invalid filters or sort information.</response>
|
/// <response code="400">Invalid filters or sort information.</response>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
@ -151,13 +151,13 @@ namespace Kyoo.Core.Api
|
|||||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
|
||||||
public async Task<ActionResult<Page<T>>> GetAll(
|
public async Task<ActionResult<Page<T>>> GetAll(
|
||||||
[FromQuery] string sortBy,
|
[FromQuery] string sortBy,
|
||||||
[FromQuery] int afterID,
|
|
||||||
[FromQuery] Dictionary<string, string> where,
|
[FromQuery] Dictionary<string, string> where,
|
||||||
[FromQuery] int limit = 20)
|
[FromQuery] int limit = 20,
|
||||||
|
[FromQuery] int? afterID = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ICollection<T> resources = await _repository.GetAll(ApiHelper.ParseWhere<T>(where),
|
ICollection<T> resources = await Repository.GetAll(ApiHelper.ParseWhere<T>(where),
|
||||||
new Sort<T>(sortBy),
|
new Sort<T>(sortBy),
|
||||||
new Pagination(limit, afterID));
|
new Pagination(limit, afterID));
|
||||||
|
|
||||||
@ -188,7 +188,7 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await _repository.Create(resource);
|
return await Repository.Create(resource);
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
@ -196,7 +196,7 @@ namespace Kyoo.Core.Api
|
|||||||
}
|
}
|
||||||
catch (DuplicatedItemException)
|
catch (DuplicatedItemException)
|
||||||
{
|
{
|
||||||
T existing = await _repository.GetOrDefault(resource.Slug);
|
T existing = await Repository.GetOrDefault(resource.Slug);
|
||||||
return Conflict(existing);
|
return Conflict(existing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,11 +225,11 @@ namespace Kyoo.Core.Api
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (resource.ID > 0)
|
if (resource.ID > 0)
|
||||||
return await _repository.Edit(resource, resetOld);
|
return await Repository.Edit(resource, resetOld);
|
||||||
|
|
||||||
T old = await _repository.Get(resource.Slug);
|
T old = await Repository.Get(resource.Slug);
|
||||||
resource.ID = old.ID;
|
resource.ID = old.ID;
|
||||||
return await _repository.Edit(resource, resetOld);
|
return await Repository.Edit(resource, resetOld);
|
||||||
}
|
}
|
||||||
catch (ItemNotFoundException)
|
catch (ItemNotFoundException)
|
||||||
{
|
{
|
||||||
@ -255,8 +255,8 @@ namespace Kyoo.Core.Api
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await identifier.Match(
|
await identifier.Match(
|
||||||
id => _repository.Delete(id),
|
id => Repository.Delete(id),
|
||||||
slug => _repository.Delete(slug)
|
slug => Repository.Delete(slug)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (ItemNotFoundException)
|
catch (ItemNotFoundException)
|
||||||
@ -284,7 +284,7 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _repository.DeleteAll(ApiHelper.ParseWhere<T>(where));
|
await Repository.DeleteAll(ApiHelper.ParseWhere<T>(where));
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
|
146
src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
Normal file
146
src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
// Kyoo - A portable and vast media library solution.
|
||||||
|
// Copyright (c) Kyoo.
|
||||||
|
//
|
||||||
|
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||||
|
//
|
||||||
|
// Kyoo is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// any later version.
|
||||||
|
//
|
||||||
|
// Kyoo is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Abstractions.Controllers;
|
||||||
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using static Kyoo.Abstractions.Models.Utils.Constants;
|
||||||
|
|
||||||
|
namespace Kyoo.Core.Api
|
||||||
|
{
|
||||||
|
public class CrudThumbsApi<T> : CrudApi<T>
|
||||||
|
where T : class, IResource, IThumbnails
|
||||||
|
{
|
||||||
|
private readonly IFileSystem _files;
|
||||||
|
private readonly IThumbnailsManager _thumbs;
|
||||||
|
|
||||||
|
public CrudThumbsApi(IRepository<T> repository,
|
||||||
|
IFileSystem files,
|
||||||
|
IThumbnailsManager thumbs,
|
||||||
|
Uri baseURL)
|
||||||
|
: base(repository, baseURL)
|
||||||
|
{
|
||||||
|
_files = files;
|
||||||
|
_thumbs = thumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Image
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Get an image for the specified item.
|
||||||
|
/// List of commonly available images:
|
||||||
|
/// <list type="bullet">
|
||||||
|
/// <item>
|
||||||
|
/// <description>Poster: Image 0, also available at /poster</description>
|
||||||
|
/// </item>
|
||||||
|
/// <item>
|
||||||
|
/// <description>Thumbnail: Image 1, also available at /thumbnail</description>
|
||||||
|
/// </item>
|
||||||
|
/// <item>
|
||||||
|
/// <description>Logo: Image 3, also available at /logo</description>
|
||||||
|
/// </item>
|
||||||
|
/// </list>
|
||||||
|
/// Other images can be arbitrarily added by plugins so any image number can be specified from this endpoint.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <param name="image">The number of the image to retrieve.</param>
|
||||||
|
/// <returns>The image asked.</returns>
|
||||||
|
/// <response code="404">
|
||||||
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
|
/// </response>
|
||||||
|
[HttpGet("{identifier:id}/image-{image:int}")]
|
||||||
|
[PartialPermission(Kind.Read)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<IActionResult> GetImage(Identifier identifier, int image)
|
||||||
|
{
|
||||||
|
T resource = await identifier.Match(
|
||||||
|
id => Repository.GetOrDefault(id),
|
||||||
|
slug => Repository.GetOrDefault(slug)
|
||||||
|
);
|
||||||
|
if (resource == null)
|
||||||
|
return NotFound();
|
||||||
|
string path = await _thumbs.GetImagePath(resource, Images.Poster);
|
||||||
|
return _files.FileResult(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Poster
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Get the poster for the specified item.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <returns>The image asked.</returns>
|
||||||
|
/// <response code="404">
|
||||||
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
|
/// </response>
|
||||||
|
[HttpGet("{identifier:id}/poster", Order = AlternativeRoute)]
|
||||||
|
[PartialPermission(Kind.Read)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public Task<IActionResult> GetPoster(Identifier identifier)
|
||||||
|
{
|
||||||
|
return GetImage(identifier, Images.Poster);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Logo
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Get the logo for the specified item.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <returns>The image asked.</returns>
|
||||||
|
/// <response code="404">
|
||||||
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
|
/// </response>
|
||||||
|
[HttpGet("{identifier:id}/logo", Order = AlternativeRoute)]
|
||||||
|
[PartialPermission(Kind.Read)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public Task<IActionResult> GetLogo(Identifier identifier)
|
||||||
|
{
|
||||||
|
return GetImage(identifier, Images.Logo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get Thumbnail
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Get the thumbnail for the specified item.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="identifier">The ID or slug of the resource to get the image for.</param>
|
||||||
|
/// <returns>The image asked.</returns>
|
||||||
|
/// <response code="404">
|
||||||
|
/// No item exist with the specific identifier or the image does not exists on kyoo.
|
||||||
|
/// </response>
|
||||||
|
[HttpGet("{identifier:id}/backdrop", Order = AlternativeRoute)]
|
||||||
|
[HttpGet("{identifier:id}/thumbnail", Order = AlternativeRoute)]
|
||||||
|
public Task<IActionResult> GetBackdrop(Identifier identifier)
|
||||||
|
{
|
||||||
|
return GetImage(identifier, Images.Thumbnail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -80,11 +80,11 @@ namespace Kyoo.Swagger
|
|||||||
return ctx.ApiDescription.ActionDescriptor.AttributeRouteInfo?.Order != AlternativeRoute;
|
return ctx.ApiDescription.ActionDescriptor.AttributeRouteInfo?.Order != AlternativeRoute;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
options.SchemaGenerator.Settings.TypeMappers
|
options.SchemaGenerator.Settings.TypeMappers.Add(new PrimitiveTypeMapper(typeof(Identifier), x =>
|
||||||
.Add(new PrimitiveTypeMapper(
|
{
|
||||||
typeof(Identifier),
|
x.IsNullableRaw = false;
|
||||||
x => x.Type = JsonObjectType.String | JsonObjectType.Integer)
|
x.Type = JsonObjectType.String | JsonObjectType.Integer;
|
||||||
);
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user