From a24bf0cfc8afc55f01bc961f7b8166ea6f8cf50f Mon Sep 17 00:00:00 2001 From: celogeek <65178+celogeek@users.noreply.github.com> Date: Fri, 7 Apr 2023 18:23:53 +0200 Subject: [PATCH 1/5] fill nav files to get toc --- internal/epub/core.go | 49 ++++++++++++++++++++++++-- internal/epub/image_processing.go | 15 ++++++++ internal/epub/templates/nav.xhtml.tmpl | 14 ++++---- internal/epub/templates/toc.ncx.tmpl | 4 +-- internal/epub/toc.go | 20 +++++++++++ 5 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 internal/epub/toc.go diff --git a/internal/epub/core.go b/internal/epub/core.go index bcb1582..bc17265 100644 --- a/internal/epub/core.go +++ b/internal/epub/core.go @@ -1,6 +1,7 @@ package epub import ( + "encoding/xml" "fmt" "image/color" "path/filepath" @@ -92,6 +93,7 @@ func (e *ePub) render(templateString string, data any) string { func (e *ePub) getParts() ([]*epubPart, error) { images, err := LoadImages(e.Input, e.ImageOptions) + if err != nil { return nil, err } @@ -139,6 +141,37 @@ func (e *ePub) getParts() ([]*epubPart, error) { return parts, nil } +func (e *ePub) getToc(title string, images []*Image) ([]byte, error) { + paths := map[string]*TocPart{ + ".": {}, + } + for _, img := range images { + currentPath := "." + for _, path := range strings.Split(img.Path, string(filepath.Separator)) { + parentPath := currentPath + currentPath = filepath.Join(currentPath, path) + if _, ok := paths[currentPath]; ok { + continue + } + part := &TocPart{ + Title: TocTitle{ + Value: path, + Link: fmt.Sprintf("Text/%d_p%d.xhtml", img.Id, img.Part), + }, + } + paths[currentPath] = part + if paths[parentPath].Children == nil { + paths[parentPath].Children = &TocChildren{} + } + paths[parentPath].Children.Tags = append(paths[parentPath].Children.Tags, part) + } + } + if paths["."].Children == nil { + return []byte{}, nil + } + return xml.MarshalIndent(paths["."].Children.Tags, " ", " ") +} + func (e *ePub) Write() error { type zipContent struct { Name string @@ -170,6 +203,11 @@ func (e *ePub) Write() error { if totalParts > 1 { title = fmt.Sprintf("%s [%d/%d]", title, i+1, totalParts) } + toc, err := e.getToc(title, part.Images) + if err != nil { + return err + } + content := []zipContent{ {"META-INF/container.xml", containerTmpl}, {"OEBPS/content.opf", e.render(contentTmpl, map[string]any{ @@ -180,8 +218,15 @@ func (e *ePub) Write() error { "Part": i + 1, "Total": totalParts, })}, - {"OEBPS/toc.ncx", e.render(tocTmpl, map[string]any{"Info": e})}, - {"OEBPS/nav.xhtml", e.render(navTmpl, map[string]any{"Info": e})}, + {"OEBPS/toc.ncx", e.render(tocTmpl, map[string]any{ + "Info": e, + "Title": title, + })}, + {"OEBPS/nav.xhtml", e.render(navTmpl, map[string]any{ + "Title": title, + "TOC": string(toc), + "Last": part.Images[len(part.Images)-1], + })}, {"OEBPS/Text/style.css", styleTmpl}, {"OEBPS/Text/part.xhtml", e.render(partTmpl, map[string]any{ "Info": e, diff --git a/internal/epub/image_processing.go b/internal/epub/image_processing.go index 6a60e51..b723efb 100644 --- a/internal/epub/image_processing.go +++ b/internal/epub/image_processing.go @@ -31,11 +31,13 @@ type Image struct { Height int IsCover bool NeedSpace bool + Path string } type imageTask struct { Id int Reader io.ReadCloser + Path string Filename string } @@ -162,6 +164,7 @@ func LoadImages(path string, options *ImageOptions) ([]*Image, error) { dst.Bounds().Dy(), img.Id == 0, false, + img.Path, } // Auto split double page @@ -185,6 +188,7 @@ func LoadImages(path string, options *ImageOptions) ([]*Image, error) { dst.Bounds().Dy(), false, false, // NeedSpace reajust during parts computation + img.Path, } } } @@ -235,6 +239,7 @@ func isSupportedImage(path string) bool { func loadDir(input string) (int, chan *imageTask, error) { images := make([]string, 0) + input = filepath.Clean(input) err := filepath.WalkDir(input, func(path string, d fs.DirEntry, err error) error { if err != nil { return err @@ -263,9 +268,16 @@ func loadDir(input string) (int, chan *imageTask, error) { fmt.Fprintln(os.Stderr, err) os.Exit(1) } + p := filepath.Dir(img) + if p == input { + p = "" + } else { + p = p[len(input)+1:] + } output <- &imageTask{ Id: i, Reader: f, + Path: p, Filename: img, } } @@ -306,6 +318,7 @@ func loadCbz(input string) (int, chan *imageTask, error) { output <- &imageTask{ Id: i, Reader: f, + Path: filepath.Dir(filepath.Clean(img.Name)), Filename: img.Name, } } @@ -374,6 +387,7 @@ func loadCbr(input string) (int, chan *imageTask, error) { output <- &imageTask{ Id: idx, Reader: io.NopCloser(b), + Path: filepath.Dir(filepath.Clean(f.Name)), Filename: f.Name, } } @@ -409,6 +423,7 @@ func loadPdf(input string) (int, chan *imageTask, error) { output <- &imageTask{ Id: i, Reader: io.NopCloser(b), + Path: "/", Filename: fmt.Sprintf("page %d", i+1), } } diff --git a/internal/epub/templates/nav.xhtml.tmpl b/internal/epub/templates/nav.xhtml.tmpl index 0492d4f..322ce44 100644 --- a/internal/epub/templates/nav.xhtml.tmpl +++ b/internal/epub/templates/nav.xhtml.tmpl @@ -2,18 +2,16 @@ - {{ .Info.Title }} + {{ .Title }} -