diff options
Diffstat (limited to 'MediaBrowser.Providers/Books/OpenPackagingFormat/OpfProvider.cs')
| -rw-r--r-- | MediaBrowser.Providers/Books/OpenPackagingFormat/OpfProvider.cs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/MediaBrowser.Providers/Books/OpenPackagingFormat/OpfProvider.cs b/MediaBrowser.Providers/Books/OpenPackagingFormat/OpfProvider.cs new file mode 100644 index 000000000..6e678802c --- /dev/null +++ b/MediaBrowser.Providers/Books/OpenPackagingFormat/OpfProvider.cs @@ -0,0 +1,94 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Providers.Books.OpenPackagingFormat +{ + /// <summary> + /// Provides metadata for book items that have an OPF file in the same directory. Supports the standard + /// content.opf filename, bespoke metadata.opf name from Calibre libraries, and OPF files that have the + /// same name as their respective books for directories with several books. + /// </summary> + public class OpfProvider : ILocalMetadataProvider<Book>, IHasItemChangeMonitor + { + private const string StandardOpfFile = "content.opf"; + private const string CalibreOpfFile = "metadata.opf"; + + private readonly IFileSystem _fileSystem; + + private readonly ILogger<OpfProvider> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="OpfProvider"/> class. + /// </summary> + /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param> + /// <param name="logger">Instance of the <see cref="ILogger{OpfProvider}"/> interface.</param> + public OpfProvider(IFileSystem fileSystem, ILogger<OpfProvider> logger) + { + _fileSystem = fileSystem; + _logger = logger; + } + + /// <inheritdoc /> + public string Name => "Open Packaging Format"; + + /// <inheritdoc /> + public bool HasChanged(BaseItem item, IDirectoryService directoryService) + { + var file = GetXmlFile(item.Path); + + return file.Exists && _fileSystem.GetLastWriteTimeUtc(file) > item.DateLastSaved; + } + + /// <inheritdoc /> + public Task<MetadataResult<Book>> GetMetadata(ItemInfo info, IDirectoryService directoryService, CancellationToken cancellationToken) + { + var path = GetXmlFile(info.Path).FullName; + + try + { + return Task.FromResult(ReadOpfData(path, cancellationToken)); + } + catch (FileNotFoundException) + { + return Task.FromResult(new MetadataResult<Book> { HasMetadata = false }); + } + } + + private FileSystemMetadata GetXmlFile(string path) + { + var fileInfo = _fileSystem.GetFileSystemInfo(path); + var directoryInfo = fileInfo.IsDirectory ? fileInfo : _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(path)!); + + // check for OPF with matching name first since it's the most specific filename + var specificFile = Path.Combine(directoryInfo.FullName, Path.GetFileNameWithoutExtension(path) + ".opf"); + var file = _fileSystem.GetFileInfo(specificFile); + + if (file.Exists) + { + return file; + } + + file = _fileSystem.GetFileInfo(Path.Combine(directoryInfo.FullName, StandardOpfFile)); + + // check metadata.opf last since it's really only used by Calibre + return file.Exists ? file : _fileSystem.GetFileInfo(Path.Combine(directoryInfo.FullName, CalibreOpfFile)); + } + + private MetadataResult<Book> ReadOpfData(string file, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var doc = new XmlDocument(); + doc.Load(file); + + var utilities = new OpfReader<OpfProvider>(doc, _logger); + return utilities.ReadOpfData(cancellationToken); + } + } +} |
