move to pkg

This commit is contained in:
Celogeek 2024-05-11 14:59:21 +02:00
parent 577d51a819
commit 30ac67b06d
Signed by: celogeek
SSH Key Fingerprint: SHA256:njNJLzoLQdbV9PC6ehcruRb0QnEgxABoCYZ+0+aUIYc
43 changed files with 278 additions and 264 deletions

View File

@ -1,72 +0,0 @@
// Package epuboptions Options for EPUB creation.
package epuboptions
import "fmt"
type Crop struct {
Enabled bool
Left, Up, Right, Bottom int
Limit int
SkipIfLimitReached bool
}
type Color struct {
Foreground, Background string
}
type View struct {
Width, Height int
AspectRatio float64
PortraitOnly bool
Color Color
}
type Image struct {
Crop Crop
Quality int
Brightness int
Contrast int
AutoContrast bool
AutoRotate bool
AutoSplitDoublePage bool
KeepDoublePageIfSplit bool
KeepSplitDoublePageAspect bool
NoBlankImage bool
Manga bool
HasCover bool
View View
GrayScale bool
GrayScaleMode int
Resize bool
Format string
AppleBookCompatibility bool
}
type Options struct {
Input string
Output string
Title string
TitlePage int
Author string
LimitMb int
StripFirstDirectoryFromToc bool
Dry bool
DryVerbose bool
SortPathMode int
Quiet bool
Json bool
Workers int
Image Image
}
func (o Options) WorkersRatio(pct int) (nbWorkers int) {
nbWorkers = o.Workers * pct / 100
if nbWorkers < 1 {
nbWorkers = 1
}
return
}
func (o Options) ImgStorage() string {
return fmt.Sprintf("%s.tmp", o.Output)
}

View File

@ -1,21 +0,0 @@
// Package epubtemplates Templates use to create xml files of the EPUB.
package epubtemplates
import _ "embed"
var (
//go:embed "epub_templates_container.xml.tmpl"
Container string
//go:embed "epub_templates_applebooks.xml.tmpl"
AppleBooks string
//go:embed "epub_templates_style.css.tmpl"
Style string
//go:embed "epub_templates_text.xhtml.tmpl"
Text string
//go:embed "epub_templates_blank.xhtml.tmpl"
Blank string
)

View File

