// 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 . using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Abstractions.Models.Permissions; using Kyoo.Abstractions.Models.Utils; using Kyoo.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using static Kyoo.Abstractions.Models.Utils.Constants; namespace Kyoo.Core.Api { /// /// Information about one or multiple . /// [Route("shows")] [Route("show", Order = AlternativeRoute)] [ApiController] [PartialPermission(nameof(Show))] [ApiDefinition("Shows", Group = ResourcesGroup)] public class ShowApi : CrudThumbsApi { /// /// The library manager used to modify or retrieve information in the data store. /// private readonly ILibraryManager _libraryManager; /// /// Create a new . /// /// /// The library manager used to modify or retrieve information about the data store. /// /// The thumbnail manager used to retrieve images paths. public ShowApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) : base(libraryManager.Shows, thumbs) { _libraryManager = libraryManager; } /// /// 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. /// The aditional fields to include in the result. /// 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)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetSeasons(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Filter? filter, [FromQuery] Pagination pagination, [FromQuery] Include fields) { ICollection resources = await _libraryManager.Seasons.GetAll( Filter.And(filter, identifier.Matcher(x => x.ShowId, x => x.Show!.Slug)), sortBy, fields, pagination ); if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } /// /// 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. /// The aditional fields to include in the result. /// 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)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetEpisodes(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Filter? filter, [FromQuery] Pagination pagination, [FromQuery] Include fields) { ICollection resources = await _libraryManager.Episodes.GetAll( Filter.And(filter, identifier.Matcher(x => x.ShowId, x => x.Show!.Slug)), sortBy, fields, pagination ); if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } // /// // /// Get staff // /// // /// // /// 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. // /// The aditional fields to include in the result. // /// 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}/staff")] // [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] // [PartialPermission(Kind.Read)] // [ProducesResponseType(StatusCodes.Status200OK)] // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] // [ProducesResponseType(StatusCodes.Status404NotFound)] // public async Task>> GetPeople(Identifier identifier, // [FromQuery] Sort sortBy, // [FromQuery] Dictionary where, // [FromQuery] Pagination pagination, // [FromQuery] Include fields) // { // Expression>? whereQuery = ApiHelper.ParseWhere(where); // // ICollection resources = await identifier.Match( // id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination), // slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination) // ); // return Page(resources, pagination.Limit); // } /// /// Get studio that made the show /// /// /// Get the studio that made the show. /// /// The ID or slug of the . /// The aditional fields to include in the result. /// The studio that made the show. /// No show with the given ID or slug could be found. [HttpGet("{identifier:id}/studio")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetStudio(Identifier identifier, [FromQuery] Include fields) { return await _libraryManager.Studios.Get(identifier.IsContainedIn(x => x.Shows!), fields); } /// /// 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. /// The aditional fields to include in the result. /// 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}/collections")] [HttpGet("{identifier:id}/collection", Order = AlternativeRoute)] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetCollections(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Filter? filter, [FromQuery] Pagination pagination, [FromQuery] Include fields) { ICollection resources = await _libraryManager.Collections.GetAll( Filter.And(filter, identifier.IsContainedIn(x => x.Shows!)), sortBy, fields, pagination ); if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } /// /// Get watch status /// /// /// Get when an item has been wathed and if it was watched. /// /// The ID or slug of the . /// The status. /// This show does not have a specific status. /// No show with the given ID or slug could be found. [HttpGet("{identifier:id}/watchStatus")] [UserOnly] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetWatchStatus(Identifier identifier) { Guid id = await identifier.Match( id => Task.FromResult(id), async slug => (await _libraryManager.Shows.Get(slug)).Id ); return await _libraryManager.WatchStatus.GetShowStatus(id, User.GetIdOrThrow()); } /// /// Set watch status /// /// /// Set when an item has been wathed and if it was watched. /// /// The ID or slug of the . /// The new watch status. /// The newly set status. /// The status has been set /// The status was not considered impactfull enough to be saved (less then 5% of watched for example). /// No movie with the given ID or slug could be found. [HttpPost("{identifier:id}/watchStatus")] [UserOnly] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task SetWatchStatus(Identifier identifier, WatchStatus status) { Guid id = await identifier.Match( id => Task.FromResult(id), async slug => (await _libraryManager.Shows.Get(slug)).Id ); return await _libraryManager.WatchStatus.SetShowStatus( id, User.GetIdOrThrow(), status ); } /// /// Delete watch status /// /// /// Delete watch status (to rewatch for example). /// /// The ID or slug of the . /// The newly set status. /// The status has been deleted. /// No show with the given ID or slug could be found. [HttpDelete("{identifier:id}/watchStatus")] [UserOnly] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteWatchStatus(Identifier identifier) { Guid id = await identifier.Match( id => Task.FromResult(id), async slug => (await _libraryManager.Shows.Get(slug)).Id ); await _libraryManager.WatchStatus.DeleteShowStatus(id, User.GetIdOrThrow()); } } }