mirror of
https://github.com/celogeek/go-comic-converter.git
synced 2025-06-29 00:29:55 +02:00
move to pkg
This commit is contained in:
parent
577d51a819
commit
30ac67b06d
@ -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)
|
|
||||||
}
|
|
@ -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
|
|
||||||
)
|
|
@ -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.
|
@ -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
|
||||||
}
|
}
|
@ -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
|
||||||
}
|
}
|
@ -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
|
@ -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))
|
||||||
}
|
}
|
@ -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
|
||||||
|
|
@ -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 {
|
@ -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
|
5
internal/pkg/epuboptions/color.go
Normal file
5
internal/pkg/epuboptions/color.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package epuboptions
|
||||||
|
|
||||||
|
type Color struct {
|
||||||
|
Foreground, Background string
|
||||||
|
}
|
8
internal/pkg/epuboptions/crop.go
Normal file
8
internal/pkg/epuboptions/crop.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package epuboptions
|
||||||
|
|
||||||
|
type Crop struct {
|
||||||
|
Enabled bool
|
||||||
|
Left, Up, Right, Bottom int
|
||||||
|
Limit int
|
||||||
|
SkipIfLimitReached bool
|
||||||
|
}
|
33
internal/pkg/epuboptions/epub_options.go
Normal file
33
internal/pkg/epuboptions/epub_options.go
Normal 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)
|
||||||
|
}
|
22
internal/pkg/epuboptions/image.go
Normal file
22
internal/pkg/epuboptions/image.go
Normal 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
|
||||||
|
}
|
8
internal/pkg/epuboptions/view.go
Normal file
8
internal/pkg/epuboptions/view.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package epuboptions
|
||||||
|
|
||||||
|
type View struct {
|
||||||
|
Width, Height int
|
||||||
|
AspectRatio float64
|
||||||
|
PortraitOnly bool
|
||||||
|
Color Color
|
||||||
|
}
|
@ -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)))
|
@ -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
|
||||||
}
|
}
|
6
internal/pkg/epubtemplates/applebooks.go
Normal file
6
internal/pkg/epubtemplates/applebooks.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package epubtemplates
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed "applebooks.xml.tmpl"
|
||||||
|
var AppleBooks string
|
7
internal/pkg/epubtemplates/blank.go
Normal file
7
internal/pkg/epubtemplates/blank.go
Normal 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
|
6
internal/pkg/epubtemplates/container.go
Normal file
6
internal/pkg/epubtemplates/container.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package epubtemplates
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed "container.xml.tmpl"
|
||||||
|
var Container string
|
@ -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)}, ""},
|
||||||
)
|
)
|
6
internal/pkg/epubtemplates/style.go
Normal file
6
internal/pkg/epubtemplates/style.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package epubtemplates
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed "style.css.tmpl"
|
||||||
|
var Style string
|
6
internal/pkg/epubtemplates/text.go
Normal file
6
internal/pkg/epubtemplates/text.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package epubtemplates
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed "text.xhtml.tmpl"
|
||||||
|
var Text string
|
@ -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")
|
@ -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)) {
|
@ -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
|
@ -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()),
|
@ -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
|
52
internal/pkg/epubzip/storage_image_writer.go
Normal file
52
internal/pkg/epubzip/storage_image_writer.go
Normal 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
10
main.go
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user