diff --git a/src/Kyoo.Abstractions/Models/Utils/Identifier.cs b/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
index 416bfabfe..bd83e9753 100644
--- a/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
+++ b/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
@@ -17,9 +17,12 @@
// along with Kyoo. If not, see .
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
+using System.Linq;
using System.Linq.Expressions;
+using System.Reflection;
using JetBrains.Annotations;
namespace Kyoo.Abstractions.Models.Utils
@@ -87,6 +90,26 @@ namespace Kyoo.Abstractions.Models.Utils
: slugFunc(_slug);
}
+ ///
+ /// Match a custom type to an identifier. This can be used for wrapped resources (see example for more details).
+ ///
+ /// An expression to retrieve an ID from the type .
+ /// An expression to retrieve a slug from the type .
+ /// The type to match against this identifier.
+ /// An expression to match the type to this identifier.
+ ///
+ ///
+ /// identifier.Matcher<Season>(x => x.ShowID, x => x.Show.Slug)
+ ///
+ ///
+ public Expression> Matcher(Expression> idGetter,
+ Expression> slugGetter)
+ {
+ ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
+ BinaryExpression equal = Expression.Equal(_id.HasValue ? idGetter.Body : slugGetter.Body, self);
+ return Expression.Lambda>(equal);
+ }
+
///
/// Return true if this match a resource.
///
@@ -102,14 +125,51 @@ namespace Kyoo.Abstractions.Models.Utils
);
}
+ ///
+ /// Return an expression that return true if this match a given resource.
+ ///
+ /// The type of resource to match against.
+ ///
+ /// true if the given resource match this identifier, false otherwise.
+ ///
public Expression> IsSame()
where T : IResource
{
return _id.HasValue
- ? x => x.ID == _id
+ ? x => x.ID == _id.Value
: x => x.Slug == _slug;
}
+ ///
+ /// Return an expression that return true if this is containing in a collection.
+ ///
+ /// An expression to retrieve the list to check.
+ /// The type that contain the list to check.
+ /// The type of resource to check this identifier against.
+ /// An expression to check if this is contained.
+ public Expression> IsContainedIn(Expression>> listGetter)
+ where T2 : IResource
+ {
+ MethodInfo method = typeof(Enumerable)
+ .GetMethods()
+ .Where(x => x.Name == nameof(Enumerable.Any))
+ .FirstOrDefault(x => x.GetParameters().Length == 2)!
+ .MakeGenericMethod(typeof(T2));
+ MethodCallExpression call = Expression.Call(null, method!, listGetter.Body, IsSame());
+ return Expression.Lambda>(call, listGetter.Parameters);
+ }
+
+ ///
+ public override string ToString()
+ {
+ return _id.HasValue
+ ? _id.Value.ToString()
+ : _slug;
+ }
+
+ ///
+ /// A custom used to convert int or strings to an .
+ ///
public class IdentifierConvertor : TypeConverter
{
///
diff --git a/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs b/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
index 098094268..d599d6eee 100644
--- a/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
+++ b/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs
@@ -23,7 +23,6 @@ using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Database;
using Kyoo.Utils;
using Microsoft.EntityFrameworkCore;
@@ -160,8 +159,6 @@ namespace Kyoo.Core.Controllers
where,
sort,
limit);
- if (!people.Any() && await _shows.Value.GetOrDefault(showID) == null)
- throw new ItemNotFoundException();
foreach (PeopleRole role in people)
role.ForPeople = true;
return people;
@@ -182,8 +179,6 @@ namespace Kyoo.Core.Controllers
where,
sort,
limit);
- if (!people.Any() && await _shows.Value.GetOrDefault(showSlug) == null)
- throw new ItemNotFoundException();
foreach (PeopleRole role in people)
role.ForPeople = true;
return people;
@@ -195,7 +190,7 @@ namespace Kyoo.Core.Controllers
Sort sort = default,
Pagination limit = default)
{
- ICollection roles = await ApplyFilters(_database.PeopleRoles
+ return await ApplyFilters(_database.PeopleRoles
.Where(x => x.PeopleID == id)
.Include(x => x.Show),
y => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == y),
@@ -203,9 +198,6 @@ namespace Kyoo.Core.Controllers
where,
sort,
limit);
- if (!roles.Any() && await GetOrDefault(id) == null)
- throw new ItemNotFoundException();
- return roles;
}
///
@@ -214,7 +206,7 @@ namespace Kyoo.Core.Controllers
Sort sort = default,
Pagination limit = default)
{
- ICollection roles = await ApplyFilters(_database.PeopleRoles
+ return await ApplyFilters(_database.PeopleRoles
.Where(x => x.People.Slug == slug)
.Include(x => x.Show),
id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id),
@@ -222,9 +214,6 @@ namespace Kyoo.Core.Controllers
where,
sort,
limit);
- if (!roles.Any() && await GetOrDefault(slug) == null)
- throw new ItemNotFoundException();
- return roles;
}
}
}
diff --git a/src/Kyoo.Core/Views/CollectionApi.cs b/src/Kyoo.Core/Views/CollectionApi.cs
index 22b0608e9..65f49a907 100644
--- a/src/Kyoo.Core/Views/CollectionApi.cs
+++ b/src/Kyoo.Core/Views/CollectionApi.cs
@@ -29,7 +29,6 @@ using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
-using NSwag.Annotations;
using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api
@@ -41,7 +40,7 @@ namespace Kyoo.Core.Api
[Route("api/collection", Order = AlternativeRoute)]
[ApiController]
[PartialPermission(nameof(CollectionApi))]
- [ApiDefinition("Collection", Group = ResourceGroup)]
+ [ApiDefinition("Collections", Group = ResourceGroup)]
public class CollectionApi : CrudThumbsApi
{
///
@@ -100,7 +99,8 @@ namespace Kyoo.Core.Api
ICollection resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere(where, x => x.Collections.Any(identifier.IsSame)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
@@ -143,7 +143,8 @@ namespace Kyoo.Core.Api
ICollection resources = await _libraryManager.GetAll(
ApiHelper.ParseWhere(where, x => x.Collections.Any(identifier.IsSame)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
diff --git a/src/Kyoo.Core/Views/Helper/CrudApi.cs b/src/Kyoo.Core/Views/Helper/CrudApi.cs
index 76d5acb32..6e11ed6bc 100644
--- a/src/Kyoo.Core/Views/Helper/CrudApi.cs
+++ b/src/Kyoo.Core/Views/Helper/CrudApi.cs
@@ -157,9 +157,11 @@ namespace Kyoo.Core.Api
{
try
{
- ICollection resources = await Repository.GetAll(ApiHelper.ParseWhere(where),
+ ICollection resources = await Repository.GetAll(
+ ApiHelper.ParseWhere(where),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
return Page(resources, limit);
}
diff --git a/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs b/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
index 95a5782c9..68acd1123 100644
--- a/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
+++ b/src/Kyoo.Core/Views/Helper/CrudThumbsApi.cs
@@ -70,7 +70,7 @@ namespace Kyoo.Core.Api
}
///
- /// Get Image
+ /// Get image
///
///
/// Get an image for the specified item.
@@ -97,7 +97,7 @@ namespace Kyoo.Core.Api
);
if (resource == null)
return NotFound();
- string path = await _thumbs.GetImagePath(resource, Images.Poster);
+ string path = await _thumbs.GetImagePath(resource, image);
return _files.FileResult(path);
}
diff --git a/src/Kyoo.Core/Views/ShowApi.cs b/src/Kyoo.Core/Views/ShowApi.cs
index 4ebe06da3..f819e9ab0 100644
--- a/src/Kyoo.Core/Views/ShowApi.cs
+++ b/src/Kyoo.Core/Views/ShowApi.cs
@@ -20,455 +20,411 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
-using Kyoo.Abstractions.Models.Exceptions;
+using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
+using Kyoo.Abstractions.Models.Utils;
using Kyoo.Core.Models.Options;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
+using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api
{
- [Route("api/show")]
+ ///
+ /// Information about one or multiple .
+ ///
[Route("api/shows")]
- [Route("api/movie")]
- [Route("api/movies")]
+ [Route("api/show", Order = AlternativeRoute)]
+ [Route("api/movie", Order = AlternativeRoute)]
+ [Route("api/movies", Order = AlternativeRoute)]
[ApiController]
[PartialPermission(nameof(ShowApi))]
- public class ShowApi : CrudApi
+ [ApiDefinition("Shows", Group = ResourceGroup)]
+ public class ShowApi : CrudThumbsApi
{
+ ///
+ /// The library manager used to modify or retrieve information about the data store.
+ ///
private readonly ILibraryManager _libraryManager;
- private readonly IFileSystem _files;
- private readonly IThumbnailsManager _thumbs;
+ ///
+ /// The file manager used to send images and fonts.
+ ///
+ private readonly IFileSystem _files;
+
+ ///
+ /// Create a new .
+ ///
+ ///
+ /// The library manager used to modify or retrieve information about the data store.
+ ///
+ /// The file manager used to send images and fonts.
+ /// The thumbnail manager used to retrieve images paths.
+ ///
+ /// Options used to retrieve the base URL of Kyoo.
+ ///
public ShowApi(ILibraryManager libraryManager,
IFileSystem files,
IThumbnailsManager thumbs,
IOptions options)
- : base(libraryManager.ShowRepository, options.Value.PublicUrl)
+ : base(libraryManager.ShowRepository, files, thumbs, options.Value.PublicUrl)
{
_libraryManager = libraryManager;
_files = files;
- _thumbs = thumbs;
}
- [HttpGet("{showID:int}/season")]
- [HttpGet("{showID:int}/seasons")]
+ ///
+ /// Get seasons of this show
+ ///
+ ///
+ /// List the seasons that are part of the specified show.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort seasons by.
+ /// An optional list of filters.
+ /// The number of seasons to return.
+ /// An optional season's ID to start the query from this specific item.
+ /// A page of seasons.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/seasons")]
+ [HttpGet("{identifier:id}/season", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetSeasons(int showID,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetSeasons(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 20)
+ [FromQuery] int limit = 20,
+ [FromQuery] int? afterID = null)
{
try
{
ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.ShowID == showID),
+ ApiHelper.ParseWhere(where, identifier.Matcher(x => x.ShowID, x => x.Show.Slug)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{slug}/season")]
- [HttpGet("{slug}/seasons")]
+ ///
+ /// Get episodes of this show
+ ///
+ ///
+ /// List the episodes that are part of the specified show.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort episodes by.
+ /// An optional list of filters.
+ /// The number of episodes to return.
+ /// An optional episode's ID to start the query from this specific item.
+ /// A page of episodes.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/episodes")]
+ [HttpGet("{identifier:id}/episode", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetSeasons(string slug,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetEpisodes(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 20)
- {
- try
- {
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Show.Slug == slug),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
- }
-
- [HttpGet("{showID:int}/episode")]
- [HttpGet("{showID:int}/episodes")]
- [PartialPermission(Kind.Read)]
- public async Task>> GetEpisodes(int showID,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 50)
+ [FromQuery] int limit = 50,
+ [FromQuery] int? afterID = null)
{
try
{
ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.ShowID == showID),
+ ApiHelper.ParseWhere(where, identifier.Matcher(x => x.ShowID, x => x.Show.Slug)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{slug}/episode")]
- [HttpGet("{slug}/episodes")]
+ ///
+ /// Get people that made this show
+ ///
+ ///
+ /// List staff members that made this show.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort staff members by.
+ /// An optional list of filters.
+ /// The number of people to return.
+ /// An optional person's ID to start the query from this specific item.
+ /// A page of people.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/people")]
+ [HttpGet("{identifier:id}/staff", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetEpisodes(string slug,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetPeople(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 50)
+ [FromQuery] int limit = 30,
+ [FromQuery] int? afterID = null)
{
try
{
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Show.Slug == slug),
- new Sort(sortBy),
- new Pagination(limit, afterID));
+ Expression> whereQuery = ApiHelper.ParseWhere(where);
+ Sort sort = new(sortBy);
+ Pagination pagination = new(limit, afterID);
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
+ ICollection resources = await identifier.Match(
+ id => _libraryManager.GetPeopleFromShow(id, whereQuery, sort, pagination),
+ slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sort, pagination)
+ );
+
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{showID:int}/people")]
+ ///
+ /// Get genres of this show
+ ///
+ ///
+ /// List the genres that represent this show.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort genres by.
+ /// An optional list of filters.
+ /// The number of genres to return.
+ /// An optional genre's ID to start the query from this specific item.
+ /// A page of genres.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/genres")]
+ [HttpGet("{identifier:id}/genre", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetPeople(int showID,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetGenres(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
- {
- try
- {
- ICollection resources = await _libraryManager.GetPeopleFromShow(showID,
- ApiHelper.ParseWhere(where),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
- }
-
- [HttpGet("{slug}/people")]
- [PartialPermission(Kind.Read)]
- public async Task>> GetPeople(string slug,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
- {
- try
- {
- ICollection resources = await _libraryManager.GetPeopleFromShow(slug,
- ApiHelper.ParseWhere(where),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
- }
-
- [HttpGet("{showID:int}/genre")]
- [HttpGet("{showID:int}/genres")]
- [PartialPermission(Kind.Read)]
- public async Task>> GetGenres(int showID,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
+ [FromQuery] int limit = 30,
+ [FromQuery] int? afterID = null)
{
try
{
ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.ID == showID)),
+ ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{slug}/genre")]
- [HttpGet("{slug}/genres")]
+ ///
+ /// Get studio that made the show
+ ///
+ ///
+ /// Get the studio that made the show.
+ ///
+ /// The ID or slug of the .
+ /// The studio that made the show.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/studio")]
[PartialPermission(Kind.Read)]
- public async Task>> GetGenre(string slug,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task> GetStudio(Identifier identifier)
{
- try
- {
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.Slug == slug)),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
- }
-
- [HttpGet("{showID:int}/studio")]
- [PartialPermission(Kind.Read)]
- public async Task> GetStudio(int showID)
- {
- try
- {
- return await _libraryManager.Get(x => x.Shows.Any(y => y.ID == showID));
- }
- catch (ItemNotFoundException)
- {
+ Studio studio = await _libraryManager.GetOrDefault(identifier.IsContainedIn(x => x.Shows));
+ if (studio == null)
return NotFound();
- }
+ return studio;
}
- [HttpGet("{slug}/studio")]
+ ///
+ /// Get libraries containing this show.
+ ///
+ ///
+ /// List the libraries that contain this show. If this show is contained in a collection that is contained in
+ /// a library, this library will be returned too.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort libraries by.
+ /// An optional list of filters.
+ /// The number of libraries to return.
+ /// An optional library's ID to start the query from this specific item.
+ /// A page of libraries.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/libraries")]
+ [HttpGet("{identifier:id}/library", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task> GetStudio(string slug)
- {
- try
- {
- return await _libraryManager.Get(x => x.Shows.Any(y => y.Slug == slug));
- }
- catch (ItemNotFoundException)
- {
- return NotFound();
- }
- }
-
- [HttpGet("{showID:int}/library")]
- [HttpGet("{showID:int}/libraries")]
- [PartialPermission(Kind.Read)]
- public async Task>> GetLibraries(int showID,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetLibraries(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
+ [FromQuery] int limit = 30,
+ [FromQuery] int? afterID = null)
{
try
{
ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.ID == showID)),
+ ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{slug}/library")]
- [HttpGet("{slug}/libraries")]
+ ///
+ /// Get collections containing this show.
+ ///
+ ///
+ /// List the collections that contain this show.
+ ///
+ /// The ID or slug of the .
+ /// A key to sort collections by.
+ /// An optional list of filters.
+ /// The number of collections to return.
+ /// An optional collection's ID to start the query from this specific item.
+ /// A page of collections.
+ /// The filters or the sort parameters are invalid.
+ /// No show with the given ID or slug could be found.
+ [HttpGet("{identifier:id}/collection")]
+ [HttpGet("{identifier:id}/collections")]
[PartialPermission(Kind.Read)]
- public async Task>> GetLibraries(string slug,
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetCollections(Identifier identifier,
[FromQuery] string sortBy,
- [FromQuery] int afterID,
[FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
- {
- try
- {
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.Slug == slug)),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
- }
-
- [HttpGet("{showID:int}/collection")]
- [HttpGet("{showID:int}/collections")]
- [PartialPermission(Kind.Read)]
- public async Task>> GetCollections(int showID,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
+ [FromQuery] int limit = 30,
+ [FromQuery] int? afterID = null)
{
try
{
ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.ID == showID)),
+ ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows)),
new Sort(sortBy),
- new Pagination(limit, afterID));
+ new Pagination(limit, afterID)
+ );
- if (!resources.Any() && await _libraryManager.GetOrDefault(showID) == null)
+ if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null)
return NotFound();
return Page(resources, limit);
}
catch (ArgumentException ex)
{
- return BadRequest(new { Error = ex.Message });
+ return BadRequest(new RequestError(ex.Message));
}
}
- [HttpGet("{slug}/collection")]
- [HttpGet("{slug}/collections")]
+ ///
+ /// List fonts
+ ///
+ ///
+ /// List available fonts for this show.
+ ///
+ /// The ID or slug of the .
+ /// An object containing the name of the font followed by the url to retrieve it.
+ [HttpGet("{identifier:id}/fonts")]
+ [HttpGet("{identifier:id}/font", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetCollections(string slug,
- [FromQuery] string sortBy,
- [FromQuery] int afterID,
- [FromQuery] Dictionary where,
- [FromQuery] int limit = 30)
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task>> GetFonts(Identifier identifier)
{
- try
- {
- ICollection resources = await _libraryManager.GetAll(
- ApiHelper.ParseWhere(where, x => x.Shows.Any(y => y.Slug == slug)),
- new Sort(sortBy),
- new Pagination(limit, afterID));
-
- if (!resources.Any() && await _libraryManager.GetOrDefault(slug) == null)
- return NotFound();
- return Page(resources, limit);
- }
- catch (ArgumentException ex)
- {
- return BadRequest(new { Error = ex.Message });
- }
+ Show show = await identifier.Match(
+ id => _libraryManager.GetOrDefault(id),
+ slug => _libraryManager.GetOrDefault(slug)
+ );
+ if (show == null)
+ return NotFound();
+ string path = _files.Combine(await _files.GetExtraDirectory(show), "Attachments");
+ return (await _files.ListFiles(path))
+ .ToDictionary(
+ Path.GetFileNameWithoutExtension,
+ x => $"{BaseURL}api/shows/{identifier}/fonts/{Path.GetFileName(x)}"
+ );
}
- [HttpGet("{slug}/font")]
- [HttpGet("{slug}/fonts")]
+ ///
+ /// Get font
+ ///
+ ///
+ /// Get a font file that is used in subtitles of this show.
+ ///
+ /// The ID or slug of the .
+ /// The name of the font to retrieve (with it's file extension).
+ /// A page of collections.
+ /// The font name is invalid.
+ /// No show with the given ID/slug could be found or the font does not exist.
+ [HttpGet("{identifier:id}/fonts/{font}")]
+ [HttpGet("{identifier:id}/font/{font}", Order = AlternativeRoute)]
[PartialPermission(Kind.Read)]
- public async Task>> GetFonts(string slug)
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task GetFont(Identifier identifier, string font)
{
- try
- {
- Show show = await _libraryManager.Get(slug);
- string path = _files.Combine(await _files.GetExtraDirectory(show), "Attachments");
- return (await _files.ListFiles(path))
- .ToDictionary(Path.GetFileNameWithoutExtension,
- x => $"{BaseURL}api/shows/{slug}/fonts/{Path.GetFileName(x)}");
- }
- catch (ItemNotFoundException)
- {
+ if (font.Contains('/') || font.Contains('\\'))
+ return BadRequest(new RequestError("Invalid font name."));
+ Show show = await identifier.Match(
+ id => _libraryManager.GetOrDefault(id),
+ slug => _libraryManager.GetOrDefault(slug)
+ );
+ if (show == null)
return NotFound();
- }
- }
-
- [HttpGet("{showSlug}/font/{slug}")]
- [HttpGet("{showSlug}/fonts/{slug}")]
- [PartialPermission(Kind.Read)]
- public async Task GetFont(string showSlug, string slug)
- {
- try
- {
- Show show = await _libraryManager.Get(showSlug);
- string path = _files.Combine(await _files.GetExtraDirectory(show), "Attachments", slug);
- return _files.FileResult(path);
- }
- catch (ItemNotFoundException)
- {
- return NotFound();
- }
- }
-
- [HttpGet("{slug}/poster")]
- public async Task GetPoster(string slug)
- {
- try
- {
- Show show = await _libraryManager.Get(slug);
- return _files.FileResult(await _thumbs.GetImagePath(show, Images.Poster));
- }
- catch (ItemNotFoundException)
- {
- return NotFound();
- }
- }
-
- [HttpGet("{slug}/logo")]
- public async Task GetLogo(string slug)
- {
- try
- {
- Show show = await _libraryManager.Get(slug);
- return _files.FileResult(await _thumbs.GetImagePath(show, Images.Logo));
- }
- catch (ItemNotFoundException)
- {
- return NotFound();
- }
- }
-
- [HttpGet("{slug}/backdrop")]
- [HttpGet("{slug}/thumbnail")]
- public async Task GetBackdrop(string slug)
- {
- try
- {
- Show show = await _libraryManager.Get(slug);
- return _files.FileResult(await _thumbs.GetImagePath(show, Images.Thumbnail));
- }
- catch (ItemNotFoundException)
- {
- return NotFound();
- }
+ string path = _files.Combine(await _files.GetExtraDirectory(show), "Attachments", font);
+ return _files.FileResult(path);
}
}
}