go-epub
| Language | Go |
|---|---|
| License | MIT |
| Repository | github.com/go-shiori/go-epub |
| Documentation | pkg.go.dev/github.com/go-shiori/go-epub |
| Depends on | Go standard library, a few small modules |
| Read / write | no / yes (EPUB 3.0 with an EPUB 2 NCX) |
go-epub builds EPUB files from HTML fragments. You add sections (chapters) as XHTML body content, plus CSS, images, fonts, audio and video from local files or URLs; the library writes the package document, the EPUB 3 navigation document, an EPUB 2 toc.ncx for older readers, and zips everything with mimetype first. Its test suite runs EPUBCheck, so the output is valid EPUB 3.
It’s a maintained fork of bmaupin/go-epub, used by the Shiori bookmark manager to save web pages as e-books. It only creates books: to read EPUB files in Go, use goreader/epub.
Installation#
go get github.com/go-shiori/go-epub
Basic usage: create an EPUB#
package main
import (
"log"
epub "github.com/go-shiori/go-epub"
)
func main() {
e, err := epub.NewEpub("My Book")
if err != nil {
log.Fatal(err)
}
e.SetAuthor("Jane Doe")
e.SetLang("en")
e.SetDescription("A short example book")
_, err = e.AddSection("<h1>Chapter 1</h1><p>First chapter.</p>", "Chapter 1", "", "")
if err != nil {
log.Fatal(err)
}
_, err = e.AddSection("<h1>Chapter 2</h1><p>Second chapter.</p>", "Chapter 2", "", "")
if err != nil {
log.Fatal(err)
}
if err := e.Write("book.epub"); err != nil {
log.Fatal(err)
}
}
AddSection(body, title, internalFilename, internalCSSPath) returns the internal file name of the section. Leave the file name empty to get a generated one.
How to add a cover image#
imgPath, err := e.AddImage("cover.jpg", "cover.jpg") // local path or URL, internal name
if err != nil {
log.Fatal(err)
}
// second argument: CSS for the cover page; "" uses the default
if err := e.SetCover(imgPath, ""); err != nil {
log.Fatal(err)
}
How to add images and CSS to chapters#
AddImage and AddCSS return paths relative to the sections, ready to use in HTML:
cssPath, err := e.AddCSS("book.css", "book.css")
if err != nil {
log.Fatal(err)
}
imgPath, err := e.AddImage("https://example.com/photo.png", "photo.png")
if err != nil {
log.Fatal(err)
}
body := `<h1>Photos</h1><p><img src="` + imgPath + `" alt="photo"/></p>`
if _, err := e.AddSection(body, "Photos", "photos.xhtml", cssPath); err != nil {
log.Fatal(err)
}
How to create nested chapters#
parent, err := e.AddSection("<h1>Part 1</h1>", "Part 1", "part1.xhtml", "")
if err != nil {
log.Fatal(err)
}
_, err = e.AddSubSection(parent, "<h2>Chapter 1</h2><p>Text.</p>", "Chapter 1", "", "")
if err != nil {
log.Fatal(err)
}
Subsections appear nested in the table of contents.
How to write the EPUB to an HTTP response#
WriteTo writes to any io.Writer:
func handler(w http.ResponseWriter, r *http.Request) {
e, _ := epub.NewEpub("Generated")
e.AddSection("<p>Hello</p>", "Hello", "", "")
w.Header().Set("Content-Type", "application/epub+zip")
w.Header().Set("Content-Disposition", `attachment; filename="book.epub"`)
if _, err := e.WriteTo(w); err != nil {
log.Println(err)
}
}
Tips#
- Section bodies are inserted into an XHTML template: they must be well-formed XML (closed tags,
&). SetIdentifiersets the book’s unique identifier; by default a random UUID is used.SetPpd("rtl")sets right-to-left page progression for Arabic, Hebrew or Japanese books.