// 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 Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using static Kyoo.Abstractions.Models.Utils.Constants; namespace Kyoo.Core.Api { /// /// Information about one or multiple . /// [Route("api/episodes")] [Route("api/episode", Order = AlternativeRoute)] [ApiController] [ResourceView] [PartialPermission(nameof(EpisodeApi))] [ApiDefinition("Episodes", Group = ResourcesGroup)] public class EpisodeApi : 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 in the data store. /// /// The file manager used to send images. /// The thumbnail manager used to retrieve images paths. public EpisodeApi(ILibraryManager libraryManager, IFileSystem files, IThumbnailsManager thumbnails) : base(libraryManager.EpisodeRepository, files, thumbnails) { _libraryManager = libraryManager; } /// /// Get episode's show /// /// /// Get the show that this episode is part of. /// /// The ID or slug of the . /// The show that contains this episode. /// No episode with the given ID or slug could be found. [HttpGet("{identifier:id}/show")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetShow(Identifier identifier) { Show ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn(x => x.Episodes)); if (ret == null) return NotFound(); return ret; } /// /// Get episode's season /// /// /// Get the season that this episode is part of. /// /// The ID or slug of the . /// The season that contains this episode. /// The episode is not part of a season. /// No episode with the given ID or slug could be found. [HttpGet("{identifier:id}/season")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetSeason(Identifier identifier) { Season ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn(x => x.Episodes)); if (ret != null) return ret; Episode episode = await identifier.Match( id => _libraryManager.GetOrDefault(id), slug => _libraryManager.GetOrDefault(slug) ); return episode == null ? NotFound() : NoContent(); } /// /// Get tracks /// /// /// List the tracks (video, audio and subtitles) available for this episode. /// This endpoint provide the list of raw tracks, without transcode on it. To get a schema easier to watch /// on a player, see the [/watch endpoint](#/watch). /// /// The ID or slug of the . /// A key to sort tracks by. /// An optional list of filters. /// The number of tracks to return. /// An optional track's ID to start the query from this specific item. /// A page of tracks. /// The filters or the sort parameters are invalid. /// No episode with the given ID or slug could be found. /// TODO fix the /watch endpoint link (when operations ID are specified). [HttpGet("{identifier:id}/tracks")] [HttpGet("{identifier:id}/track", Order = AlternativeRoute)] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task>> GetEpisode(Identifier identifier, [FromQuery] string sortBy, [FromQuery] Dictionary where, [FromQuery] int limit = 30, [FromQuery] int? afterID = null) { try { ICollection resources = await _libraryManager.GetAll( ApiHelper.ParseWhere(where, identifier.Matcher(x => x.EpisodeID, x => x.Episode.Slug)), new Sort(sortBy), new Pagination(limit, afterID)); if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, limit); } catch (ArgumentException ex) { return BadRequest(new RequestError(ex.Message)); } } } }