aboutsummaryrefslogtreecommitdiff
path: root/tests/Jellyfin.Providers.Tests/MediaInfo/EmbeddedImageProviderTests.cs
blob: 2bc686a33718ad3dd362e6d148d7da40ffe9519a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Providers.MediaInfo;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;

namespace Jellyfin.Providers.Tests.MediaInfo
{
    public class EmbeddedImageProviderTests
    {
        [Theory]
        [InlineData(typeof(AudioBook))]
        [InlineData(typeof(BoxSet))]
        [InlineData(typeof(Series))]
        [InlineData(typeof(Season))]
        [InlineData(typeof(Episode), ImageType.Primary)]
        [InlineData(typeof(Movie), ImageType.Logo, ImageType.Backdrop, ImageType.Primary)]
        public void GetSupportedImages_AnyBaseItem_ReturnsExpected(Type type, params ImageType[] expected)
        {
            BaseItem item = (BaseItem)Activator.CreateInstance(type)!;
            var embeddedImageProvider = new EmbeddedImageProvider(Mock.Of<IMediaSourceManager>(), Mock.Of<IMediaEncoder>(), new NullLogger<EmbeddedImageProvider>());
            var actual = embeddedImageProvider.GetSupportedImages(item);
            Assert.Equal(expected.OrderBy(i => i.ToString()), actual.OrderBy(i => i.ToString()));
        }

        [Fact]
        public async void GetImage_NoStreams_ReturnsNoImage()
        {
            var input = new Movie();

            var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), new List<MediaStream>());
            var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, null, new NullLogger<EmbeddedImageProvider>());

            var actual = await embeddedImageProvider.GetImage(input, ImageType.Primary, CancellationToken.None);
            Assert.NotNull(actual);
            Assert.False(actual.HasImage);
        }

        [Theory]
        [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
        [InlineData("unmatched", null, 1, ImageType.Primary, null)] // doesn't default on no match
        [InlineData("clearlogo.png", null, 1, ImageType.Logo, ImageFormat.Png)] // extract extension from name
        [InlineData("backdrop", "image/bmp", 2, ImageType.Backdrop, ImageFormat.Bmp)] // extract extension from mimetype
        [InlineData("poster", null, 3, ImageType.Primary, ImageFormat.Jpg)] // default extension to jpg
        public async void GetImage_Attachment_ReturnsCorrectSelection(string filename, string mimetype, int targetIndex, ImageType type, ImageFormat? expectedFormat)
        {
            var attachments = new List<MediaAttachment>();
            string pathPrefix = "path";
            for (int i = 1; i <= targetIndex; i++)
            {
                var name = i == targetIndex ? filename : "unmatched";
                attachments.Add(new()
                {
                    FileName = name,
                    MimeType = mimetype,
                    Index = i
                });
            }

            var input = new Movie();

            var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
            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>()))
                .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, _, index, ext, _) => Task.FromResult(pathPrefix + index + "." + ext));
            var mediaSourceManager = GetMediaSourceManager(input, attachments, new List<MediaStream>());
            var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());

            var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
            Assert.NotNull(actual);
            if (expectedFormat is null)
            {
                Assert.False(actual.HasImage);
            }
            else
            {
                Assert.True(actual.HasImage);
                Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
                Assert.Equal(expectedFormat, actual.Format);
            }
        }

        [Theory]
        [InlineData("chapter", null, 1, ImageType.Chapter, null)] // unexpected type, nothing found
        [InlineData(null, null, 1, ImageType.Backdrop, null)] // no label, can only find primary
        [InlineData(null, null, 1, ImageType.Primary, ImageFormat.Jpg)] // no label, finds primary
        [InlineData("backdrop", null, 2, ImageType.Backdrop, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
        [InlineData("cover", null, 2, ImageType.Primary, ImageFormat.Jpg)] // uses label to find index 2, not just pulling first stream
        [InlineData(null, "bmp", 1, ImageType.Primary, ImageFormat.Bmp)]
        [InlineData(null, "gif", 1, ImageType.Primary, ImageFormat.Gif)]
        [InlineData(null, "mjpeg", 1, ImageType.Primary, ImageFormat.Jpg)]
        [InlineData(null, "png", 1, ImageType.Primary, ImageFormat.Png)]
        [InlineData(null, "webp", 1, ImageType.Primary, ImageFormat.Webp)]
        public async void GetImage_Embedded_ReturnsCorrectSelection(string label, string? codec, int targetIndex, ImageType type, ImageFormat? expectedFormat)
        {
            var streams = new List<MediaStream>();
            for (int i = 1; i <= targetIndex; i++)
            {
                var comment = i == targetIndex ? label : "unmatched";
                streams.Add(new()
                {
                    Type = MediaStreamType.EmbeddedImage,
                    Index = i,
                    Comment = comment,
                    Codec = codec
                });
            }

            var input = new Movie();

            var pathPrefix = "path";
            var mediaEncoder = new Mock<IMediaEncoder>(MockBehavior.Strict);
            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>()))
                .Returns<string, string, MediaSourceInfo, MediaStream, int, ImageFormat, CancellationToken>((_, _, _, stream, index, ext, _) =>
                {
                    Assert.Equal(streams[index - 1], stream);
                    return Task.FromResult(pathPrefix + index + "." + ext);
                });
            var mediaSourceManager = GetMediaSourceManager(input, new List<MediaAttachment>(), streams);
            var embeddedImageProvider = new EmbeddedImageProvider(mediaSourceManager, mediaEncoder.Object, new NullLogger<EmbeddedImageProvider>());

            var actual = await embeddedImageProvider.GetImage(input, type, CancellationToken.None);
            Assert.NotNull(actual);
            if (expectedFormat is null)
            {
                Assert.False(actual.HasImage);
            }
            else
            {
                Assert.True(actual.HasImage);
                Assert.Equal(pathPrefix + targetIndex + "." + expectedFormat, actual.Path, StringComparer.OrdinalIgnoreCase);
                Assert.Equal(expectedFormat, actual.Format);
            }
        }

        private static IMediaSourceManager GetMediaSourceManager(BaseItem item, List<MediaAttachment> mediaAttachments, List<MediaStream> mediaStreams)
        {
            var mediaSourceManager = new Mock<IMediaSourceManager>(MockBehavior.Strict);
            mediaSourceManager.Setup(i => i.GetMediaAttachments(item.Id))
                .Returns(mediaAttachments);
            mediaSourceManager.Setup(i => i.GetMediaStreams(It.Is<MediaStreamQuery>(q => q.ItemId.Equals(item.Id) && q.Type == MediaStreamType.EmbeddedImage)))
                .Returns(mediaStreams);
            return mediaSourceManager.Object;
        }
    }
}