mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
API: Documenting the search API
This commit is contained in:
parent
cb6ea80adb
commit
40e32a1689
@ -23,8 +23,10 @@ namespace Kyoo.Abstractions.Models.Attributes
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An attribute to specify on apis to specify it's documentation's name and category.
|
/// An attribute to specify on apis to specify it's documentation's name and category.
|
||||||
|
/// If this is applied on a method, the specified method will be exploded from the controller's page and be
|
||||||
|
/// included on the specified tag page.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||||
public class ApiDefinitionAttribute : Attribute
|
public class ApiDefinitionAttribute : Attribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -54,14 +54,9 @@ namespace Kyoo.Abstractions.Models.Permissions
|
|||||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||||
/// lead to unspecified behaviors.
|
/// lead to unspecified behaviors.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="type">
|
/// <param name="type">The type of the action</param>
|
||||||
/// The type of the action
|
|
||||||
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
|
|
||||||
/// </param>
|
|
||||||
public PartialPermissionAttribute(string type)
|
public PartialPermissionAttribute(string type)
|
||||||
{
|
{
|
||||||
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
|
|
||||||
type = type[..^3];
|
|
||||||
Type = type.ToLower();
|
Type = type.ToLower();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,17 +91,16 @@ namespace Kyoo.Abstractions.Models.Permissions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">
|
/// <param name="type">
|
||||||
/// The type of the action
|
/// The type of the action
|
||||||
/// (if the type ends with api, it will be removed. This allow you to use nameof(YourApi)).
|
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="permission">The kind of permission needed.</param>
|
/// <param name="permission">
|
||||||
|
/// The kind of permission needed.
|
||||||
|
/// </param>
|
||||||
/// <param name="group">
|
/// <param name="group">
|
||||||
/// The group of this permission (allow grouped permission like overall.read
|
/// The group of this permission (allow grouped permission like overall.read
|
||||||
/// for all read permissions of this group).
|
/// for all read permissions of this group).
|
||||||
/// </param>
|
/// </param>
|
||||||
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
|
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
|
||||||
{
|
{
|
||||||
if (type.EndsWith("API", StringComparison.OrdinalIgnoreCase))
|
|
||||||
type = type[..^3];
|
|
||||||
Type = type.ToLower();
|
Type = type.ToLower();
|
||||||
Kind = permission;
|
Kind = permission;
|
||||||
Group = group;
|
Group = group;
|
||||||
|
@ -36,7 +36,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/task", Order = AlternativeRoute)]
|
[Route("api/task", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
[PartialPermission(nameof(TaskApi), Group = Group.Admin)]
|
[PartialPermission("Task", Group = Group.Admin)]
|
||||||
[ApiDefinition("Tasks", Group = AdminGroup)]
|
[ApiDefinition("Tasks", Group = AdminGroup)]
|
||||||
public class TaskApi : ControllerBase
|
public class TaskApi : ControllerBase
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/genres")]
|
[Route("api/genres")]
|
||||||
[Route("api/genre", Order = AlternativeRoute)]
|
[Route("api/genre", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(GenreApi))]
|
[PartialPermission(nameof(Genre))]
|
||||||
[ApiDefinition("Genres", Group = MetadataGroup)]
|
[ApiDefinition("Genres", Group = MetadataGroup)]
|
||||||
public class GenreApi : CrudApi<Genre>
|
public class GenreApi : CrudApi<Genre>
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/provider", Order = AlternativeRoute)]
|
[Route("api/provider", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
[PartialPermission(nameof(ProviderApi))]
|
[PartialPermission(nameof(Provider))]
|
||||||
[ApiDefinition("Providers", Group = MetadataGroup)]
|
[ApiDefinition("Providers", Group = MetadataGroup)]
|
||||||
public class ProviderApi : CrudThumbsApi<Provider>
|
public class ProviderApi : CrudThumbsApi<Provider>
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/people", Order = AlternativeRoute)]
|
[Route("api/people", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
[PartialPermission(nameof(StaffApi))]
|
[PartialPermission(nameof(People))]
|
||||||
[ApiDefinition("Staff", Group = MetadataGroup)]
|
[ApiDefinition("Staff", Group = MetadataGroup)]
|
||||||
public class StaffApi : CrudThumbsApi<People>
|
public class StaffApi : CrudThumbsApi<People>
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/studios")]
|
[Route("api/studios")]
|
||||||
[Route("api/studio", Order = AlternativeRoute)]
|
[Route("api/studio", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(ShowApi))]
|
[PartialPermission(nameof(Show))]
|
||||||
[ApiDefinition("Studios", Group = MetadataGroup)]
|
[ApiDefinition("Studios", Group = MetadataGroup)]
|
||||||
public class StudioApi : CrudApi<Studio>
|
public class StudioApi : CrudApi<Studio>
|
||||||
{
|
{
|
||||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/collections")]
|
[Route("api/collections")]
|
||||||
[Route("api/collection", Order = AlternativeRoute)]
|
[Route("api/collection", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(CollectionApi))]
|
[PartialPermission(nameof(Collection))]
|
||||||
[ApiDefinition("Collections", Group = ResourcesGroup)]
|
[ApiDefinition("Collections", Group = ResourcesGroup)]
|
||||||
public class CollectionApi : CrudThumbsApi<Collection>
|
public class CollectionApi : CrudThumbsApi<Collection>
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/episode", Order = AlternativeRoute)]
|
[Route("api/episode", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
[PartialPermission(nameof(EpisodeApi))]
|
[PartialPermission(nameof(Episode))]
|
||||||
[ApiDefinition("Episodes", Group = ResourcesGroup)]
|
[ApiDefinition("Episodes", Group = ResourcesGroup)]
|
||||||
public class EpisodeApi : CrudThumbsApi<Episode>
|
public class EpisodeApi : CrudThumbsApi<Episode>
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/library", Order = AlternativeRoute)]
|
[Route("api/library", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
[PartialPermission(nameof(LibraryApi), Group = Group.Admin)]
|
[PartialPermission(nameof(Library), Group = Group.Admin)]
|
||||||
[ApiDefinition("Library", Group = ResourcesGroup)]
|
[ApiDefinition("Library", Group = ResourcesGroup)]
|
||||||
public class LibraryApi : CrudApi<Library>
|
public class LibraryApi : CrudApi<Library>
|
||||||
{
|
{
|
||||||
|
@ -38,6 +38,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/item", Order = AlternativeRoute)]
|
[Route("api/item", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[ResourceView]
|
[ResourceView]
|
||||||
|
[PartialPermission(nameof(LibraryItem))]
|
||||||
[ApiDefinition("Items", Group = ResourcesGroup)]
|
[ApiDefinition("Items", Group = ResourcesGroup)]
|
||||||
public class LibraryItemApi : BaseApi
|
public class LibraryItemApi : BaseApi
|
||||||
{
|
{
|
||||||
@ -74,7 +75,7 @@ namespace Kyoo.Core.Api
|
|||||||
/// <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 library with the given ID or slug could be found.</response>
|
/// <response code="404">No library with the given ID or slug could be found.</response>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Permission(nameof(LibraryItemApi), 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)]
|
||||||
|
194
src/Kyoo.Core/Views/Resources/SearchApi.cs
Normal file
194
src/Kyoo.Core/Views/Resources/SearchApi.cs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Kyoo.Abstractions.Controllers;
|
||||||
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Kyoo.Abstractions.Models.Attributes;
|
||||||
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using static Kyoo.Abstractions.Models.Utils.Constants;
|
||||||
|
|
||||||
|
namespace Kyoo.Core.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An endpoint to search for every resources of kyoo. Searching for only a specific type of resource
|
||||||
|
/// is available on the said endpoint.
|
||||||
|
/// </summary>
|
||||||
|
[Route("api/search/{query}")]
|
||||||
|
[ApiController]
|
||||||
|
[ResourceView]
|
||||||
|
[ApiDefinition("Search", Group = ResourcesGroup)]
|
||||||
|
public class SearchApi : ControllerBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The library manager used to modify or retrieve information in the data store.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ILibraryManager _libraryManager;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="SearchApi"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="libraryManager">The library manager used to interact with the data store.</param>
|
||||||
|
public SearchApi(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Global search
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for collections, shows, episodes, staff, genre and studios at the same time
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of every resources found for the specified query.</returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Permission(nameof(Collection), Kind.Read)]
|
||||||
|
[Permission(nameof(Show), Kind.Read)]
|
||||||
|
[Permission(nameof(Episode), Kind.Read)]
|
||||||
|
[Permission(nameof(People), Kind.Read)]
|
||||||
|
[Permission(nameof(Genre), Kind.Read)]
|
||||||
|
[Permission(nameof(Studio), Kind.Read)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public async Task<ActionResult<SearchResult>> Search(string query)
|
||||||
|
{
|
||||||
|
return new SearchResult
|
||||||
|
{
|
||||||
|
Query = query,
|
||||||
|
Collections = await _libraryManager.Search<Collection>(query),
|
||||||
|
Shows = await _libraryManager.Search<Show>(query),
|
||||||
|
Episodes = await _libraryManager.Search<Episode>(query),
|
||||||
|
People = await _libraryManager.Search<People>(query),
|
||||||
|
Genres = await _libraryManager.Search<Genre>(query),
|
||||||
|
Studios = await _libraryManager.Search<Studio>(query)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search collections
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for collections
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of collections found for the specified query.</returns>
|
||||||
|
[HttpGet("collections")]
|
||||||
|
[HttpGet("collection", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(Collection), Kind.Read)]
|
||||||
|
[ApiDefinition("Collections")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<Collection>> SearchCollections(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<Collection>(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search shows
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for shows
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of shows found for the specified query.</returns>
|
||||||
|
[HttpGet("shows")]
|
||||||
|
[HttpGet("show", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(Show), Kind.Read)]
|
||||||
|
[ApiDefinition("Shows")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<Show>> SearchShows(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<Show>(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search episodes
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for episodes
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of episodes found for the specified query.</returns>
|
||||||
|
[HttpGet("episodes")]
|
||||||
|
[HttpGet("episode", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(Episode), Kind.Read)]
|
||||||
|
[ApiDefinition("Episodes")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<Episode>> SearchEpisodes(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<Episode>(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search staff
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for staff
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of staff members found for the specified query.</returns>
|
||||||
|
[HttpGet("staff")]
|
||||||
|
[HttpGet("person", Order = AlternativeRoute)]
|
||||||
|
[HttpGet("people", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(People), Kind.Read)]
|
||||||
|
[ApiDefinition("Staff")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<People>> SearchPeople(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<People>(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search genres
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for genres
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of genres found for the specified query.</returns>
|
||||||
|
[HttpGet("genres")]
|
||||||
|
[HttpGet("genre", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(Genre), Kind.Read)]
|
||||||
|
[ApiDefinition("Genres")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<Genre>> SearchGenres(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<Genre>(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Search studios
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Search for studios
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="query">The query to search for.</param>
|
||||||
|
/// <returns>A list of studios found for the specified query.</returns>
|
||||||
|
[HttpGet("studios")]
|
||||||
|
[HttpGet("studio", Order = AlternativeRoute)]
|
||||||
|
[Permission(nameof(Studio), Kind.Read)]
|
||||||
|
[ApiDefinition("Studios")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
public Task<ICollection<Studio>> SearchStudios(string query)
|
||||||
|
{
|
||||||
|
return _libraryManager.Search<Studio>(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/seasons")]
|
[Route("api/seasons")]
|
||||||
[Route("api/season", Order = AlternativeRoute)]
|
[Route("api/season", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(SeasonApi))]
|
[PartialPermission(nameof(Season))]
|
||||||
[ApiDefinition("Seasons", Group = ResourcesGroup)]
|
[ApiDefinition("Seasons", Group = ResourcesGroup)]
|
||||||
public class SeasonApi : CrudThumbsApi<Season>
|
public class SeasonApi : CrudThumbsApi<Season>
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ namespace Kyoo.Core.Api
|
|||||||
[Route("api/movie", Order = AlternativeRoute)]
|
[Route("api/movie", Order = AlternativeRoute)]
|
||||||
[Route("api/movies", Order = AlternativeRoute)]
|
[Route("api/movies", Order = AlternativeRoute)]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[PartialPermission(nameof(ShowApi))]
|
[PartialPermission(nameof(Show))]
|
||||||
[ApiDefinition("Shows", Group = ResourcesGroup)]
|
[ApiDefinition("Shows", Group = ResourcesGroup)]
|
||||||
public class ShowApi : CrudThumbsApi<Show>
|
public class ShowApi : CrudThumbsApi<Show>
|
||||||
{
|
{
|
||||||
|
@ -1,107 +0,0 @@
|
|||||||
// 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.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Abstractions.Models;
|
|
||||||
using Kyoo.Abstractions.Models.Permissions;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Api
|
|
||||||
{
|
|
||||||
[Route("api/search/{query}")]
|
|
||||||
[ApiController]
|
|
||||||
public class SearchApi : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public SearchApi(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet]
|
|
||||||
[Permission(nameof(Collection), Kind.Read)]
|
|
||||||
[Permission(nameof(Show), Kind.Read)]
|
|
||||||
[Permission(nameof(Episode), Kind.Read)]
|
|
||||||
[Permission(nameof(People), Kind.Read)]
|
|
||||||
[Permission(nameof(Genre), Kind.Read)]
|
|
||||||
[Permission(nameof(Studio), Kind.Read)]
|
|
||||||
public async Task<ActionResult<SearchResult>> Search(string query)
|
|
||||||
{
|
|
||||||
return new SearchResult
|
|
||||||
{
|
|
||||||
Query = query,
|
|
||||||
Collections = await _libraryManager.Search<Collection>(query),
|
|
||||||
Shows = await _libraryManager.Search<Show>(query),
|
|
||||||
Episodes = await _libraryManager.Search<Episode>(query),
|
|
||||||
People = await _libraryManager.Search<People>(query),
|
|
||||||
Genres = await _libraryManager.Search<Genre>(query),
|
|
||||||
Studios = await _libraryManager.Search<Studio>(query)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("collection")]
|
|
||||||
[HttpGet("collections")]
|
|
||||||
[Permission(nameof(Collection), Kind.Read)]
|
|
||||||
public Task<ICollection<Collection>> SearchCollections(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<Collection>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("show")]
|
|
||||||
[HttpGet("shows")]
|
|
||||||
[Permission(nameof(Show), Kind.Read)]
|
|
||||||
public Task<ICollection<Show>> SearchShows(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<Show>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("episode")]
|
|
||||||
[HttpGet("episodes")]
|
|
||||||
[Permission(nameof(Episode), Kind.Read)]
|
|
||||||
public Task<ICollection<Episode>> SearchEpisodes(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<Episode>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("people")]
|
|
||||||
[Permission(nameof(People), Kind.Read)]
|
|
||||||
public Task<ICollection<People>> SearchPeople(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<People>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("genre")]
|
|
||||||
[HttpGet("genres")]
|
|
||||||
[Permission(nameof(Genre), Kind.Read)]
|
|
||||||
public Task<ICollection<Genre>> SearchGenres(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<Genre>(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("studio")]
|
|
||||||
[HttpGet("studios")]
|
|
||||||
[Permission(nameof(Studio), Kind.Read)]
|
|
||||||
public Task<ICollection<Studio>> SearchStudios(string query)
|
|
||||||
{
|
|
||||||
return _libraryManager.Search<Studio>(query);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Kyoo.Swagger.Models;
|
||||||
using NSwag;
|
using NSwag;
|
||||||
using NSwag.Generation.AspNetCore;
|
using NSwag.Generation.AspNetCore;
|
||||||
|
|
||||||
@ -49,13 +50,16 @@ namespace Kyoo.Swagger
|
|||||||
{
|
{
|
||||||
if (!postProcess.ExtensionData.TryGetValue("x-tagGroups", out object list))
|
if (!postProcess.ExtensionData.TryGetValue("x-tagGroups", out object list))
|
||||||
return;
|
return;
|
||||||
List<dynamic> tagGroups = (List<dynamic>)list;
|
List<TagGroups> tagGroups = (List<TagGroups>)list;
|
||||||
postProcess.ExtensionData["x-tagGroups"] = tagGroups
|
postProcess.ExtensionData["x-tagGroups"] = tagGroups
|
||||||
.OrderBy(x => x.name)
|
.OrderBy(x => x.Name)
|
||||||
.Select(x => new
|
.Select(x =>
|
||||||
{
|
{
|
||||||
name = x.name.Substring(x.name.IndexOf(':') + 1),
|
x.Name = x.Name[(x.Name.IndexOf(':') + 1)..];
|
||||||
x.tags
|
x.Tags = x.Tags
|
||||||
|
.OrderBy(y => y)
|
||||||
|
.ToList();
|
||||||
|
return x;
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Kyoo.Abstractions.Models.Attributes;
|
using Kyoo.Abstractions.Models.Attributes;
|
||||||
|
using Kyoo.Swagger.Models;
|
||||||
using Namotion.Reflection;
|
using Namotion.Reflection;
|
||||||
using NSwag;
|
using NSwag;
|
||||||
using NSwag.Generation.AspNetCore;
|
using NSwag.Generation.AspNetCore;
|
||||||
@ -44,6 +45,10 @@ namespace Kyoo.Swagger
|
|||||||
ApiDefinitionAttribute def = context.ControllerType.GetCustomAttribute<ApiDefinitionAttribute>();
|
ApiDefinitionAttribute def = context.ControllerType.GetCustomAttribute<ApiDefinitionAttribute>();
|
||||||
string name = def?.Name ?? context.ControllerType.Name;
|
string name = def?.Name ?? context.ControllerType.Name;
|
||||||
|
|
||||||
|
ApiDefinitionAttribute methodOverride = context.MethodInfo.GetCustomAttribute<ApiDefinitionAttribute>();
|
||||||
|
if (methodOverride != null)
|
||||||
|
name = methodOverride.Name;
|
||||||
|
|
||||||
context.OperationDescription.Operation.Tags.Add(name);
|
context.OperationDescription.Operation.Tags.Add(name);
|
||||||
if (context.Document.Tags.All(x => x.Name != name))
|
if (context.Document.Tags.All(x => x.Name != name))
|
||||||
{
|
{
|
||||||
@ -58,20 +63,20 @@ namespace Kyoo.Swagger
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
context.Document.ExtensionData ??= new Dictionary<string, object>();
|
context.Document.ExtensionData ??= new Dictionary<string, object>();
|
||||||
context.Document.ExtensionData.TryAdd("x-tagGroups", new List<dynamic>());
|
context.Document.ExtensionData.TryAdd("x-tagGroups", new List<TagGroups>());
|
||||||
List<dynamic> obj = (List<dynamic>)context.Document.ExtensionData["x-tagGroups"];
|
List<TagGroups> obj = (List<TagGroups>)context.Document.ExtensionData["x-tagGroups"];
|
||||||
dynamic existing = obj.FirstOrDefault(x => x.name == def.Group);
|
TagGroups existing = obj.FirstOrDefault(x => x.Name == def.Group);
|
||||||
if (existing != null)
|
if (existing != null)
|
||||||
{
|
{
|
||||||
if (!existing.tags.Contains(def.Name))
|
if (!existing.Tags.Contains(def.Name))
|
||||||
existing.tags.Add(def.Name);
|
existing.Tags.Add(def.Name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
obj.Add(new
|
obj.Add(new TagGroups
|
||||||
{
|
{
|
||||||
name = def.Group,
|
Name = def.Group,
|
||||||
tags = new List<string> { def.Name }
|
Tags = new List<string> { def.Name }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,19 +93,19 @@ namespace Kyoo.Swagger
|
|||||||
/// </param>
|
/// </param>
|
||||||
public static void AddLeftoversToOthersGroup(this OpenApiDocument postProcess)
|
public static void AddLeftoversToOthersGroup(this OpenApiDocument postProcess)
|
||||||
{
|
{
|
||||||
List<dynamic> tagGroups = (List<dynamic>)postProcess.ExtensionData["x-tagGroups"];
|
List<TagGroups> tagGroups = (List<TagGroups>)postProcess.ExtensionData["x-tagGroups"];
|
||||||
List<string> tagsWithoutGroup = postProcess.Tags
|
List<string> tagsWithoutGroup = postProcess.Tags
|
||||||
.Select(x => x.Name)
|
.Select(x => x.Name)
|
||||||
.Where(x => tagGroups
|
.Where(x => tagGroups
|
||||||
.SelectMany<dynamic, string>(y => y.tags)
|
.SelectMany(y => y.Tags)
|
||||||
.All(y => y != x))
|
.All(y => y != x))
|
||||||
.ToList();
|
.ToList();
|
||||||
if (tagsWithoutGroup.Any())
|
if (tagsWithoutGroup.Any())
|
||||||
{
|
{
|
||||||
tagGroups.Add(new
|
tagGroups.Add(new TagGroups
|
||||||
{
|
{
|
||||||
name = "Others",
|
Name = "Others",
|
||||||
tags = tagsWithoutGroup
|
Tags = tagsWithoutGroup
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
src/Kyoo.Swagger/Models/TagGroups.cs
Normal file
42
src/Kyoo.Swagger/Models/TagGroups.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// 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.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NSwag;
|
||||||
|
|
||||||
|
namespace Kyoo.Swagger.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class representing a group of tags in the <see cref="OpenApiDocument"/>
|
||||||
|
/// </summary>
|
||||||
|
public class TagGroups
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the tag group.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty(PropertyName = "name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of tags in this group.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty(PropertyName = "tags")]
|
||||||
|
public List<string> Tags { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user