2020-04-20 12:06:29 -07:00
using System ;
using System.Collections.Generic ;
2020-08-06 07:17:45 -07:00
using System.ComponentModel.DataAnnotations ;
2020-04-20 12:06:29 -07:00
using System.IO ;
using System.Linq ;
2020-05-19 12:13:07 -07:00
using System.Net.Mime ;
2020-09-03 05:42:56 -07:00
using Jellyfin.Api.Attributes ;
2020-06-22 06:44:11 -07:00
using Jellyfin.Api.Constants ;
2020-04-20 12:06:29 -07:00
using MediaBrowser.Controller ;
using MediaBrowser.Controller.Configuration ;
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Model.Dto ;
using MediaBrowser.Model.IO ;
using MediaBrowser.Model.Net ;
2020-05-19 08:24:04 -07:00
using Microsoft.AspNetCore.Authorization ;
2020-04-20 12:06:29 -07:00
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
2020-06-17 09:49:34 -07:00
namespace Jellyfin.Api.Controllers
2020-04-20 12:06:29 -07:00
{
/// <summary>
/// Images By Name Controller.
/// </summary>
[Route("Images")]
public class ImageByNameController : BaseJellyfinApiController
{
private readonly IServerApplicationPaths _applicationPaths ;
private readonly IFileSystem _fileSystem ;
/// <summary>
/// Initializes a new instance of the <see cref="ImageByNameController" /> class.
/// </summary>
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager" /> interface.</param>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem" /> interface.</param>
public ImageByNameController (
IServerConfigurationManager serverConfigurationManager ,
IFileSystem fileSystem )
{
_applicationPaths = serverConfigurationManager . ApplicationPaths ;
_fileSystem = fileSystem ;
}
/// <summary>
/// Get all general images.
/// </summary>
2020-05-02 17:46:27 -07:00
/// <response code="200">Retrieved list of images.</response>
/// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
2020-04-20 12:06:29 -07:00
[HttpGet("General")]
2020-06-22 06:44:11 -07:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-05-02 17:46:27 -07:00
public ActionResult < IEnumerable < ImageByNameInfo > > GetGeneralImages ( )
2020-04-20 12:06:29 -07:00
{
2020-05-19 08:14:37 -07:00
return GetImageList ( _applicationPaths . GeneralPath , false ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Get General Image.
/// </summary>
/// <param name="name">The name of the image.</param>
/// <param name="type">Image Type (primary, backdrop, logo, etc).</param>
2020-05-02 17:46:27 -07:00
/// <response code="200">Image stream retrieved.</response>
/// <response code="404">Image not found.</response>
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
2020-06-20 17:02:07 -07:00
[HttpGet("General/{name}/{type}")]
2020-06-04 09:10:36 -07:00
[AllowAnonymous]
2020-05-19 12:13:07 -07:00
[Produces(MediaTypeNames.Application.Octet)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-04-20 12:06:29 -07:00
[ProducesResponseType(StatusCodes.Status404NotFound)]
2020-09-03 05:42:56 -07:00
[ProducesImageFile]
2020-09-09 13:23:53 -07:00
public ActionResult GetGeneralImage ( [ FromRoute , Required ] string name , [ FromRoute , Required ] string type )
2020-04-20 12:06:29 -07:00
{
2020-04-21 06:57:45 -07:00
var filename = string . Equals ( type , "primary" , StringComparison . OrdinalIgnoreCase )
? "folder"
: type ;
2020-04-20 12:06:29 -07:00
2020-06-04 09:10:36 -07:00
var path = BaseItem . SupportedImageExtensions
2021-03-19 16:46:59 -07:00
. Select ( i = > Path . GetFullPath ( Path . Combine ( _applicationPaths . GeneralPath , name , filename + i ) ) )
2020-06-04 09:10:36 -07:00
. FirstOrDefault ( System . IO . File . Exists ) ;
2020-04-20 12:06:29 -07:00
2020-06-04 09:10:36 -07:00
if ( path = = null )
2020-04-20 12:06:29 -07:00
{
2020-04-21 06:57:45 -07:00
return NotFound ( ) ;
2020-04-20 12:06:29 -07:00
}
2020-04-21 06:57:45 -07:00
2021-11-08 12:39:02 -07:00
if ( ! path . StartsWith ( _applicationPaths . GeneralPath , StringComparison . InvariantCulture ) )
2021-03-19 16:46:59 -07:00
{
return BadRequest ( "Invalid image path." ) ;
}
2020-04-21 06:57:45 -07:00
var contentType = MimeTypes . GetMimeType ( path ) ;
2021-06-12 13:20:35 -07:00
return File ( AsyncFile . OpenRead ( path ) , contentType ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Get all general images.
/// </summary>
2020-05-02 17:46:27 -07:00
/// <response code="200">Retrieved list of images.</response>
/// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
2020-04-20 12:06:29 -07:00
[HttpGet("Ratings")]
2020-06-22 06:44:11 -07:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-05-02 17:46:27 -07:00
public ActionResult < IEnumerable < ImageByNameInfo > > GetRatingImages ( )
2020-04-20 12:06:29 -07:00
{
2020-05-19 08:14:37 -07:00
return GetImageList ( _applicationPaths . RatingsPath , false ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Get rating image.
/// </summary>
/// <param name="theme">The theme to get the image from.</param>
/// <param name="name">The name of the image.</param>
2020-05-02 17:46:27 -07:00
/// <response code="200">Image stream retrieved.</response>
/// <response code="404">Image not found.</response>
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
2020-06-20 17:02:07 -07:00
[HttpGet("Ratings/{theme}/{name}")]
2020-06-04 09:10:36 -07:00
[AllowAnonymous]
2020-05-19 12:13:07 -07:00
[Produces(MediaTypeNames.Application.Octet)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-04-20 12:06:29 -07:00
[ProducesResponseType(StatusCodes.Status404NotFound)]
2020-09-03 05:42:56 -07:00
[ProducesImageFile]
2020-09-02 14:06:13 -07:00
public ActionResult GetRatingImage (
2020-09-07 17:45:06 -07:00
[FromRoute, Required] string theme ,
[FromRoute, Required] string name )
2020-04-20 12:06:29 -07:00
{
2020-04-21 06:57:45 -07:00
return GetImageFile ( _applicationPaths . RatingsPath , theme , name ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Get all media info images.
/// </summary>
2020-05-02 17:46:27 -07:00
/// <response code="200">Image list retrieved.</response>
/// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
2020-04-20 12:06:29 -07:00
[HttpGet("MediaInfo")]
2020-06-22 06:44:11 -07:00
[Authorize(Policy = Policies.DefaultAuthorization)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-05-02 17:47:05 -07:00
public ActionResult < IEnumerable < ImageByNameInfo > > GetMediaInfoImages ( )
2020-04-20 12:06:29 -07:00
{
2020-05-19 08:14:37 -07:00
return GetImageList ( _applicationPaths . MediaInfoImagesPath , false ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Get media info image.
/// </summary>
/// <param name="theme">The theme to get the image from.</param>
/// <param name="name">The name of the image.</param>
2020-05-02 17:46:27 -07:00
/// <response code="200">Image stream retrieved.</response>
/// <response code="404">Image not found.</response>
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
2020-06-20 17:02:07 -07:00
[HttpGet("MediaInfo/{theme}/{name}")]
2020-06-04 09:10:36 -07:00
[AllowAnonymous]
2020-05-19 12:13:07 -07:00
[Produces(MediaTypeNames.Application.Octet)]
2020-04-21 13:07:11 -07:00
[ProducesResponseType(StatusCodes.Status200OK)]
2020-04-20 12:06:29 -07:00
[ProducesResponseType(StatusCodes.Status404NotFound)]
2020-09-03 05:42:56 -07:00
[ProducesImageFile]
2020-09-02 14:06:13 -07:00
public ActionResult GetMediaInfoImage (
2020-09-07 17:45:06 -07:00
[FromRoute, Required] string theme ,
[FromRoute, Required] string name )
2020-04-20 12:06:29 -07:00
{
2020-04-21 06:57:45 -07:00
return GetImageFile ( _applicationPaths . MediaInfoImagesPath , theme , name ) ;
2020-04-20 12:06:29 -07:00
}
/// <summary>
/// Internal FileHelper.
/// </summary>
/// <param name="basePath">Path to begin search.</param>
/// <param name="theme">Theme to search.</param>
/// <param name="name">File name to search for.</param>
2020-05-02 17:46:27 -07:00
/// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
2020-11-13 09:04:31 -07:00
private ActionResult GetImageFile ( string basePath , string theme , string? name )
2020-04-20 12:06:29 -07:00
{
2021-03-19 16:46:59 -07:00
var themeFolder = Path . GetFullPath ( Path . Combine ( basePath , theme ) ) ;
2020-04-20 12:06:29 -07:00
if ( Directory . Exists ( themeFolder ) )
{
var path = BaseItem . SupportedImageExtensions . Select ( i = > Path . Combine ( themeFolder , name + i ) )
. FirstOrDefault ( System . IO . File . Exists ) ;
if ( ! string . IsNullOrEmpty ( path ) & & System . IO . File . Exists ( path ) )
{
2021-11-08 12:39:02 -07:00
if ( ! path . StartsWith ( basePath , StringComparison . InvariantCulture ) )
2021-03-19 16:46:59 -07:00
{
return BadRequest ( "Invalid image path." ) ;
}
2020-04-20 12:06:29 -07:00
var contentType = MimeTypes . GetMimeType ( path ) ;
2021-03-19 16:46:59 -07:00
2020-09-02 14:06:13 -07:00
return PhysicalFile ( path , contentType ) ;
2020-04-20 12:06:29 -07:00
}
}
2021-03-19 16:46:59 -07:00
var allFolder = Path . GetFullPath ( Path . Combine ( basePath , "all" ) ) ;
2020-04-20 12:06:29 -07:00
if ( Directory . Exists ( allFolder ) )
{
var path = BaseItem . SupportedImageExtensions . Select ( i = > Path . Combine ( allFolder , name + i ) )
. FirstOrDefault ( System . IO . File . Exists ) ;
if ( ! string . IsNullOrEmpty ( path ) & & System . IO . File . Exists ( path ) )
{
2021-11-08 12:39:02 -07:00
if ( ! path . StartsWith ( basePath , StringComparison . InvariantCulture ) )
2021-03-19 16:46:59 -07:00
{
return BadRequest ( "Invalid image path." ) ;
}
2020-04-20 12:06:29 -07:00
var contentType = MimeTypes . GetMimeType ( path ) ;
2020-09-02 14:06:13 -07:00
return PhysicalFile ( path , contentType ) ;
2020-04-20 12:06:29 -07:00
}
}
return NotFound ( ) ;
}
private List < ImageByNameInfo > GetImageList ( string path , bool supportsThemes )
{
try
{
return _fileSystem . GetFiles ( path , BaseItem . SupportedImageExtensions , false , true )
. Select ( i = > new ImageByNameInfo
{
Name = _fileSystem . GetFileNameWithoutExtension ( i ) ,
FileLength = i . Length ,
// For themeable images, use the Theme property
// For general images, the same object structure is fine,
// but it's not owned by a theme, so call it Context
Theme = supportsThemes ? GetThemeName ( i . FullName , path ) : null ,
Context = supportsThemes ? null : GetThemeName ( i . FullName , path ) ,
Format = i . Extension . ToLowerInvariant ( ) . TrimStart ( '.' )
} )
. OrderBy ( i = > i . Name )
. ToList ( ) ;
}
catch ( IOException )
{
return new List < ImageByNameInfo > ( ) ;
}
}
2020-04-20 12:12:35 -07:00
private string? GetThemeName ( string path , string rootImagePath )
2020-04-20 12:06:29 -07:00
{
var parentName = Path . GetDirectoryName ( path ) ;
if ( string . Equals ( parentName , rootImagePath , StringComparison . OrdinalIgnoreCase ) )
{
return null ;
}
parentName = Path . GetFileName ( parentName ) ;
return string . Equals ( parentName , "all" , StringComparison . OrdinalIgnoreCase ) ? null : parentName ;
}
}
}