aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordkanada <dkanada@users.noreply.github.com>2026-07-12 19:46:56 +0900
committerdkanada <dkanada@users.noreply.github.com>2026-07-12 19:46:56 +0900
commit9e996d612c3ee6779db8802a4c3eb3bcd09fe9c9 (patch)
treeda214966f0dad46e6e05f69378a6761c72d6daf6
parent53aafcd38e1f4558ff18f5258d0d46b3a0565783 (diff)
extract page count from archives and PDFs
-rw-r--r--Directory.Packages.props1
-rw-r--r--MediaBrowser.Controller/Entities/Book.cs5
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs2
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj1
-rw-r--r--MediaBrowser.Providers/MediaInfo/ProbeProvider.cs54
5 files changed, 57 insertions, 6 deletions
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f0a655d488..17add2f9c9 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -53,6 +53,7 @@
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="NEbml" Version="1.1.0.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
+ <PackageVersion Include="PDFtoImage" Version="5.2.1" />
<PackageVersion Include="PlaylistsNET" Version="1.4.1" />
<PackageVersion Include="prometheus-net.AspNetCore" Version="8.2.1" />
<PackageVersion Include="prometheus-net.DotNetRuntime" Version="4.4.1" />
diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs
index 5187669373..8559681bdc 100644
--- a/MediaBrowser.Controller/Entities/Book.cs
+++ b/MediaBrowser.Controller/Entities/Book.cs
@@ -13,11 +13,6 @@ namespace MediaBrowser.Controller.Entities
[Common.RequiresSourceSerialisation]
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
- public Book()
- {
- this.RunTimeTicks = TimeSpan.TicksPerSecond;
- }
-
[JsonIgnore]
public override MediaType MediaType => MediaType.Book;
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index 118ccf8679..62827c07b9 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -1116,7 +1116,7 @@ namespace MediaBrowser.Providers.Manager
{
if (replaceData || !target.RunTimeTicks.HasValue)
{
- if (target is not Audio && target is not Video)
+ if (target is not Audio && target is not Video && target is not Book)
{
target.RunTimeTicks = source.RunTimeTicks;
}
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index df51dd8421..2b0f480b1c 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -21,6 +21,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Newtonsoft.Json" />
+ <PackageReference Include="PDFtoImage" />
<PackageReference Include="PlaylistsNET" />
<PackageReference Include="SharpCompress" />
<PackageReference Include="z440.atl.core" />
diff --git a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
index 789df8f061..221c6bff5e 100644
--- a/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/ProbeProvider.cs
@@ -24,6 +24,8 @@ using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
+using PDFtoImage;
+using SharpCompress.Archives;
namespace MediaBrowser.Providers.MediaInfo
{
@@ -37,6 +39,7 @@ namespace MediaBrowser.Providers.MediaInfo
ICustomMetadataProvider<Video>,
ICustomMetadataProvider<Audio>,
ICustomMetadataProvider<AudioBook>,
+ ICustomMetadataProvider<Book>,
IHasOrder,
IForcedProvider,
IPreRefreshProvider,
@@ -214,6 +217,57 @@ namespace MediaBrowser.Providers.MediaInfo
return FetchAudioInfo(item, options, cancellationToken);
}
+ /// <inheritdoc />
+ public Task<ItemUpdateType> FetchAsync(Book item, MetadataRefreshOptions options, CancellationToken cancellationToken)
+ {
+ if (item.IsVirtualItem || !item.IsFileProtocol)
+ {
+ return _cachedTask;
+ }
+
+ long pageCount;
+ switch (Path.GetExtension(item.Path).ToLowerInvariant())
+ {
+ case ".cb7":
+ case ".cbr":
+ case ".cbt":
+ case ".cbz":
+ using (var stream = File.OpenRead(item.Path))
+ using (var archive = ArchiveFactory.OpenArchive(stream))
+ {
+ pageCount = archive.Entries.Count(e => !e.IsDirectory);
+ }
+
+ break;
+
+#pragma warning disable CA1416
+ case ".pdf":
+ using (var stream = File.OpenRead(item.Path))
+ {
+ pageCount = Conversion.GetPageCount(stream);
+ }
+
+ break;
+#pragma warning restore CA1416
+
+ case ".epub":
+ // TODO process CFI and store as a string when multiple progress types are supported
+ // current progress value is percentage stored as a proportion of one second worth of ticks
+ item.RunTimeTicks = TimeSpan.TicksPerSecond;
+
+ return Task.FromResult(ItemUpdateType.MetadataImport);
+
+ default:
+ return _cachedTask;
+ }
+
+ // TODO use page count without modification when multiple progress types are supported
+ // book players report page count and the web client multiplies that value by 10000 to convert the expected milliseconds into ticks
+ item.RunTimeTicks = pageCount * 10000;
+
+ return Task.FromResult(ItemUpdateType.MetadataImport);
+ }
+
/// <summary>
/// Fetches video information for an item.
/// </summary>