ImageByNameController.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net.Mime;
  6. using MediaBrowser.Controller;
  7. using MediaBrowser.Controller.Configuration;
  8. using MediaBrowser.Controller.Entities;
  9. using MediaBrowser.Model.Dto;
  10. using MediaBrowser.Model.IO;
  11. using MediaBrowser.Model.Net;
  12. using Microsoft.AspNetCore.Authorization;
  13. using Microsoft.AspNetCore.Http;
  14. using Microsoft.AspNetCore.Mvc;
  15. namespace Jellyfin.Api.Controllers
  16. {
  17. /// <summary>
  18. /// Images By Name Controller.
  19. /// </summary>
  20. [Route("Images")]
  21. public class ImageByNameController : BaseJellyfinApiController
  22. {
  23. private readonly IServerApplicationPaths _applicationPaths;
  24. private readonly IFileSystem _fileSystem;
  25. /// <summary>
  26. /// Initializes a new instance of the <see cref="ImageByNameController" /> class.
  27. /// </summary>
  28. /// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager" /> interface.</param>
  29. /// <param name="fileSystem">Instance of the <see cref="IFileSystem" /> interface.</param>
  30. public ImageByNameController(
  31. IServerConfigurationManager serverConfigurationManager,
  32. IFileSystem fileSystem)
  33. {
  34. _applicationPaths = serverConfigurationManager.ApplicationPaths;
  35. _fileSystem = fileSystem;
  36. }
  37. /// <summary>
  38. /// Get all general images.
  39. /// </summary>
  40. /// <response code="200">Retrieved list of images.</response>
  41. /// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
  42. [HttpGet("General")]
  43. [Authorize]
  44. [ProducesResponseType(StatusCodes.Status200OK)]
  45. public ActionResult<IEnumerable<ImageByNameInfo>> GetGeneralImages()
  46. {
  47. return GetImageList(_applicationPaths.GeneralPath, false);
  48. }
  49. /// <summary>
  50. /// Get General Image.
  51. /// </summary>
  52. /// <param name="name">The name of the image.</param>
  53. /// <param name="type">Image Type (primary, backdrop, logo, etc).</param>
  54. /// <response code="200">Image stream retrieved.</response>
  55. /// <response code="404">Image not found.</response>
  56. /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
  57. [HttpGet("General/{name}/{type}")]
  58. [AllowAnonymous]
  59. [Produces(MediaTypeNames.Application.Octet)]
  60. [ProducesResponseType(StatusCodes.Status200OK)]
  61. [ProducesResponseType(StatusCodes.Status404NotFound)]
  62. public ActionResult<FileStreamResult> GetGeneralImage([FromRoute] string name, [FromRoute] string type)
  63. {
  64. var filename = string.Equals(type, "primary", StringComparison.OrdinalIgnoreCase)
  65. ? "folder"
  66. : type;
  67. var path = BaseItem.SupportedImageExtensions
  68. .Select(i => Path.Combine(_applicationPaths.GeneralPath, name, filename + i))
  69. .FirstOrDefault(System.IO.File.Exists);
  70. if (path == null)
  71. {
  72. return NotFound();
  73. }
  74. var contentType = MimeTypes.GetMimeType(path);
  75. return File(System.IO.File.OpenRead(path), contentType);
  76. }
  77. /// <summary>
  78. /// Get all general images.
  79. /// </summary>
  80. /// <response code="200">Retrieved list of images.</response>
  81. /// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
  82. [HttpGet("Ratings")]
  83. [Authorize]
  84. [ProducesResponseType(StatusCodes.Status200OK)]
  85. public ActionResult<IEnumerable<ImageByNameInfo>> GetRatingImages()
  86. {
  87. return GetImageList(_applicationPaths.RatingsPath, false);
  88. }
  89. /// <summary>
  90. /// Get rating image.
  91. /// </summary>
  92. /// <param name="theme">The theme to get the image from.</param>
  93. /// <param name="name">The name of the image.</param>
  94. /// <response code="200">Image stream retrieved.</response>
  95. /// <response code="404">Image not found.</response>
  96. /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
  97. [HttpGet("Ratings/{theme}/{name}")]
  98. [AllowAnonymous]
  99. [Produces(MediaTypeNames.Application.Octet)]
  100. [ProducesResponseType(StatusCodes.Status200OK)]
  101. [ProducesResponseType(StatusCodes.Status404NotFound)]
  102. public ActionResult<FileStreamResult> GetRatingImage(
  103. [FromRoute] string theme,
  104. [FromRoute] string name)
  105. {
  106. return GetImageFile(_applicationPaths.RatingsPath, theme, name);
  107. }
  108. /// <summary>
  109. /// Get all media info images.
  110. /// </summary>
  111. /// <response code="200">Image list retrieved.</response>
  112. /// <returns>An <see cref="OkResult"/> containing the list of images.</returns>
  113. [HttpGet("MediaInfo")]
  114. [Authorize]
  115. [ProducesResponseType(StatusCodes.Status200OK)]
  116. public ActionResult<IEnumerable<ImageByNameInfo>> GetMediaInfoImages()
  117. {
  118. return GetImageList(_applicationPaths.MediaInfoImagesPath, false);
  119. }
  120. /// <summary>
  121. /// Get media info image.
  122. /// </summary>
  123. /// <param name="theme">The theme to get the image from.</param>
  124. /// <param name="name">The name of the image.</param>
  125. /// <response code="200">Image stream retrieved.</response>
  126. /// <response code="404">Image not found.</response>
  127. /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
  128. [HttpGet("MediaInfo/{theme}/{name}")]
  129. [AllowAnonymous]
  130. [Produces(MediaTypeNames.Application.Octet)]
  131. [ProducesResponseType(StatusCodes.Status200OK)]
  132. [ProducesResponseType(StatusCodes.Status404NotFound)]
  133. public ActionResult<FileStreamResult> GetMediaInfoImage(
  134. [FromRoute] string theme,
  135. [FromRoute] string name)
  136. {
  137. return GetImageFile(_applicationPaths.MediaInfoImagesPath, theme, name);
  138. }
  139. /// <summary>
  140. /// Internal FileHelper.
  141. /// </summary>
  142. /// <param name="basePath">Path to begin search.</param>
  143. /// <param name="theme">Theme to search.</param>
  144. /// <param name="name">File name to search for.</param>
  145. /// <returns>A <see cref="FileStreamResult"/> containing the image contents on success, or a <see cref="NotFoundResult"/> if the image could not be found.</returns>
  146. private ActionResult<FileStreamResult> GetImageFile(string basePath, string theme, string name)
  147. {
  148. var themeFolder = Path.Combine(basePath, theme);
  149. if (Directory.Exists(themeFolder))
  150. {
  151. var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(themeFolder, name + i))
  152. .FirstOrDefault(System.IO.File.Exists);
  153. if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
  154. {
  155. var contentType = MimeTypes.GetMimeType(path);
  156. return File(System.IO.File.OpenRead(path), contentType);
  157. }
  158. }
  159. var allFolder = Path.Combine(basePath, "all");
  160. if (Directory.Exists(allFolder))
  161. {
  162. var path = BaseItem.SupportedImageExtensions.Select(i => Path.Combine(allFolder, name + i))
  163. .FirstOrDefault(System.IO.File.Exists);
  164. if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
  165. {
  166. var contentType = MimeTypes.GetMimeType(path);
  167. return File(System.IO.File.OpenRead(path), contentType);
  168. }
  169. }
  170. return NotFound();
  171. }
  172. private List<ImageByNameInfo> GetImageList(string path, bool supportsThemes)
  173. {
  174. try
  175. {
  176. return _fileSystem.GetFiles(path, BaseItem.SupportedImageExtensions, false, true)
  177. .Select(i => new ImageByNameInfo
  178. {
  179. Name = _fileSystem.GetFileNameWithoutExtension(i),
  180. FileLength = i.Length,
  181. // For themeable images, use the Theme property
  182. // For general images, the same object structure is fine,
  183. // but it's not owned by a theme, so call it Context
  184. Theme = supportsThemes ? GetThemeName(i.FullName, path) : null,
  185. Context = supportsThemes ? null : GetThemeName(i.FullName, path),
  186. Format = i.Extension.ToLowerInvariant().TrimStart('.')
  187. })
  188. .OrderBy(i => i.Name)
  189. .ToList();
  190. }
  191. catch (IOException)
  192. {
  193. return new List<ImageByNameInfo>();
  194. }
  195. }
  196. private string? GetThemeName(string path, string rootImagePath)
  197. {
  198. var parentName = Path.GetDirectoryName(path);
  199. if (string.Equals(parentName, rootImagePath, StringComparison.OrdinalIgnoreCase))
  200. {
  201. return null;
  202. }
  203. parentName = Path.GetFileName(parentName);
  204. return string.Equals(parentName, "all", StringComparison.OrdinalIgnoreCase) ? null : parentName;
  205. }
  206. }
  207. }