< Summary - Jellyfin

Information
Class: MediaBrowser.Providers.Books.ComicInfo.ExternalComicInfoProvider
Assembly: MediaBrowser.Providers
File(s): /srv/git/jellyfin/MediaBrowser.Providers/Books/ComicInfo/ExternalComicInfoProvider.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 31
Coverable lines: 31
Total lines: 99
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 12
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 6/11/2026 - 12:16:04 AM Line coverage: 0% (0/31) Branch coverage: 0% (0/12) Total lines: 99 6/11/2026 - 12:16:04 AM Line coverage: 0% (0/31) Branch coverage: 0% (0/12) Total lines: 99

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
ReadMetadata()0%2040%
HasItemChanged(...)0%620%
LoadXml()0%620%
GetXmlFilePath(...)0%2040%

File(s)

/srv/git/jellyfin/MediaBrowser.Providers/Books/ComicInfo/ExternalComicInfoProvider.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Threading;
 4using System.Threading.Tasks;
 5using System.Xml;
 6using System.Xml.Linq;
 7using MediaBrowser.Controller.Entities;
 8using MediaBrowser.Controller.Providers;
 9using MediaBrowser.Model.IO;
 10using Microsoft.Extensions.Logging;
 11
 12namespace MediaBrowser.Providers.Books.ComicInfo;
 13
 14/// <summary>
 15/// Handles metadata for comics which is saved as an XML document. This XML document is not part
 16/// of the comic itself but an external file.
 17/// </summary>
 18public class ExternalComicInfoProvider : IComicProvider
 19{
 20    private readonly IFileSystem _fileSystem;
 21    private readonly ILogger<ExternalComicInfoProvider> _logger;
 22
 23    /// <summary>
 24    /// Initializes a new instance of the <see cref="ExternalComicInfoProvider"/> class.
 25    /// </summary>
 26    /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
 27    /// <param name="logger">Instance of the <see cref="ILogger{ExternalComicInfoProvider}"/> interface.</param>
 28    public ExternalComicInfoProvider(IFileSystem fileSystem, ILogger<ExternalComicInfoProvider> logger)
 29    {
 030        _logger = logger;
 031        _fileSystem = fileSystem;
 032    }
 33
 34    /// <inheritdoc />
 35    public async ValueTask<MetadataResult<Book>> ReadMetadata(ItemInfo info, IDirectoryService directoryService, Cancell
 36    {
 037        var comicInfoXml = await LoadXml(info, cancellationToken).ConfigureAwait(false);
 38
 039        if (comicInfoXml is null)
 40        {
 041            _logger.LogInformation("Could not load ComicInfo metadata for {Path} from XML file.", info.Path);
 042            return new MetadataResult<Book> { HasMetadata = false };
 43        }
 44
 045        var book = ComicInfoReader.ReadComicBookMetadata(comicInfoXml);
 46
 047        if (book is null)
 48        {
 049            return new MetadataResult<Book> { HasMetadata = false };
 50        }
 51
 052        var metadataResult = new MetadataResult<Book> { Item = book, HasMetadata = true };
 53
 054        ComicInfoReader.ReadPeopleMetadata(comicInfoXml, metadataResult);
 055        ComicInfoReader.ReadCultureInfoInto(comicInfoXml, "ComicInfo/LanguageISO", cultureInfo => metadataResult.ResultL
 56
 057        return metadataResult;
 058    }
 59
 60    /// <inheritdoc />
 61    public bool HasItemChanged(BaseItem item)
 62    {
 063        var file = GetXmlFilePath(item.Path);
 64
 065        return file.Exists && _fileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved;
 66    }
 67
 68    private async Task<XDocument?> LoadXml(ItemInfo info, CancellationToken cancellationToken)
 69    {
 070        var path = GetXmlFilePath(info.Path).FullName;
 71
 072        if (path is null)
 73        {
 074            return null;
 75        }
 76
 77        try
 78        {
 079            using var reader = XmlReader.Create(path, new XmlReaderSettings { Async = true });
 080            var comicInfoXml = XDocument.LoadAsync(reader, LoadOptions.None, cancellationToken);
 81
 082            return await comicInfoXml.ConfigureAwait(false);
 83        }
 084        catch (Exception e)
 85        {
 086            _logger.LogInformation(e, "Could not load external XML from {Path}. This could mean there is no separate Com
 087            return null;
 88        }
 089    }
 90
 91    private FileSystemMetadata GetXmlFilePath(string path)
 92    {
 093        var fileInfo = _fileSystem.GetFileSystemInfo(path);
 094        var directoryInfo = fileInfo.IsDirectory ? fileInfo : _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(path)!)
 095        var file = _fileSystem.GetFileInfo(Path.Combine(directoryInfo.FullName, Path.GetFileNameWithoutExtension(path) +
 96
 097        return file.Exists ? file : _fileSystem.GetFileInfo(Path.Combine(directoryInfo.FullName, ComicInfoReader.ComicRa
 98    }
 99}