glepub
An EPUB toolkit for the Erlang and JavaScript targets.
glepub is the format layer of an EPUB reader: it opens the container,
parses the package document (OPF), navigation (EPUB 3 nav documents and
EPUB 2 NCX), and exposes a typed Book — metadata, manifest, spine,
table of contents, landmarks, and cover.
Like glexml underneath it, glepub performs no I/O of its own. Opening
a book takes a Loader: a function from a path inside the container to
its bytes. Supply one backed by whatever suits the platform — a zip
library on the server, a JSZip-style reader in the browser, a
directory on disk, or a dictionary in tests.
let assert Ok(book) = glepub.open(loader)
book.metadata.title // -> "Moby-Dick; or, The Whale"
list.map(book.spine, fn(s) { s.item.href })
book.toc // -> nested TocEntry tree
Types
An opened EPUB publication.
pub type Book {
Book(
version: String,
metadata: Metadata,
manifest: List(ManifestItem),
spine: List(SpineItem),
toc: List(TocEntry),
page_list: List(TocEntry),
landmarks: List(TocEntry),
direction: Direction,
rendition: Rendition,
cover: option.Option(ManifestItem),
loader: fn(String) -> Result(BitArray, Nil),
)
}
Constructors
-
Book( version: String, metadata: Metadata, manifest: List(ManifestItem), spine: List(SpineItem), toc: List(TocEntry), page_list: List(TocEntry), landmarks: List(TocEntry), direction: Direction, rendition: Rendition, cover: option.Option(ManifestItem), loader: fn(String) -> Result(BitArray, Nil), )Arguments
- version
-
The package version, e.g.
"3.0"or"2.0". - manifest
-
Every resource the package declares.
- spine
-
The reading order.
- toc
-
The table of contents, from the EPUB 3 nav document or the EPUB 2 NCX, whichever the book provides.
- page_list
-
The page list, if the book provides one.
- landmarks
-
Landmarks (EPUB 3) or the guide (EPUB 2).
- direction
-
Reading direction of the spine.
- cover
-
The cover image, when one is identified.
- loader
-
The loader the book was opened with, used by
resourceanddocument.
pub type Contributor {
Contributor(
name: String,
role: option.Option(String),
file_as: option.Option(String),
)
}
Constructors
-
Contributor( name: String, role: option.Option(String), file_as: option.Option(String), )Arguments
- role
-
A MARC relator code such as
"aut"or"ill", when given. - file_as
-
The name normalised for sorting, when given.
pub type Direction {
LeftToRight
RightToLeft
DefaultDirection
}
Constructors
-
LeftToRight -
RightToLeft -
DefaultDirection
pub type EpubError {
MissingFile(path: String)
InvalidXml(path: String, error: glexml.ParseError)
InvalidPackage(description: String)
}
Constructors
-
MissingFile(path: String)The loader had no file at this path.
-
InvalidXml(path: String, error: glexml.ParseError)A file exists but is not well-formed XML.
-
InvalidPackage(description: String)The container or package is structurally wrong; the description says how.
Reads the bytes of a file inside the container, by its path from the
container root (e.g. "OEBPS/content.opf"). Paths are given
percent-decoded and normalised, with no leading slash.
pub type Loader =
fn(String) -> Result(BitArray, Nil)
pub type ManifestItem {
ManifestItem(
id: String,
href: String,
media_type: String,
properties: List(String),
)
}
Constructors
-
ManifestItem( id: String, href: String, media_type: String, properties: List(String), )Arguments
- href
-
The path within the container, resolved from the package document and percent-decoded, ready to pass to the loader.
pub type Metadata {
Metadata(
identifier: String,
title: String,
language: String,
creators: List(Contributor),
contributors: List(Contributor),
publisher: option.Option(String),
description: option.Option(String),
published: option.Option(String),
modified: option.Option(String),
subjects: List(String),
rights: option.Option(String),
)
}
Constructors
-
Metadata( identifier: String, title: String, language: String, creators: List(Contributor), contributors: List(Contributor), publisher: option.Option(String), description: option.Option(String), published: option.Option(String), modified: option.Option(String), subjects: List(String), rights: option.Option(String), )Arguments
- identifier
-
The package’s unique identifier.
- published
-
The publication date (
dc:date). - modified
-
The last-modified timestamp (
dcterms:modified).
pub type Rendition {
Rendition(
layout: Layout,
orientation: option.Option(String),
spread: option.Option(String),
)
}
Constructors
-
Rendition( layout: Layout, orientation: option.Option(String), spread: option.Option(String), )
pub type SpineItem {
SpineItem(
item: ManifestItem,
linear: Bool,
properties: List(String),
cfi: String,
)
}
Constructors
-
SpineItem( item: ManifestItem, linear: Bool, properties: List(String), cfi: String, )Arguments
- cfi
-
The CFI path to this itemref in the package document, e.g.
/6/4[chap01ref]— the part of anepubcfi(...)locator before the!indirection. Seeglepub/cfi.
Where the display label for a spine document came from. The publication’s
navigation remains authoritative when it names the document; headings and
the document title are explicit fallbacks for sparse EPUB navigation. A
title that names nothing — blank, “Unknown”, “Untitled”, or the book’s own
title, as converters stamp on every file — is reported as Unlabelled
rather than passed off as a label.
pub type SpineLabel {
TocLabel(String)
DocumentHeading(String)
DocumentTitle(String)
Unlabelled
}
Constructors
-
TocLabel(String) -
DocumentHeading(String) -
DocumentTitle(String) -
Unlabelled
A spine item paired with the best navigation label the publication makes
available for it. This is derived navigation; Book.toc always remains the
unmodified EPUB 3 nav or EPUB 2 NCX tree.
pub type SpineNavigationEntry {
SpineNavigationEntry(item: SpineItem, label: SpineLabel)
}
Constructors
-
SpineNavigationEntry(item: SpineItem, label: SpineLabel)
One entry of a table of contents, page list, or landmarks navigation.
pub type TocEntry {
TocEntry(
label: String,
href: option.Option(String),
children: List(TocEntry),
)
}
Constructors
-
TocEntry( label: String, href: option.Option(String), children: List(TocEntry), )Arguments
- href
-
The target as a container path plus optional fragment, resolved relative to the document that declared it. None for entries that are only headings.
Values
pub fn document(
book: Book,
item: ManifestItem,
) -> Result(glexml.Document, EpubError)
Read and parse a manifest item as XML — a content document, for
instance. EPUB 2 XHTML may use the named entities of the XHTML DTD;
supply them with document_with_dtd if you need them.
pub fn document_with_dtd(
book: Book,
item: ManifestItem,
dtd: glexml.Dtd,
) -> Result(glexml.Document, EpubError)
Like document, with extra DTD declarations available — typically the
XHTML entity set for EPUB 2 content documents.
pub fn error_to_string(error: EpubError) -> String
Convert an EpubError into a human readable message.
pub fn is_external(reference: String) -> Bool
Whether a reference in a content document points outside the container.
pub fn item_for_href(
book: Book,
href: String,
) -> Result(ManifestItem, Nil)
Find the manifest item a container path (as produced in TocEntry.href,
fragment ignored) refers to.
pub fn open(
loader: fn(String) -> Result(BitArray, Nil),
) -> Result(Book, EpubError)
Open a publication: read META-INF/container.xml, find the package
document, and parse the package, navigation, and cover information.
pub fn resolve(base: String, reference: String) -> String
Resolve a reference found in the document at directory base to a
container path: percent-decoded, ./.. normalised, fragment kept.
pub fn resource(
book: Book,
item: ManifestItem,
) -> Result(BitArray, EpubError)
Read a manifest item’s bytes from the container.
pub fn spine_navigation(book: Book) -> List(SpineNavigationEntry)
Pair every spine item with its first TOC label, or a label recovered from the content document when the EPUB’s navigation does not include it.
Consumers that need document-granularity reading units can use this instead
of guessing that an unlisted document belongs to the preceding TOC entry.
The spine’s linear flags are preserved on each returned item.
pub fn strip_fragment(href: String) -> String
The container path without any #fragment.