using System; using System.ComponentModel.DataAnnotations; using System.Net.Mime; using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers { /// /// Attachments controller. /// [Route("Videos")] public class VideoAttachmentsController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; private readonly IAttachmentExtractor _attachmentExtractor; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. public VideoAttachmentsController( ILibraryManager libraryManager, IAttachmentExtractor attachmentExtractor) { _libraryManager = libraryManager; _attachmentExtractor = attachmentExtractor; } /// /// Get video attachment. /// /// Video ID. /// Media Source ID. /// Attachment Index. /// Attachment retrieved. /// Video or attachment not found. /// An containing the attachment stream on success, or a if the attachment could not be found. [HttpGet("{videoId}/{mediaSourceId}/Attachments/{index}")] [ProducesFile(MediaTypeNames.Application.Octet)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task GetAttachment( [FromRoute, Required] Guid videoId, [FromRoute, Required] string mediaSourceId, [FromRoute, Required] int index) { try { var item = _libraryManager.GetItemById(videoId); if (item is null) { return NotFound(); } var (attachment, stream) = await _attachmentExtractor.GetAttachment( item, mediaSourceId, index, CancellationToken.None) .ConfigureAwait(false); var contentType = string.IsNullOrWhiteSpace(attachment.MimeType) ? MediaTypeNames.Application.Octet : attachment.MimeType; return new FileStreamResult(stream, contentType); } catch (ResourceNotFoundException e) { return NotFound(e.Message); } } } }