mobi (Go)
| Language | Go |
|---|---|
| License | MIT |
| Repository | github.com/leotaku/mobi |
| Documentation | pkg.go.dev/github.com/leotaku/mobi |
| Depends on | golang.org/x/text |
| Read / write | no / yes (KF8 / AZW3) |
leotaku/mobi builds Kindle books in pure Go, without KindleGen or Calibre. You describe a mobi.Book (title, authors, language, chapters of HTML, CSS, images, cover) and call Realize(), which returns a Palm database (pdb.Database) that you write to a .azw3 file. The output is KF8 only: it opens on Kindle devices and apps that support KF8, but not on the Kindle 1, Kindle 2 and Kindle DX.
The package also exports its building blocks: pdb (Palm database reader and writer), records (PalmDOC, MOBI, EXTH, index and image records) and jfif, so you can implement other PalmDB-based formats. Known limits: chapters can’t have subchapters, and a book without any text is malformed.
Installation#
go get github.com/leotaku/mobi
Basic usage: create an AZW3 book#
package main
import (
"log"
"math/rand"
"os"
"time"
"github.com/leotaku/mobi"
"golang.org/x/text/language"
)
func main() {
book := mobi.Book{
Title: "My Book",
Authors: []string{"Jane Doe"},
Language: language.English,
CreatedDate: time.Now(),
UniqueID: rand.Uint32(),
Chapters: []mobi.Chapter{
{Title: "Chapter 1", Chunks: mobi.Chunks("<h1>Chapter 1</h1><p>First chapter.</p>")},
{Title: "Chapter 2", Chunks: mobi.Chunks("<h1>Chapter 2</h1><p>Second chapter.</p>")},
},
}
db := book.Realize()
f, err := os.Create("book.azw3")
if err != nil {
log.Fatal(err)
}
defer f.Close()
if err := db.Write(f); err != nil {
log.Fatal(err)
}
}
Each chapter becomes an entry in the Kindle’s table of contents. mobi.Chunks takes one or more HTML strings; long chapters can be split into several chunks.
How to add a cover image#
CoverImage takes any image.Image; it’s stored as JPEG and marked as the cover in the EXTH header:
import (
"image"
_ "image/jpeg"
_ "image/png"
)
f, err := os.Open("cover.jpg")
if err != nil {
log.Fatal(err)
}
cover, _, err := image.Decode(f)
f.Close()
if err != nil {
log.Fatal(err)
}
book.CoverImage = cover
book.ThumbImage = cover // small thumbnail for the library view
How to add images to chapters#
Images in Book.Images are referenced as kindle:embed:XXXX, where XXXX is the 1-based index in base 32, padded to 4 digits:
book.Images = []image.Image{photo} // first image: kindle:embed:0001
book.Chapters = append(book.Chapters, mobi.Chapter{
Title: "Photos",
Chunks: mobi.Chunks(`<p><img src="kindle:embed:0001?mime=image/jpeg"/></p>`),
})
How to add CSS#
book.CSSFlows = []string{"body { font-family: serif; } h1 { text-align: center; }"}
The default page template links every CSS flow from each chapter.
How to show the cover on a Kindle for sideloaded books#
Newer Kindles download covers from Amazon and ignore the embedded thumbnail of sideloaded books. Copy a JPEG to the Kindle’s thumbnails folder with the name the library expects:
name := book.GetThumbFilename() // thumbnail_<ASIN>_EBOK_portrait.jpg
// copy the cover JPEG to <Kindle>/system/thumbnails/<name>
Tips#
book.FixedLayout = truecreates a fixed-layout book (comics),RightToLeftandVerticalset page direction and vertical text.- Chapter HTML goes into an XHTML template: it must be well-formed XML. Override the template with
book.OverrideTemplate(tpl). pdb.ReadDatabasereads the records of any Palm database file, which helps when debugging the output.