@ -18,27 +18,26 @@ import (
"strings" "strings"
"time" "time"
"github.com/celogeek/go-comic-converter/v2/internal/converter/options" "github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
"github.com/celogeek/go-comic-converter/v2/internal/utils"
) )
type Converter struct { type Converter struct {
Options *options.Options Options *Options
Cmd *flag.FlagSet Cmd *flag.FlagSet
order []converterOrder order []order
isZeroValueErrs []error isZeroValueErrs []error
startAt time.Time startAt time.Time
} }
// New Create a new parser // New Create a new parser
func New() *Converter { func New() *Converter {
o := options.New() o := NewOptions()
cmd := flag.NewFlagSet("go-comic-converter", flag.ExitOnError) cmd := flag.NewFlagSet("go-comic-converter", flag.ExitOnError)
conv := &Converter{ conv := &Converter{
Options: o, Options: o,
Cmd: cmd, Cmd: cmd,
order: make([]converterOrder, 0), order: make([]order, 0),
startAt: time.Now(), startAt: time.Now(),
} }
@ -48,9 +47,9 @@ func New() *Converter {
utils.Printf("Usage of %s:\n", filepath.Base(os.Args[0])) utils.Printf("Usage of %s:\n", filepath.Base(os.Args[0]))
for _, o := range conv.order { for _, o := range conv.order {
switch v := o.(type) { switch v := o.(type) {
case converterOrderSection: case orderSection:
utils.Printf("\n%s:\n", o.Value()) utils.Printf("\n%s:\n", o.Value())
case converterOrderName: case orderName:
utils.Println(conv.Usage(v.isString, cmd.Lookup(v.Value()))) utils.Println(conv.Usage(v.isString, cmd.Lookup(v.Value())))
} }
} }
@ -69,31 +68,31 @@ func (c *Converter) LoadConfig() error {
// AddSection Create a new section of config // AddSection Create a new section of config
func (c *Converter) AddSection(section string) { func (c *Converter) AddSection(section string) {
c.order = append(c.order, converterOrderSection{value: section}) c.order = append(c.order, orderSection{value: section})
} }
// AddStringParam Add a string parameter // AddStringParam Add a string parameter
func (c *Converter) AddStringParam(p *string, name string, value string, usage string) { func (c *Converter) AddStringParam(p *string, name string, value string, usage string) {
c.Cmd.StringVar(p, name, value, usage) c.Cmd.StringVar(p, name, value, usage)
c.order = append(c.order, converterOrderName{value: name, isString: true}) c.order = append(c.order, orderName{value: name, isString: true})
} }
// AddIntParam Add an integer parameter // AddIntParam Add an integer parameter
func (c *Converter) AddIntParam(p *int, name string, value int, usage string) { func (c *Converter) AddIntParam(p *int, name string, value int, usage string) {
c.Cmd.IntVar(p, name, value, usage) c.Cmd.IntVar(p, name, value, usage)
c.order = append(c.order, converterOrderName{value: name}) c.order = append(c.order, orderName{value: name})
} }
// AddFloatParam Add an float parameter // AddFloatParam Add an float parameter
func (c *Converter) AddFloatParam(p *float64, name string, value float64, usage string) { func (c *Converter) AddFloatParam(p *float64, name string, value float64, usage string) {
c.Cmd.Float64Var(p, name, value, usage) c.Cmd.Float64Var(p, name, value, usage)
c.order = append(c.order, converterOrderName{value: name}) c.order = append(c.order, orderName{value: name})
} }
// AddBoolParam Add a boolean parameter // AddBoolParam Add a boolean parameter
func (c *Converter) AddBoolParam(p *bool, name string, value bool, usage string) { func (c *Converter) AddBoolParam(p *bool, name string, value bool, usage string) {
c.Cmd.BoolVar(p, name, value, usage) c.Cmd.BoolVar(p, name, value, usage)
c.order = append(c.order, converterOrderName{value: name}) c.order = append(c.order, orderName{value: name})
} }
// InitParse Initialize the parser with all section and parameter. // InitParse Initialize the parser with all section and parameter.

View File

@ -1,5 +1,5 @@
// Package options manage options with default value from config. // Package options manage options with default value from config.
package options package converter
import ( import (
"encoding/json" "encoding/json"
@ -9,8 +9,6 @@ import (
"strings" "strings"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
"github.com/celogeek/go-comic-converter/v2/internal/converter/profiles"
) )
type Options struct { type Options struct {
@ -77,11 +75,11 @@ type Options struct {
Help bool `yaml:"-"` Help bool `yaml:"-"`
// Internal // Internal
profiles profiles.Profiles profiles Profiles
} }
// New Initialize default options. // NewOptions Initialize default options.
func New() *Options { func NewOptions() *Options {
return &Options{ return &Options{
Profile: "SR", Profile: "SR",
Quality: 85, Quality: 85,
@ -100,7 +98,7 @@ func New() *Options {
BackgroundColor: "FFF", BackgroundColor: "FFF",
Format: "jpeg", Format: "jpeg",
TitlePage: 1, TitlePage: 1,
profiles: profiles.New(), profiles: NewProfiles(),
} }
} }
@ -310,7 +308,7 @@ func (o *Options) ShowConfig() string {
// ResetConfig reset all settings to default value // ResetConfig reset all settings to default value
func (o *Options) ResetConfig() error { func (o *Options) ResetConfig() error {
if err := New().SaveConfig(); err != nil { if err := NewOptions().SaveConfig(); err != nil {
return err return err
} }
return o.LoadConfig() return o.LoadConfig()
@ -329,7 +327,7 @@ func (o *Options) SaveConfig() error {
} }
// GetProfile shortcut to get current profile // GetProfile shortcut to get current profile
func (o *Options) GetProfile() *profiles.Profile { func (o *Options) GetProfile() *Profile {
if p, ok := o.profiles[o.Profile]; ok { if p, ok := o.profiles[o.Profile]; ok {
return &p return &p
} }

View File

@ -1,27 +1,27 @@
package converter package converter
// Name or Section // Name or Section
type converterOrder interface { type order interface {
Value() string Value() string
} }
// Section // Section
type converterOrderSection struct { type orderSection struct {
value string value string
} }
func (s converterOrderSection) Value() string { func (s orderSection) Value() string {
return s.value return s.value
} }
// Name // Name
// //
// isString is used to quote the default value. // isString is used to quote the default value.
type converterOrderName struct { type orderName struct {
value string value string
isString bool isString bool
} }
func (s converterOrderName) Value() string { func (s orderName) Value() string {
return s.value return s.value
} }

View File

@ -1,5 +1,5 @@
// Package profiles manage supported profiles for go-comic-converter. // Package profiles manage supported profiles for go-comic-converter.
package profiles package converter
import ( import (
"fmt" "fmt"
@ -15,8 +15,8 @@ type Profile struct {
type Profiles map[string]Profile type Profiles map[string]Profile
// New Initialize list of all supported profiles. // NewProfiles Initialize list of all supported profiles.
func New() Profiles { func NewProfiles() Profiles {
res := make(Profiles) res := make(Profiles)
for _, r := range []Profile{ for _, r := range []Profile{
// High Resolution for Tablet // High Resolution for Tablet

View File

@ -14,18 +14,18 @@ import (
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimage"
epubimageprocessor "github.com/celogeek/go-comic-converter/v2/internal/epub/imageprocessor" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimageprocessor"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubprogress"
epubtemplates "github.com/celogeek/go-comic-converter/v2/internal/epub/templates" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubtemplates"
epubtree "github.com/celogeek/go-comic-converter/v2/internal/epub/tree" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubtree"
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubzip"
"github.com/celogeek/go-comic-converter/v2/internal/utils" "github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
) )
type EPUB struct { type EPUB struct {
epuboptions.Options epuboptions.EPUBOptions
UID string UID string
Publisher string Publisher string
UpdatedAt string UpdatedAt string
@ -35,12 +35,12 @@ type EPUB struct {
} }
type epubPart struct { type epubPart struct {
Cover epubimage.Image Cover epubimage.EPUBImage
Images []epubimage.Image Images []epubimage.EPUBImage
} }
// New initialize EPUB // New initialize EPUB
func New(options epuboptions.Options) EPUB { func New(options epuboptions.EPUBOptions) EPUB {
uid := uuid.Must(uuid.NewV4()) uid := uuid.Must(uuid.NewV4())
tmpl := template.New("parser") tmpl := template.New("parser")
tmpl.Funcs(template.FuncMap{ tmpl.Funcs(template.FuncMap{
@ -49,7 +49,7 @@ func New(options epuboptions.Options) EPUB {
}) })
return EPUB{ return EPUB{
Options: options, EPUBOptions: options,
UID: uid.String(), UID: uid.String(),
Publisher: "GO Comic Converter", Publisher: "GO Comic Converter",
UpdatedAt: time.Now().UTC().Format("2006-01-02T15:04:05Z"), UpdatedAt: time.Now().UTC().Format("2006-01-02T15:04:05Z"),
@ -69,7 +69,7 @@ func (e EPUB) render(templateString string, data map[string]any) string {
} }
// write image to the zip // write image to the zip
func (e EPUB) writeImage(wz epubzip.EPUBZip, img epubimage.Image, zipImg *zip.File) error { func (e EPUB) writeImage(wz epubzip.EPUBZip, img epubimage.EPUBImage, zipImg *zip.File) error {
err := wz.WriteContent( err := wz.WriteContent(
img.EPUBPagePath(), img.EPUBPagePath(),
[]byte(e.render(epubtemplates.Text, map[string]any{ []byte(e.render(epubtemplates.Text, map[string]any{
@ -87,7 +87,7 @@ func (e EPUB) writeImage(wz epubzip.EPUBZip, img epubimage.Image, zipImg *zip.Fi
} }
// write blank page // write blank page
func (e EPUB) writeBlank(wz epubzip.EPUBZip, img epubimage.Image) error { func (e EPUB) writeBlank(wz epubzip.EPUBZip, img epubimage.EPUBImage) error {
return wz.WriteContent( return wz.WriteContent(
img.EPUBSpacePath(), img.EPUBSpacePath(),
[]byte(e.render(epubtemplates.Blank, map[string]any{ []byte(e.render(epubtemplates.Blank, map[string]any{
@ -98,7 +98,7 @@ func (e EPUB) writeBlank(wz epubzip.EPUBZip, img epubimage.Image) error {
} }
// write title image // write title image
func (e EPUB) writeCoverImage(wz epubzip.EPUBZip, img epubimage.Image, part, totalParts int) error { func (e EPUB) writeCoverImage(wz epubzip.EPUBZip, img epubimage.EPUBImage, part, totalParts int) error {
title := "Cover" title := "Cover"
text := "" text := ""
if totalParts > 1 { if totalParts > 1 {
@ -141,7 +141,7 @@ func (e EPUB) writeCoverImage(wz epubzip.EPUBZip, img epubimage.Image, part, tot
} }
// write title image // write title image
func (e EPUB) writeTitleImage(wz epubzip.EPUBZip, img epubimage.Image, title string) error { func (e EPUB) writeTitleImage(wz epubzip.EPUBZip, img epubimage.EPUBImage, title string) error {
titleAlign := "" titleAlign := ""
if !e.Image.View.PortraitOnly { if !e.Image.View.PortraitOnly {
if e.Image.Manga { if e.Image.Manga {
@ -238,7 +238,7 @@ func (e EPUB) getParts() (parts []epubPart, imgStorage epubzip.StorageImageReade
baseSize := uint64(128*1024) + imgStorage.Size(cover.EPUBImgPath())*2 baseSize := uint64(128*1024) + imgStorage.Size(cover.EPUBImgPath())*2
currentSize := baseSize currentSize := baseSize
currentImages := make([]epubimage.Image, 0) currentImages := make([]epubimage.EPUBImage, 0)
part := 1 part := 1
for _, img := range images { for _, img := range images {
@ -250,7 +250,7 @@ func (e EPUB) getParts() (parts []epubPart, imgStorage epubzip.StorageImageReade
}) })
part += 1 part += 1
currentSize = baseSize currentSize = baseSize
currentImages = make([]epubimage.Image, 0) currentImages = make([]epubimage.EPUBImage, 0)
} }
currentSize += imgSize currentSize += imgSize
currentImages = append(currentImages, img) currentImages = append(currentImages, img)
@ -268,7 +268,7 @@ func (e EPUB) getParts() (parts []epubPart, imgStorage epubzip.StorageImageReade
// create a tree from the directories. // create a tree from the directories.
// //
// this is used to simulate the toc. // this is used to simulate the toc.
func (e EPUB) getTree(images []epubimage.Image, skipFiles bool) string { func (e EPUB) getTree(images []epubimage.EPUBImage, skipFiles bool) string {
t := epubtree.New() t := epubtree.New()
for _, img := range images { for _, img := range images {
if skipFiles { if skipFiles {
@ -423,7 +423,7 @@ func (e EPUB) Write() error {
utils.Printf("TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true)) utils.Printf("TOC:\n - %s\n%s\n", e.Title, e.getTree(p.Images, true))
if e.DryVerbose { if e.DryVerbose {
if e.Image.HasCover { if e.Image.HasCover {
utils.Printf("Cover:\n%s\n", e.getTree([]epubimage.Image{p.Cover}, false)) utils.Printf("Cover:\n%s\n", e.getTree([]epubimage.EPUBImage{p.Cover}, false))
} }
utils.Printf("Files:\n%s\n", e.getTree(p.Images, false)) utils.Printf("Files:\n%s\n", e.getTree(p.Images, false))
} }

View File

@ -1,4 +1,4 @@
// Package epubimage Image helpers to transform image. // Package epubimage EPUBImage helpers to transform image.
package epubimage package epubimage
import ( import (
@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
type Image struct { type EPUBImage struct {
Id int Id int
Part int Part int
Raw image.Image Raw image.Image
@ -24,47 +24,47 @@ type Image struct {
} }
// SpaceKey key name of the blank page after the image // SpaceKey key name of the blank page after the image
func (i Image) SpaceKey() string { func (i EPUBImage) SpaceKey() string {
return fmt.Sprintf("space_%d", i.Id) return fmt.Sprintf("space_%d", i.Id)
} }
// SpacePath path of the blank page // SpacePath path of the blank page
func (i Image) SpacePath() string { func (i EPUBImage) SpacePath() string {
return fmt.Sprintf("Text/%s.xhtml", i.SpaceKey()) return fmt.Sprintf("Text/%s.xhtml", i.SpaceKey())
} }
// EPUBSpacePath path of the blank page into the EPUB // EPUBSpacePath path of the blank page into the EPUB
func (i Image) EPUBSpacePath() string { func (i EPUBImage) EPUBSpacePath() string {
return fmt.Sprintf("OEBPS/%s", i.SpacePath()) return fmt.Sprintf("OEBPS/%s", i.SpacePath())
} }
// PageKey key for page // PageKey key for page
func (i Image) PageKey() string { func (i EPUBImage) PageKey() string {
return fmt.Sprintf("page_%d_p%d", i.Id, i.Part) return fmt.Sprintf("page_%d_p%d", i.Id, i.Part)
} }
// PagePath page path linked to the image // PagePath page path linked to the image
func (i Image) PagePath() string { func (i EPUBImage) PagePath() string {
return fmt.Sprintf("Text/%s.xhtml", i.PageKey()) return fmt.Sprintf("Text/%s.xhtml", i.PageKey())
} }
// EPUBPagePath page path into the EPUB // EPUBPagePath page path into the EPUB
func (i Image) EPUBPagePath() string { func (i EPUBImage) EPUBPagePath() string {
return fmt.Sprintf("OEBPS/%s", i.PagePath()) return fmt.Sprintf("OEBPS/%s", i.PagePath())
} }
// ImgKey key for image // ImgKey key for image
func (i Image) ImgKey() string { func (i EPUBImage) ImgKey() string {
return fmt.Sprintf("img_%d_p%d", i.Id, i.Part) return fmt.Sprintf("img_%d_p%d", i.Id, i.Part)
} }
// ImgPath image path // ImgPath image path
func (i Image) ImgPath() string { func (i EPUBImage) ImgPath() string {
return fmt.Sprintf("Images/%s.%s", i.ImgKey(), i.Format) return fmt.Sprintf("Images/%s.%s", i.ImgKey(), i.Format)
} }
// EPUBImgPath image path into the EPUB // EPUBImgPath image path into the EPUB
func (i Image) EPUBImgPath() string { func (i EPUBImage) EPUBImgPath() string {
return fmt.Sprintf("OEBPS/%s", i.ImgPath()) return fmt.Sprintf("OEBPS/%s", i.ImgPath())
} }
@ -72,7 +72,7 @@ func (i Image) EPUBImgPath() string {
// //
// center by default. // center by default.
// align to left or right if it's part of the split double page. // align to left or right if it's part of the split double page.
func (i Image) ImgStyle(viewWidth, viewHeight int, align string) string { func (i EPUBImage) ImgStyle(viewWidth, viewHeight int, align string) string {
relWidth, relHeight := i.RelSize(viewWidth, viewHeight) relWidth, relHeight := i.RelSize(viewWidth, viewHeight)
marginW, marginH := float64(viewWidth-relWidth)/2, float64(viewHeight-relHeight)/2 marginW, marginH := float64(viewWidth-relWidth)/2, float64(viewHeight-relHeight)/2
@ -97,7 +97,7 @@ func (i Image) ImgStyle(viewWidth, viewHeight int, align string) string {
return strings.Join(style, "; ") return strings.Join(style, "; ")
} }
func (i Image) RelSize(viewWidth, viewHeight int) (relWidth, relHeight int) { func (i EPUBImage) RelSize(viewWidth, viewHeight int) (relWidth, relHeight int) {
w, h := viewWidth, viewHeight w, h := viewWidth, viewHeight
srcw, srch := i.Width, i.Height srcw, srch := i.Width, i.Height

View File

@ -27,8 +27,9 @@ import (
pdfimage "github.com/raff/pdfreader/image" pdfimage "github.com/raff/pdfreader/image"
"github.com/raff/pdfreader/pdfread" "github.com/raff/pdfreader/pdfread"
"github.com/celogeek/go-comic-converter/v2/internal/sortpath" "github.com/celogeek/go-comic-converter/v2/internal/pkg/sortpath"
"github.com/celogeek/go-comic-converter/v2/internal/utils"
"github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
) )
type task struct { type task struct {

View File

@ -11,25 +11,25 @@ import (
"github.com/disintegration/gift" "github.com/disintegration/gift"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimage"
epubimagefilters "github.com/celogeek/go-comic-converter/v2/internal/epub/imagefilters" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimagefilters"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
epubprogress "github.com/celogeek/go-comic-converter/v2/internal/epub/progress" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubprogress"
epubzip "github.com/celogeek/go-comic-converter/v2/internal/epub/zip" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubzip"
"github.com/celogeek/go-comic-converter/v2/internal/utils" "github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
) )
type EPUBImageProcessor struct { type EPUBImageProcessor struct {
epuboptions.Options epuboptions.EPUBOptions
} }
func New(o epuboptions.Options) EPUBImageProcessor { func New(o epuboptions.EPUBOptions) EPUBImageProcessor {
return EPUBImageProcessor{o} return EPUBImageProcessor{o}
} }
// Load extract and convert images // Load extract and convert images
func (e EPUBImageProcessor) Load() (images []epubimage.Image, err error) { func (e EPUBImageProcessor) Load() (images []epubimage.EPUBImage, err error) {
images = make([]epubimage.Image, 0) images = make([]epubimage.EPUBImage, 0)
imageCount, imageInput, err := e.load() imageCount, imageInput, err := e.load()
if err != nil { if err != nil {
return nil, err return nil, err
@ -38,7 +38,7 @@ func (e EPUBImageProcessor) Load() (images []epubimage.Image, err error) {
// dry run, skip conversion // dry run, skip conversion
if e.Dry { if e.Dry {
for img := range imageInput { for img := range imageInput {
images = append(images, epubimage.Image{ images = append(images, epubimage.EPUBImage{
Id: img.Id, Id: img.Id,
Path: img.Path, Path: img.Path,
Name: img.Name, Name: img.Name,
@ -49,7 +49,7 @@ func (e EPUBImageProcessor) Load() (images []epubimage.Image, err error) {
return images, nil return images, nil
} }
imageOutput := make(chan epubimage.Image) imageOutput := make(chan epubimage.EPUBImage)
// processing // processing
bar := epubprogress.New(epubprogress.Options{ bar := epubprogress.New(epubprogress.Options{
@ -82,7 +82,7 @@ func (e EPUBImageProcessor) Load() (images []epubimage.Image, err error) {
// do not keep double page if requested // do not keep double page if requested
if !(img.DoublePage && input.Id > 0 && if !(img.DoublePage && input.Id > 0 &&
e.Options.Image.AutoSplitDoublePage && !e.Options.Image.KeepDoublePageIfSplit) { e.EPUBOptions.Image.AutoSplitDoublePage && !e.EPUBOptions.Image.KeepDoublePageIfSplit) {
if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil { if err = imgStorage.Add(img.EPUBImgPath(), img.Raw, e.Image.Quality); err != nil {
_ = bar.Close() _ = bar.Close()
utils.Printf("error with %s: %s", input.Name, err) utils.Printf("error with %s: %s", input.Name, err)
@ -141,7 +141,7 @@ func (e EPUBImageProcessor) Load() (images []epubimage.Image, err error) {
} }
func (e EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw.Image { func (e EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw.Image {
if e.Options.Image.GrayScale { if e.EPUBOptions.Image.GrayScale {
return image.NewGray(r) return image.NewGray(r)
} }
@ -173,7 +173,7 @@ func (e EPUBImageProcessor) createImage(src image.Image, r image.Rectangle) draw
// transform image into 1 or 3 images // transform image into 1 or 3 images
// only doublepage with autosplit has 3 versions // only doublepage with autosplit has 3 versions
func (e EPUBImageProcessor) transformImage(input task, part int, right bool) epubimage.Image { func (e EPUBImageProcessor) transformImage(input task, part int, right bool) epubimage.EPUBImage {
g := gift.New() g := gift.New()
src := input.Image src := input.Image
srcBounds := src.Bounds() srcBounds := src.Bounds()
@ -262,7 +262,7 @@ func (e EPUBImageProcessor) transformImage(input task, part int, right bool) epu
dst := e.createImage(src, g.Bounds(src.Bounds())) dst := e.createImage(src, g.Bounds(src.Bounds()))
g.Draw(dst, src) g.Draw(dst, src)
return epubimage.Image{ return epubimage.EPUBImage{
Id: input.Id, Id: input.Id,
Part: part, Part: part,
Raw: dst, Raw: dst,
@ -312,7 +312,7 @@ func (e EPUBImageProcessor) Cover16LevelOfGray(bounds image.Rectangle) draw.Imag
} }
// CoverTitleData create a title page with the cover // CoverTitleData create a title page with the cover
func (e EPUBImageProcessor) CoverTitleData(o CoverTitleDataOptions) (epubzip.ZipImage, error) { func (e EPUBImageProcessor) CoverTitleData(o CoverTitleDataOptions) (epubzip.Image, error) {
// Create a blur version of the cover // Create a blur version of the cover
g := gift.New(epubimagefilters.CoverTitle(o.Text, o.Align, o.PctWidth, o.PctMargin, o.MaxFontSize, o.BorderSize)) g := gift.New(epubimagefilters.CoverTitle(o.Text, o.Align, o.PctWidth, o.PctMargin, o.MaxFontSize, o.BorderSize))
var dst draw.Image var dst draw.Image

View File

@ -0,0 +1,5 @@
package epuboptions
type Color struct {
Foreground, Background string
}

View File

@ -0,0 +1,8 @@
package epuboptions
type Crop struct {
Enabled bool
Left, Up, Right, Bottom int
Limit int
SkipIfLimitReached bool
}

View File

@ -0,0 +1,33 @@
// Package epuboptions EPUBOptions for EPUB creation.
package epuboptions
import "fmt"
type EPUBOptions struct {
Input string
Output string
Title string
TitlePage int
Author string
LimitMb int
StripFirstDirectoryFromToc bool
Dry bool
DryVerbose bool
SortPathMode int
Quiet bool
Json bool
Workers int
Image Image
}
func (o EPUBOptions) WorkersRatio(pct int) (nbWorkers int) {
nbWorkers = o.Workers * pct / 100
if nbWorkers < 1 {
nbWorkers = 1
}
return
}
func (o EPUBOptions) ImgStorage() string {
return fmt.Sprintf("%s.tmp", o.Output)
}

View File

@ -0,0 +1,22 @@
package epuboptions
type Image struct {
Crop Crop
Quality int
Brightness int
Contrast int
AutoContrast bool
AutoRotate bool
AutoSplitDoublePage bool
KeepDoublePageIfSplit bool
KeepSplitDoublePageAspect bool
NoBlankImage bool
Manga bool
HasCover bool
View View
GrayScale bool
GrayScaleMode int
Resize bool
Format string
AppleBookCompatibility bool
}

View File

@ -0,0 +1,8 @@
package epuboptions
type View struct {
Width, Height int
AspectRatio float64
PortraitOnly bool
Color Color
}

View File

@ -2,13 +2,14 @@
package epubprogress package epubprogress
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"time" "time"
"github.com/schollz/progressbar/v3" "github.com/schollz/progressbar/v3"
"github.com/celogeek/go-comic-converter/v2/internal/utils" "github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
) )
type Options struct { type Options struct {
@ -20,18 +21,21 @@ type Options struct {
TotalJob int TotalJob int
} }
type EpubProgress interface { type EPUBProgress interface {
Add(num int) error Add(num int) error
Close() error Close() error
} }
func New(o Options) EpubProgress { func New(o Options) EPUBProgress {
if o.Quiet { if o.Quiet {
return progressbar.DefaultSilent(int64(o.Max)) return progressbar.DefaultSilent(int64(o.Max))
} }
if o.Json { if o.Json {
return newEpubProgressJson(o) return &jsonprogress{
o: o,
e: json.NewEncoder(os.Stdout),
}
} }
fmtJob := fmt.Sprintf("%%0%dd", len(fmt.Sprint(o.TotalJob))) fmtJob := fmt.Sprintf("%%0%dd", len(fmt.Sprint(o.TotalJob)))

View File

@ -2,28 +2,20 @@ package epubprogress
import ( import (
"encoding/json" "encoding/json"
"os"
) )
type Json struct { type jsonprogress struct {
o Options o Options
e *json.Encoder e *json.Encoder
current int current int
} }
func newEpubProgressJson(o Options) EpubProgress { func (p *jsonprogress) Add(num int) error {
return &Json{
o: o,
e: json.NewEncoder(os.Stdout),
}
}
func (p *Json) Add(num int) error {
p.current += num p.current += num
return p.e.Encode(map[string]any{ return p.e.Encode(map[string]any{
"type": "progress", "type": "epubprogress",
"data": map[string]any{ "data": map[string]any{
"progress": map[string]any{ "epubprogress": map[string]any{
"current": p.current, "current": p.current,
"total": p.o.Max, "total": p.o.Max,
}, },
@ -36,6 +28,6 @@ func (p *Json) Add(num int) error {
}) })
} }
func (p *Json) Close() error { func (p *jsonprogress) Close() error {
return nil return nil
} }

View File

@ -0,0 +1,6 @@
package epubtemplates
import _ "embed"
//go:embed "applebooks.xml.tmpl"
var AppleBooks string

View File

@ -0,0 +1,7 @@
// Package epubtemplates Templates use to create xml files of the EPUB.
package epubtemplates
import _ "embed"
//go:embed "blank.xhtml.tmpl"
var Blank string

View File

@ -0,0 +1,6 @@
package epubtemplates
import _ "embed"
//go:embed "container.xml.tmpl"
var Container string

View File

@ -5,8 +5,8 @@ import (
"github.com/beevik/etree" "github.com/beevik/etree"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimage"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
) )
type Content struct { type Content struct {
@ -17,8 +17,8 @@ type Content struct {
Publisher string Publisher string
UpdatedAt string UpdatedAt string
ImageOptions epuboptions.Image ImageOptions epuboptions.Image
Cover epubimage.Image Cover epubimage.EPUBImage
Images []epubimage.Image Images []epubimage.EPUBImage
Current int Current int
Total int Total int
} }
@ -143,7 +143,7 @@ func (o Content) getMeta() []tag {
func (o Content) getManifest() []tag { func (o Content) getManifest() []tag {
var imageTags, pageTags, spaceTags []tag var imageTags, pageTags, spaceTags []tag
addTag := func(img epubimage.Image, withSpace bool) { addTag := func(img epubimage.EPUBImage, withSpace bool) {
imageTags = append(imageTags, imageTags = append(imageTags,
tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": fmt.Sprintf("image/%s", o.ImageOptions.Format)}, ""}, tag{"item", tagAttrs{"id": img.ImgKey(), "href": img.ImgPath(), "media-type": fmt.Sprintf("image/%s", o.ImageOptions.Format)}, ""},
) )

View File

@ -0,0 +1,6 @@
package epubtemplates
import _ "embed"
//go:embed "style.css.tmpl"
var Style string

View File

@ -0,0 +1,6 @@
package epubtemplates
import _ "embed"
//go:embed "text.xhtml.tmpl"
var Text string

View File

@ -6,13 +6,13 @@ import (
"github.com/beevik/etree" "github.com/beevik/etree"
epubimage "github.com/celogeek/go-comic-converter/v2/internal/epub/image" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epubimage"
) )
// Toc create toc // Toc create toc
// //
//goland:noinspection HttpUrlsUsage //goland:noinspection HttpUrlsUsage
func Toc(title string, hasTitle bool, stripFirstDirectoryFromToc bool, images []epubimage.Image) string { func Toc(title string, hasTitle bool, stripFirstDirectoryFromToc bool, images []epubimage.EPUBImage) string {
doc := etree.NewDocument() doc := etree.NewDocument()
doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`) doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
doc.CreateDirective("DOCTYPE html") doc.CreateDirective("DOCTYPE html")

View File

@ -23,7 +23,7 @@ import (
"strings" "strings"
) )
type Tree struct { type EPUBTree struct {
nodes map[string]*Node nodes map[string]*Node
} }
@ -33,19 +33,19 @@ type Node struct {
} }
// New initialize tree with a root node // New initialize tree with a root node
func New() *Tree { func New() *EPUBTree {
return &Tree{map[string]*Node{ return &EPUBTree{map[string]*Node{
".": {".", []*Node{}}, ".": {".", []*Node{}},
}} }}
} }
// Root root node // Root root node
func (n *Tree) Root() *Node { func (n *EPUBTree) Root() *Node {
return n.nodes["."] return n.nodes["."]
} }
// Add the filename to the tree // Add the filename to the tree
func (n *Tree) Add(filename string) { func (n *EPUBTree) Add(filename string) {
cn := n.Root() cn := n.Root()
cp := "" cp := ""
for _, p := range strings.Split(filepath.Clean(filename), string(filepath.Separator)) { for _, p := range strings.Split(filepath.Clean(filename), string(filepath.Separator)) {

View File

@ -67,7 +67,7 @@ func (e EPUBZip) Copy(fz *zip.File) error {
} }
// WriteRaw Write image. They are already compressed, so we write them down directly. // WriteRaw Write image. They are already compressed, so we write them down directly.
func (e EPUBZip) WriteRaw(raw ZipImage) error { func (e EPUBZip) WriteRaw(raw Image) error {
m, err := e.wz.CreateRaw(raw.Header) m, err := e.wz.CreateRaw(raw.Header)
if err != nil { if err != nil {
return err return err

View File

@ -12,13 +12,13 @@ import (
"time" "time"
) )
type ZipImage struct { type Image struct {
Header *zip.FileHeader Header *zip.FileHeader
Data []byte Data []byte
} }
// CompressImage create gzip encoded jpeg // CompressImage create gzip encoded jpeg
func CompressImage(filename string, format string, img image.Image, quality int) (ZipImage, error) { func CompressImage(filename string, format string, img image.Image, quality int) (Image, error) {
var ( var (
data, cdata bytes.Buffer data, cdata bytes.Buffer
err error err error
@ -33,27 +33,27 @@ func CompressImage(filename string, format string, img image.Image, quality int)
err = fmt.Errorf("unknown format %q", format) err = fmt.Errorf("unknown format %q", format)
} }
if err != nil { if err != nil {
return ZipImage{}, err return Image{}, err
} }
wcdata, err := flate.NewWriter(&cdata, flate.BestCompression) wcdata, err := flate.NewWriter(&cdata, flate.BestCompression)
if err != nil { if err != nil {
return ZipImage{}, err return Image{}, err
} }
_, err = wcdata.Write(data.Bytes()) _, err = wcdata.Write(data.Bytes())
if err != nil { if err != nil {
return ZipImage{}, err return Image{}, err
} }
err = wcdata.Close() err = wcdata.Close()
if err != nil { if err != nil {
return ZipImage{}, err return Image{}, err
} }
t := time.Now() t := time.Now()
//goland:noinspection GoDeprecation //goland:noinspection GoDeprecation
return ZipImage{ return Image{
&zip.FileHeader{ &zip.FileHeader{
Name: filename, Name: filename,
CompressedSize64: uint64(cdata.Len()), CompressedSize64: uint64(cdata.Len()),

View File

@ -2,55 +2,9 @@ package epubzip
import ( import (
"archive/zip" "archive/zip"
"image"
"os" "os"
"sync"
) )
type StorageImageWriter struct {
fh *os.File
fz *zip.Writer
format string
mut *sync.Mutex
}
func NewStorageImageWriter(filename string, format string) (StorageImageWriter, error) {
fh, err := os.Create(filename)
if err != nil {
return StorageImageWriter{}, err
}
fz := zip.NewWriter(fh)
return StorageImageWriter{fh, fz, format, &sync.Mutex{}}, nil
}
func (e StorageImageWriter) Close() error {
if err := e.fz.Close(); err != nil {
_ = e.fh.Close()
return err
}
return e.fh.Close()
}
func (e StorageImageWriter) Add(filename string, img image.Image, quality int) error {
zipImage, err := CompressImage(filename, e.format, img, quality)
if err != nil {
return err
}
e.mut.Lock()
defer e.mut.Unlock()
fh, err := e.fz.CreateRaw(zipImage.Header)
if err != nil {
return err
}
_, err = fh.Write(zipImage.Data)
if err != nil {
return err
}
return nil
}
type StorageImageReader struct { type StorageImageReader struct {
filename string filename string
fh *os.File fh *os.File

View File

@ -0,0 +1,52 @@
package epubzip
import (
"archive/zip"
"image"
"os"
"sync"
)
type StorageImageWriter struct {
fh *os.File
fz *zip.Writer
format string
mut *sync.Mutex
}
func NewStorageImageWriter(filename string, format string) (StorageImageWriter, error) {
fh, err := os.Create(filename)
if err != nil {
return StorageImageWriter{}, err
}
fz := zip.NewWriter(fh)
return StorageImageWriter{fh, fz, format, &sync.Mutex{}}, nil
}
func (e StorageImageWriter) Close() error {
if err := e.fz.Close(); err != nil {
_ = e.fh.Close()
return err
}
return e.fh.Close()
}
func (e StorageImageWriter) Add(filename string, img image.Image, quality int) error {
zipImage, err := CompressImage(filename, e.format, img, quality)
if err != nil {
return err
}
e.mut.Lock()
defer e.mut.Unlock()
fh, err := e.fz.CreateRaw(zipImage.Header)
if err != nil {
return err
}
_, err = fh.Write(zipImage.Data)
if err != nil {
return err
}
return nil
}

10
main.go
View File

@ -14,10 +14,10 @@ import (
"github.com/tcnksm/go-latest" "github.com/tcnksm/go-latest"
"github.com/celogeek/go-comic-converter/v2/internal/converter" "github.com/celogeek/go-comic-converter/v2/internal/pkg/converter"
"github.com/celogeek/go-comic-converter/v2/internal/epub" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epub"
epuboptions "github.com/celogeek/go-comic-converter/v2/internal/epub/options" "github.com/celogeek/go-comic-converter/v2/internal/pkg/epuboptions"
"github.com/celogeek/go-comic-converter/v2/internal/utils" "github.com/celogeek/go-comic-converter/v2/internal/pkg/utils"
) )
func main() { func main() {
@ -110,7 +110,7 @@ $ go install github.com/celogeek/go-comic-converter/v%d@%s
profile := cmd.Options.GetProfile() profile := cmd.Options.GetProfile()
if err := epub.New(epuboptions.Options{ if err := epub.New(epuboptions.EPUBOptions{
Input: cmd.Options.Input, Input: cmd.Options.Input,
Output: cmd.Options.Output, Output: cmd.Options.Output,
LimitMb: cmd.Options.LimitMb, LimitMb: cmd.Options.LimitMb,