#nullable enable using System; using System.Collections.Generic; using System.IO; using System.Linq; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Dto; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers.Images { /// /// Images By Name Controller. /// [Route("Images")] [Authenticated] public class ImageByNameController : BaseJellyfinApiController { private readonly IServerApplicationPaths _applicationPaths; private readonly IFileSystem _fileSystem; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. public ImageByNameController( IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem) { _applicationPaths = serverConfigurationManager.ApplicationPaths; _fileSystem = fileSystem; } /// /// Get all general images. /// /// General images. [HttpGet("General")] [ProducesResponseType(typeof(ImageByNameInfo[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetGeneralImages() { try { return Ok(GetImageList(_applicationPaths.GeneralPath, false)); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Get General Image. /// /// The name of the image. /// Image Type (primary, backdrop, logo, etc). /// Image Stream. [HttpGet("General/{Name}/{Type}")] [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetGeneralImage([FromRoute] string name, [FromRoute] string type) { try { var filename = string.Equals(type, "primary", StringComparison.OrdinalIgnoreCase) ? "folder" : type; var paths = BaseItem.SupportedImageExtensions .Select(i => Path.Combine(_applicationPaths.GeneralPath, name, filename + i)).ToList(); var path = paths.FirstOrDefault(System.IO.File.Exists) ?? paths.FirstOrDefault(); if (path == null || !System.IO.File.Exists(path)) { return NotFound(); } var contentType = MimeTypes.GetMimeType(path); return new FileStreamResult(System.IO.File.OpenRead(path), contentType); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Get all general images. /// /// General images. [HttpGet("Ratings")] [ProducesResponseType(typeof(ImageByNameInfo[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetRatingImages() { try { return Ok(GetImageList(_applicationPaths.RatingsPath, false)); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Get rating image. /// /// The theme to get the image from. /// The name of the image. /// Image Stream. [HttpGet("Ratings/{Theme}/{Name}")] [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetRatingImage( [FromRoute] string theme, [FromRoute] string name) { try { return GetImageFile(_applicationPaths.RatingsPath, theme, name); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Get all media info images. /// /// Media Info images. [HttpGet("MediaInfo")] [ProducesResponseType(typeof(ImageByNameInfo[]), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetMediaInfoImages() { try { return Ok(GetImageList(_applicationPaths.MediaInfoImagesPath, false)); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Get media info image. /// /// The theme to get the image from. /// The name of the image. /// Image Stream. [HttpGet("MediaInfo/{Theme}/{Name}")] [ProducesResponseType(typeof(FileStreamResult), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IActionResult GetMediaInfoImage( [FromRoute] string theme, [FromRoute] string name) { try { return GetImageFile(_applicationPaths.MediaInfoImagesPath, theme, name); } catch (Exception e) { return StatusCode(StatusCodes.Status500InternalServerError, e.Message); } } /// /// Internal FileHelper. /// /// Path to begin search. /// Theme to search. /// File name to search for. /// Image Stream. private IActionResult GetImageFile(string basePath, string theme, string name) { var themeFolder = Path.Combine(basePath, theme); 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)) { var contentType = MimeTypes.GetMimeType(path); return new FileStreamResult(System.IO.File.OpenRead(path), contentType); } } var allFolder = Path.Combine(basePath, "all"); 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)) { var contentType = MimeTypes.GetMimeType(path); return new FileStreamResult(System.IO.File.OpenRead(path), contentType); } } return NotFound(); } private List 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(); } } private string GetThemeName(string path, string rootImagePath) { 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; } } }