EmbeddedImageProviderTests.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MediaBrowser.Controller.Entities;
  7. using MediaBrowser.Controller.Entities.Movies;
  8. using MediaBrowser.Controller.Entities.TV;
  9. using MediaBrowser.Controller.Library;
  10. using MediaBrowser.Controller.MediaEncoding;
  11. using MediaBrowser.Controller.Persistence;
  12. using MediaBrowser.Model.Drawing;
  13. using MediaBrowser.Model.Dto;
  14. using MediaBrowser.Model.Entities;
  15. using MediaBrowser.Providers.MediaInfo;
  16. using Microsoft.Extensions.Logging.Abstractions;
  17. using Moq;
  18. using Xunit;
  19. namespace Jellyfin.Providers.Tests.MediaInfo
  20. {
  21. public class EmbeddedImageProviderTests
  22. {
  23. [Theory]
  24. [InlineData(typeof(AudioBook))]
  25. [InlineData(typeof(BoxSet))]
  26. [InlineData(typeof(Series))]
  27. [InlineData(typeof(Season))]
  28. [InlineData(typeof(Episode), ImageType.Primary)]
  29. [InlineData(typeof(Movie), ImageType.Logo, ImageType.Backdrop, ImageType.Primary)]
  30. public void GetSupportedImages_AnyBaseItem_ReturnsExpected(Type type, params ImageType[] expected)
  31. {
  32. BaseItem item = (BaseItem)Activator.CreateInstance(type)!;
  33. var embeddedImageProvider = new EmbeddedImageProvider(Mock.Of<IMediaSourceManager>(), Mock.Of<IMediaEncoder>(), new NullLogger<EmbeddedImageProvider>());
  34. var actual = embeddedImageProvider.GetSupportedImages(item);
  35. Assert.Equal(expected.OrderBy(i => i.ToString()), actual.OrderBy(i => i.ToString()));
  36. }
  37. [Fact]
  38. public async void GetImage_NoStreams_ReturnsNoImage()
  39. {
  40. var input = new Movie();
  41. var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), new List<MediaStream>());
  42. var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, null, new NullLogger<EmbeddedImageProvider>());
  43. var actual = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
  44. Assert.NotNull(actual);
  45. Assert.False(actual.HasImage);
  46. }
  47. [Theory]
  48. [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
  49. [InlineData("unmatched", null, 1, ImageType.Primary, null)] // doesn't default on no match
  50. [InlineData("clearlogo.png", null, 1, ImageType.Logo, ImageFormat.Png)] // extract extension from name
  51. [InlineData("backdrop", "image/bmp", 2, ImageType.Backdrop, ImageFormat.Bmp)] // extract extension from mimetype
  52. [InlineData("poster", null, 3, ImageType.Primary, ImageFormat.Jpg)] // default extension to jpg
  53. public async void GetImage_Attachment_ReturnsCorrectSelection(string filename, string mimetype, int targetIndex, ImageType type, ImageFormat? expectedFormat)
  54. {
  55. var attachments = new List<MediaAttachment>();
  56. string pathPrefix = "path";
  57. for (int i = 1; i <= targetIndex; i++)
  58. {
  59. var name = i == targetIndex ? filename : "unmatched";
  60. attachments.Add(new()
  61. {
  62. FileName = name,
  63. MimeType = mimetype,
  64. Index = i
  65. });
  66. }
  67. var input = new Movie();
  68. var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
  69. mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<int>(), It.IsAny<ImageFormat>(), It.IsAny<CancellationToken>()))
  70. .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, _, index, ext, _) => Task.FromResult(pathPrefix + index + "." + ext));
  71. var mediaSourceManager = GetMediaSourceManager(input, attachments, new List<MediaStream>());
  72. var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());
  73. var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
  74. Assert.NotNull(actual);
  75. if (expectedFormat == null)
  76. {
  77. Assert.False(actual.HasImage);
  78. }
  79. else
  80. {
  81. Assert.True(actual.HasImage);
  82. Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
  83. Assert.Equal(expectedFormat, actual.Format);
  84. }
  85. }
  86. [Theory]
  87. [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
  88. [InlineData(null, null, 1, ImageType.Backdrop, null)] // no label, can only find primary
  89. [InlineData(null, null, 1, ImageType.Primary, ImageFormat.Jpg)] // no label, finds primary
  90. [InlineData("backdrop", null, 2, ImageType.Backdrop, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
  91. [InlineData("cover", null, 2, ImageType.Primary, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
  92. [InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)]
  93. [InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)]
  94. [InlineData(null, "gif", 1, ImageType.Primary, ImageFormat.Gif)]
  95. public async void GetImage_Embedded_ReturnsCorrectSelection(string label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat)
  96. {
  97. var streams = new List<MediaStream>();
  98. for (int i = 1; i <= targetIndex; i++)
  99. {
  100. var comment = i == targetIndex ? label : "unmatched";
  101. streams.Add(new()
  102. {
  103. Type = MediaStreamType.EmbeddedImage,
  104. Index = i,
  105. Comment = comment,
  106. Codec = codec
  107. });
  108. }
  109. var input = new Movie();
  110. var pathPrefix = "path";
  111. var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
  112. mediaEncoder.Setup(encoder => encoder.ExtractVideoImage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MediaSourceInfo>(), It.IsAny<MediaStream>(), It.IsAny<int>(), It.IsAny<ImageFormat>(), It.IsAny<CancellationToken>()))
  113. .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, stream, index, ext, _) =>
  114. {
  115. Assert.Equal(streams[index - 1], stream);
  116. return Task.FromResult(pathPrefix + index + "." + ext);
  117. });
  118. var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), streams);
  119. var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());
  120. var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
  121. Assert.NotNull(actual);
  122. if (expectedFormat == null)
  123. {
  124. Assert.False(actual.HasImage);
  125. }
  126. else
  127. {
  128. Assert.True(actual.HasImage);
  129. Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
  130. Assert.Equal(expectedFormat, actual.Format);
  131. }
  132. }
  133. private static IMediaSourceManager GetMediaSourceManager(BaseItem item, List<MediaAttachment> mediaAttachments, List<MediaStream> mediaStreams)
  134. {
  135. var mediaSourceManager = new Mock<IMediaSourceManager>(MockBehavior.Strict);
  136. mediaSourceManager.Setup(i => i.GetMediaAttachments(item.Id))
  137. .Returns(mediaAttachments);
  138. mediaSourceManager.Setup(i => i.GetMediaStreams(It.Is<MediaStreamQuery>(q => q.ItemId.Equals(item.Id) && q.Type == MediaStreamType.EmbeddedImage)))
  139. .Returns(mediaStreams);
  140. return mediaSourceManager.Object;
  141. }
  142. }
  143. }