< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Books.OpenPackagingFormat.EpubImageProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Books/OpenPackagingFormat/EpubImageProvider.cs
Line coverage
7%
Covered lines: 3
Uncovered lines: 38
Coverable lines: 41
Total lines: 120
Line coverage: 7.3%
Branch coverage
0%
Covered branches: 0
Total branches: 14
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 1/29/2026 - 12:13:32 AM Line coverage: 42.8% (3/7) Branch coverage: 0% (0/2) Total lines: 1204/19/2026 - 12:14:27 AM Line coverage: 7.3% (3/41) Branch coverage: 0% (0/14) Total lines: 120 1/29/2026 - 12:13:32 AM Line coverage: 42.8% (3/7) Branch coverage: 0% (0/2) Total lines: 1204/19/2026 - 12:14:27 AM Line coverage: 7.3% (3/41) Branch coverage: 0% (0/14) Total lines: 120

Coverage delta

Coverage delta 36 -36

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Name()100%210%
Supports(...)100%11100%
GetSupportedImages()100%210%
GetImage(...)0%620%
LoadCover()0%2040%
GetFromZip()0%7280%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Books/OpenPackagingFormat/EpubImageProvider.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.IO;
 4using System.IO.Compression;
 5using System.Threading;
 6using System.Threading.Tasks;
 7using System.Xml;
 8using MediaBrowser.Controller.Entities;
 9using MediaBrowser.Controller.Providers;
 10using MediaBrowser.Model.Entities;
 11using Microsoft.Extensions.Logging;
 12
 13namespace MediaBrowser.Providers.Books.OpenPackagingFormat
 14{
 15    /// <summary>
 16    /// Provides the primary image for EPUB items that have embedded covers.
 17    /// </summary>
 18    public class EpubImageProvider : IDynamicImageProvider
 19    {
 20        private readonly ILogger<EpubImageProvider> _logger;
 21
 22        /// <summary>
 23        /// Initializes a new instance of the <see cref="EpubImageProvider"/> class.
 24        /// </summary>
 25        /// <param name="logger">Instance of the <see cref="ILogger{EpubImageProvider}"/> interface.</param>
 26        public EpubImageProvider(ILogger<EpubImageProvider> logger)
 27        {
 2128            _logger = logger;
 2129        }
 30
 31        /// <inheritdoc />
 032        public string Name => "EPUB Metadata";
 33
 34        /// <inheritdoc />
 35        public bool Supports(BaseItem item)
 36        {
 5737            return item is Book;
 38        }
 39
 40        /// <inheritdoc />
 41        public IEnumerable<ImageType> GetSupportedImages(BaseItem item)
 42        {
 043            yield return ImageType.Primary;
 044        }
 45
 46        /// <inheritdoc />
 47        public Task<DynamicImageResponse> GetImage(BaseItem item, ImageType type, CancellationToken cancellationToken)
 48        {
 049            if (string.Equals(Path.GetExtension(item.Path), ".epub", StringComparison.OrdinalIgnoreCase))
 50            {
 051                return GetFromZip(item, cancellationToken);
 52            }
 53
 054            return Task.FromResult(new DynamicImageResponse { HasImage = false });
 55        }
 56
 57        private async Task<DynamicImageResponse> LoadCover(ZipArchive epub, XmlDocument opf, string opfRootDirectory, Ca
 58        {
 059            var utilities = new OpfReader<EpubImageProvider>(opf, _logger);
 060            var coverReference = utilities.ReadCoverPath(opfRootDirectory);
 061            if (coverReference == null)
 62            {
 063                return new DynamicImageResponse { HasImage = false };
 64            }
 65
 066            var cover = coverReference.Value;
 067            var coverFile = epub.GetEntry(cover.Path);
 68
 069            if (coverFile == null)
 70            {
 071                return new DynamicImageResponse { HasImage = false };
 72            }
 73
 074            var memoryStream = new MemoryStream();
 75
 076            var coverStream = await coverFile.OpenAsync(cancellationToken).ConfigureAwait(false);
 077            await using (coverStream.ConfigureAwait(false))
 78            {
 079                await coverStream.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
 80            }
 81
 082            memoryStream.Position = 0;
 83
 084            var response = new DynamicImageResponse { HasImage = true, Stream = memoryStream };
 085            response.SetFormatFromMimeType(cover.MimeType);
 86
 087            return response;
 088        }
 89
 90        private async Task<DynamicImageResponse> GetFromZip(BaseItem item, CancellationToken cancellationToken)
 91        {
 092            using var epub = await ZipFile.OpenReadAsync(item.Path, cancellationToken).ConfigureAwait(false);
 93
 094            var opfFilePath = EpubUtils.ReadContentFilePath(epub);
 095            if (opfFilePath == null)
 96            {
 097                return new DynamicImageResponse { HasImage = false };
 98            }
 99
 0100            var opfRootDirectory = Path.GetDirectoryName(opfFilePath);
 0101            if (opfRootDirectory == null)
 102            {
 0103                return new DynamicImageResponse { HasImage = false };
 104            }
 105
 0106            var opfFile = epub.GetEntry(opfFilePath);
 0107            if (opfFile == null)
 108            {
 0109                return new DynamicImageResponse { HasImage = false };
 110            }
 111
 0112            using var opfStream = await opfFile.OpenAsync(cancellationToken).ConfigureAwait(false);
 113
 0114            var opfDocument = new XmlDocument();
 0115            opfDocument.Load(opfStream);
 116
 0117            return await LoadCover(epub, opfDocument, opfRootDirectory, cancellationToken).ConfigureAwait(false);
 0118        }
 119    }
 120}