Skip to content

[Feature] Enhance EPUB OPF parser to support Calibre 9.x metadata formats #341

Description

@jadehawk

What's your idea?

Extend server/src/modules/metadata/lib/opf-parser.ts to recognize three additional Calibre-specific metadata encodings that are standard output from Calibre 9.x when EPUBs are exported or modified:

1. Calibre prefix:value identifiers in <dc:identifier>

Calibre 9.x writes provider IDs directly into <dc:identifier> elements using a prefix:value format instead of the opf:scheme attribute or urn: URN prefix already supported by the parser:

<dc:identifier>amazon:B0G3YRNY6Y</dc:identifier>
<dc:identifier>goodreads:244564568</dc:identifier>
<dc:identifier>google:ABCD1234</dc:identifier>
<dc:identifier>openlibrary:OL99999999W</dc:identifier>
<dc:identifier>hardcover:test-book-slug</dc:identifier>
<dc:identifier>kobo:test-kobo-id</dc:identifier>
<dc:identifier>itunes:987654321</dc:identifier>
<dc:identifier>lubimyczytac:lub-99999</dc:identifier>
<dc:identifier>ranobedb:ranobe-999</dc:identifier>
<dc:identifier>asin:B0G3YRNY6Y</dc:identifier>

Currently these are silently ignored by the parser. They should be recognized as fallbacks when opf:scheme and urn: formats are absent.

2. calibre:user_metadata JSON blob for page count

Calibre stores user-defined custom column values in a <meta property="calibre:user_metadata"> JSON blob. Two common column names users create for page count are #pagecount and #page_count. Both should be recognized:

<meta property="calibre:user_metadata">{"#pagecount":{"#value#":353}}</meta>
<!-- or -->
<meta property="calibre:user_metadata">{"#page_count":{"#value#":400}}</meta>

3. calibre:user_metadata JSON blob for subtitle

The same JSON blob can carry a subtitle under a #subtitle key:

<meta property="calibre:user_metadata">{"#subtitle":{"#value#":"A Subtitle"}}</meta>

In all three cases, these Calibre-specific values should only fill fields that are still null after the standard parsing passes (opf:schemeurn: → Calibre fallback), preserving full backward compatibility.

What problem does it solve?

Users who manage their book library with Calibre 9.x (the current stable release) and import EPUBs into BookOrbit lose all (Except ISBN) provider identifier metadata silently. Calibre writes identifiers in prefix:value format as its default output — not opf:scheme or urn: format — so Amazon IDs, Goodreads IDs, Google Books IDs, and others are all dropped on import.

Similarly, Calibre users who track page count and subtitle via Calibre custom columns (#pagecount, #page_count, #subtitle) see those fields arrive as null in BookOrbit, even though the data is present in the EPUB file.

This affects any self-hosted user who uses Calibre as their primary library management tool before migrating to or alongside BookOrbit.

Anything else? (optional)

Priority order of parsing (no regressions): Existing opf:scheme and urn: formats retain highest priority. The Calibre fallbacks only activate when those fields are still null.

Implementation approach (no new dependencies required): All three additions work within the existing fast-xml-parser + pure TypeScript parsing already in opf-parser.ts. No new packages needed.

Test coverage: A reference implementation has been locally validated with 23 new unit tests (14 for prefix:value identifiers, 9 for user_metadata JSON) alongside all 63 existing tests passing — 86 total.

Calibre version confirmed: Calibre 9.9 (current stable at time of writing).

Sample real-world OPF snippet from Calibre 9.9:

<dc:identifier>amazon:B0G3YRNY6Y</dc:identifier>
<dc:identifier>goodreads:244564568</dc:identifier>
<meta property="calibre:user_metadata">{"#pagecount":{"#value#":353},"#subtitle":{"#value#":"TEST-SUBTITLE"}}</meta>

Also a docker image based on 1.10.0 with proposed enhancement is available here:

docker pull jadehawk/jh-bookorbit:1.10.0-calibre-meta

Want to help?

Yes, I'd like to implement this

Before submitting

  • I've searched existing issues and this hasn't been requested yet.

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature request or capability proposal.releasedIssue or PR is included in a released version.status:approvedApproved by maintainers; ready for contribution

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions