package main import ( "flag" "fmt" "image/color" "os" "path/filepath" "runtime" "strings" "github.com/celogeek/go-comic-converter/internal/epub" ) type Profile struct { Code string Description string Width int Height int Palette color.Palette } var Profiles = []Profile{ // Kindle {"K1", "Kindle 1", 600, 670, epub.PALETTE_4}, {"K11", "Kindle 11", 1072, 1448, epub.PALETTE_16}, {"K2", "Kindle 2", 600, 670, epub.PALETTE_15}, {"K34", "Kindle Keyboard/Touch", 600, 800, epub.PALETTE_16}, {"K578", "Kindle", 600, 800, epub.PALETTE_16}, {"KDX", "Kindle DX/DXG", 824, 1000, epub.PALETTE_16}, {"KPW", "Kindle Paperwhite 1/2", 758, 1024, epub.PALETTE_16}, {"KV", "Kindle Paperwhite 3/4/Voyage/Oasis", 1072, 1448, epub.PALETTE_16}, {"KPW5", "Kindle Paperwhite 5/Signature Edition", 1236, 1648, epub.PALETTE_16}, {"KO", "Kindle Oasis 2/3", 1264, 1680, epub.PALETTE_16}, {"KS", "Kindle Scribe", 1860, 2480, epub.PALETTE_16}, // Kobo {"KoMT", "Kobo Mini/Touch", 600, 800, epub.PALETTE_16}, {"KoG", "Kobo Glo", 768, 1024, epub.PALETTE_16}, {"KoGHD", "Kobo Glo HD", 1072, 1448, epub.PALETTE_16}, {"KoA", "Kobo Aura", 758, 1024, epub.PALETTE_16}, {"KoAHD", "Kobo Aura HD", 1080, 1440, epub.PALETTE_16}, {"KoAH2O", "Kobo Aura H2O", 1080, 1430, epub.PALETTE_16}, {"KoAO", "Kobo Aura ONE", 1404, 1872, epub.PALETTE_16}, {"KoN", "Kobo Nia", 758, 1024, epub.PALETTE_16}, {"KoC", "Kobo Clara HD/Kobo Clara 2E", 1072, 1448, epub.PALETTE_16}, {"KoL", "Kobo Libra H2O/Kobo Libra 2", 1264, 1680, epub.PALETTE_16}, {"KoF", "Kobo Forma", 1440, 1920, epub.PALETTE_16}, {"KoS", "Kobo Sage", 1440, 1920, epub.PALETTE_16}, {"KoE", "Kobo Elipsa", 1404, 1872, epub.PALETTE_16}, } var ProfilesIdx = map[string]int{} func init() { for i, p := range Profiles { ProfilesIdx[p.Code] = i } } type Option struct { Input string Output string Profile string Author string Title string Quality int NoCrop bool Brightness int Contrast int Auto bool AutoRotate bool AutoSplitDoublePage bool NoBlankPage bool Manga bool Workers int LimitMb int } func (o *Option) String() string { var desc string var width, height, level int if i, ok := ProfilesIdx[o.Profile]; ok { profile := Profiles[i] desc = profile.Description width = profile.Width height = profile.Height level = len(profile.Palette) } limitmb := "nolimit" if o.LimitMb > 0 { limitmb = fmt.Sprintf("%d Mb", o.LimitMb) } return fmt.Sprintf(`Go Comic Converter Options: Input : %s Output : %s Profile : %s - %s - %dx%d - %d levels of gray Author : %s Title : %s Quality : %d Crop : %v Brightness : %d Contrast : %d AutoRotate : %v AutoSplitDoublePage: %v NoBlankPage : %v Manga : %v LimitMb : %s Workers : %d `, o.Input, o.Output, o.Profile, desc, width, height, level, o.Author, o.Title, o.Quality, !o.NoCrop, o.Brightness, o.Contrast, o.AutoRotate, o.AutoSplitDoublePage, o.NoBlankPage, o.Manga, limitmb, o.Workers, ) } func main() { availableProfiles := make([]string, 0) for _, p := range Profiles { availableProfiles = append(availableProfiles, fmt.Sprintf( " - %-7s ( %9s ) - %2d levels of gray - %s", p.Code, fmt.Sprintf("%dx%d", p.Width, p.Height), len(p.Palette), p.Description, )) } opt := &Option{} flag.StringVar(&opt.Input, "input", "", "Source of comic to convert: directory, cbz, zip, cbr, rar, pdf") flag.StringVar(&opt.Output, "output", "", "Output of the epub (directory or epub): (default [INPUT].epub)") flag.StringVar(&opt.Profile, "profile", "", fmt.Sprintf("Profile to use: \n%s", strings.Join(availableProfiles, "\n"))) flag.StringVar(&opt.Author, "author", "GO Comic Converter", "Author of the epub") flag.StringVar(&opt.Title, "title", "", "Title of the epub") flag.IntVar(&opt.Quality, "quality", 85, "Quality of the image") flag.BoolVar(&opt.NoCrop, "nocrop", false, "Disable cropping") flag.IntVar(&opt.Brightness, "brightness", 0, "Brightness readjustement: between -100 and 100, > 0 lighter, < 0 darker") flag.IntVar(&opt.Contrast, "contrast", 0, "Contrast readjustement: between -100 and 100, > 0 more contrast, < 0 less contrast") flag.BoolVar(&opt.Auto, "auto", false, "Activate all automatic options") flag.BoolVar(&opt.AutoRotate, "autorotate", false, "Auto Rotate page when width > height") flag.BoolVar(&opt.AutoSplitDoublePage, "autosplitdoublepage", false, "Auto Split double page when width > height") flag.BoolVar(&opt.NoBlankPage, "noblankpage", false, "Remove blank pages") flag.BoolVar(&opt.Manga, "manga", false, "Manga mode (right to left)") flag.IntVar(&opt.LimitMb, "limitmb", 0, "Limit size of the ePub: Default nolimit (0), Minimum 20") flag.IntVar(&opt.Workers, "workers", runtime.NumCPU(), "Number of workers") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", filepath.Base(os.Args[0])) flag.PrintDefaults() } flag.Parse() if opt.Input == "" { fmt.Fprintln(os.Stderr, "Missing input or output!") flag.Usage() os.Exit(1) } var defaultOutput string fi, err := os.Stat(opt.Input) if err != nil { fmt.Fprintln(os.Stderr, err) flag.Usage() os.Exit(1) } inputBase := filepath.Clean(opt.Input) if fi.IsDir() { defaultOutput = fmt.Sprintf("%s.epub", inputBase) } else { ext := filepath.Ext(inputBase) defaultOutput = fmt.Sprintf("%s.epub", inputBase[0:len(inputBase)-len(ext)]) } if opt.Output == "" { opt.Output = defaultOutput } if filepath.Ext(opt.Output) != ".epub" { fo, err := os.Stat(opt.Output) if err != nil { fmt.Fprintln(os.Stderr, err) flag.Usage() os.Exit(1) } if !fo.IsDir() { fmt.Fprintln(os.Stderr, "output must be an existing dir or end with .epub") flag.Usage() os.Exit(1) } opt.Output = filepath.Join( opt.Output, filepath.Base(defaultOutput), ) } profileIdx, profileMatch := ProfilesIdx[opt.Profile] if !profileMatch { fmt.Fprintln(os.Stderr, "Profile doesn't exists!") flag.Usage() os.Exit(1) } profile := Profiles[profileIdx] if opt.LimitMb > 0 && opt.LimitMb < 20 { fmt.Fprintln(os.Stderr, "LimitMb should be 0 or >= 20") flag.Usage() os.Exit(1) } if opt.Brightness < -100 || opt.Brightness > 100 { fmt.Fprintln(os.Stderr, "Brightness should be between -100 and 100") flag.Usage() os.Exit(1) } if opt.Contrast < -100 || opt.Contrast > 100 { fmt.Fprintln(os.Stderr, "Contrast should be between -100 and 100") flag.Usage() os.Exit(1) } if opt.Title == "" { ext := filepath.Ext(defaultOutput) opt.Title = filepath.Base(defaultOutput[0 : len(defaultOutput)-len(ext)]) } if opt.Auto { opt.AutoRotate = true opt.AutoSplitDoublePage = true } fmt.Fprintln(os.Stderr, opt) if err := epub.NewEpub(&epub.EpubOptions{ Input: opt.Input, Output: opt.Output, LimitMb: opt.LimitMb, Title: opt.Title, Author: opt.Author, ImageOptions: &epub.ImageOptions{ ViewWidth: profile.Width, ViewHeight: profile.Height, Quality: opt.Quality, Crop: !opt.NoCrop, Palette: profile.Palette, Brightness: opt.Brightness, Contrast: opt.Contrast, AutoRotate: opt.AutoRotate, AutoSplitDoublePage: opt.AutoSplitDoublePage, NoBlankPage: opt.NoBlankPage, Manga: opt.Manga, Workers: opt.Workers, }, }).Write(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } os.Exit(0) }