Files
wjones af1152b001 Refactor: standardize namespace and using directive style
Refactored all C# test files to use explicit namespace declarations and moved all using directives inside the namespace block for consistency. Updated assembly info and cache files to reflect the new build. Adjusted MvcTestingAppManifest.json to use fully qualified assembly names. No functional changes; all updates are related to code style, organization, and project metadata.
2026-02-20 16:26:53 -05:00

99 lines
3.7 KiB
C#

// <copyright file="OpfProvider.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace MediaBrowser.Providers.Books.OpenPackagingFormat
{
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;
/// <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);
}
}
}