mirror of
https://github.com/gen2brain/cbconvert
synced 2026-06-30 09:11:54 +02:00
Fix outdir and recursive, issue #41
This commit is contained in:
+39
-11
@@ -93,6 +93,8 @@ type Converter struct {
|
||||
Workdir string
|
||||
// Page name prefix, set per input when combining
|
||||
prefix string
|
||||
// Input root for the current file, used to build recursive output paths
|
||||
root string
|
||||
// Number of files
|
||||
Nfiles int
|
||||
// Index of the current file
|
||||
@@ -115,6 +117,7 @@ type Converter struct {
|
||||
type File struct {
|
||||
Name string
|
||||
Path string
|
||||
Root string
|
||||
Stat os.FileInfo
|
||||
SizeHuman string
|
||||
}
|
||||
@@ -157,11 +160,13 @@ func (c *Converter) Cancel() {
|
||||
// Files returns list of found comic files.
|
||||
func (c *Converter) Files(args []string) ([]File, error) {
|
||||
var files []File
|
||||
var root string
|
||||
|
||||
toFile := func(fp string, f os.FileInfo) File {
|
||||
var file File
|
||||
file.Name = filepath.Base(fp)
|
||||
file.Path = fp
|
||||
file.Root = root
|
||||
file.Stat = f
|
||||
file.SizeHuman = humanize.IBytes(uint64(f.Size()))
|
||||
return file
|
||||
@@ -214,12 +219,14 @@ func (c *Converter) Files(args []string) ([]File, error) {
|
||||
}
|
||||
|
||||
if !stat.IsDir() {
|
||||
root = filepath.Dir(path)
|
||||
if isArchive(path) || isDocument(path) {
|
||||
if isSize(int64(c.Opts.Size), stat.Size()) {
|
||||
files = append(files, toFile(path, stat))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
root = path
|
||||
if c.Opts.Recursive {
|
||||
if err := filepath.Walk(path, walkFiles); err != nil {
|
||||
return files, fmt.Errorf("%s: %w", arg, err)
|
||||
@@ -261,9 +268,26 @@ func (c *Converter) Files(args []string) ([]File, error) {
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// recursiveDir mirrors the source path under OutDir, relative to the input root.
|
||||
func (c *Converter) recursiveDir(fileName string) string {
|
||||
dir := filepath.Dir(fileName)
|
||||
|
||||
if c.root != "" {
|
||||
if rel, err := filepath.Rel(c.root, dir); err == nil {
|
||||
return filepath.Join(c.Opts.OutDir, rel)
|
||||
}
|
||||
}
|
||||
|
||||
dir = strings.TrimPrefix(dir[len(filepath.VolumeName(dir)):], string(os.PathSeparator))
|
||||
|
||||
return filepath.Join(c.Opts.OutDir, dir)
|
||||
}
|
||||
|
||||
// Cover extracts cover.
|
||||
func (c *Converter) Cover(fileName string, fileInfo os.FileInfo) error {
|
||||
func (c *Converter) Cover(file File) error {
|
||||
c.CurrFile++
|
||||
c.root = file.Root
|
||||
fileName, fileInfo := file.Path, file.Stat
|
||||
|
||||
cover, err := c.coverImage(fileName, fileInfo)
|
||||
if err != nil {
|
||||
@@ -285,13 +309,12 @@ func (c *Converter) Cover(fileName string, fileInfo os.FileInfo) error {
|
||||
|
||||
var fName string
|
||||
if c.Opts.Recursive {
|
||||
fDir := strings.Split(filepath.Dir(fileName), string(os.PathSeparator))[1:]
|
||||
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Join(fDir...)), 0755)
|
||||
if err != nil {
|
||||
outDir := c.recursiveDir(fileName)
|
||||
if err := os.MkdirAll(outDir, 0755); err != nil {
|
||||
return fmt.Errorf("%s: %w", fileName, err)
|
||||
}
|
||||
|
||||
fName = filepath.Join(c.Opts.OutDir, filepath.Join(fDir...), fmt.Sprintf("%s.%s", baseNoExt(fileName), ext))
|
||||
fName = filepath.Join(outDir, fmt.Sprintf("%s.%s", baseNoExt(fileName), ext))
|
||||
} else {
|
||||
fName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s.%s", baseNoExt(fileName), ext))
|
||||
}
|
||||
@@ -310,8 +333,10 @@ func (c *Converter) Cover(fileName string, fileInfo os.FileInfo) error {
|
||||
}
|
||||
|
||||
// Thumbnail extracts thumbnail.
|
||||
func (c *Converter) Thumbnail(fileName string, fileInfo os.FileInfo) error {
|
||||
func (c *Converter) Thumbnail(file File) error {
|
||||
c.CurrFile++
|
||||
c.root = file.Root
|
||||
fileName, fileInfo := file.Path, file.Stat
|
||||
|
||||
cover, err := c.coverImage(fileName, fileInfo)
|
||||
if err != nil {
|
||||
@@ -352,13 +377,12 @@ func (c *Converter) Thumbnail(fileName string, fileInfo os.FileInfo) error {
|
||||
fURI = "file://" + fileName
|
||||
|
||||
if c.Opts.Recursive {
|
||||
fDir := strings.Split(filepath.Dir(fileName), string(os.PathSeparator))[1:]
|
||||
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Join(fDir...)), 0755)
|
||||
if err != nil {
|
||||
outDir := c.recursiveDir(fileName)
|
||||
if err := os.MkdirAll(outDir, 0755); err != nil {
|
||||
return fmt.Errorf("%s: %w", fileName, err)
|
||||
}
|
||||
|
||||
fName = filepath.Join(c.Opts.OutDir, filepath.Join(fDir...), fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
|
||||
fName = filepath.Join(outDir, fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
|
||||
} else {
|
||||
fName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%x.png", md5.Sum([]byte(fURI))))
|
||||
}
|
||||
@@ -496,8 +520,10 @@ func (c *Converter) Preview(fileName string, fileInfo os.FileInfo, width, height
|
||||
}
|
||||
|
||||
// Convert converts a comic book.
|
||||
func (c *Converter) Convert(fileName string, fileInfo os.FileInfo) error {
|
||||
func (c *Converter) Convert(file File) error {
|
||||
c.CurrFile++
|
||||
c.root = file.Root
|
||||
fileName, fileInfo := file.Path, file.Stat
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@@ -541,6 +567,8 @@ func (c *Converter) Combine(files []File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
c.root = ""
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
|
||||
@@ -33,13 +33,12 @@ func (c *Converter) archiveSaveZip(fileName string) error {
|
||||
|
||||
var zipName string
|
||||
if c.Opts.Recursive {
|
||||
fDir := strings.Split(filepath.Dir(fileName), string(os.PathSeparator))[1:]
|
||||
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Join(fDir...)), 0755)
|
||||
if err != nil {
|
||||
outDir := c.recursiveDir(fileName)
|
||||
if err := os.MkdirAll(outDir, 0755); err != nil {
|
||||
return fmt.Errorf("archiveSaveZip: %w", err)
|
||||
}
|
||||
|
||||
zipName = filepath.Join(c.Opts.OutDir, filepath.Join(fDir...), fmt.Sprintf("%s%s.cbz", baseNoExt(fileName), c.Opts.Suffix))
|
||||
zipName = filepath.Join(outDir, fmt.Sprintf("%s%s.cbz", baseNoExt(fileName), c.Opts.Suffix))
|
||||
} else {
|
||||
zipName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s%s.cbz", baseNoExt(fileName), c.Opts.Suffix))
|
||||
}
|
||||
@@ -108,13 +107,12 @@ func (c *Converter) archiveSaveTar(fileName string) error {
|
||||
|
||||
var tarName string
|
||||
if c.Opts.Recursive {
|
||||
fDir := strings.Split(filepath.Dir(fileName), string(os.PathSeparator))[1:]
|
||||
err := os.MkdirAll(filepath.Join(c.Opts.OutDir, filepath.Join(fDir...)), 0755)
|
||||
if err != nil {
|
||||
outDir := c.recursiveDir(fileName)
|
||||
if err := os.MkdirAll(outDir, 0755); err != nil {
|
||||
return fmt.Errorf("archiveSaveTar: %w", err)
|
||||
}
|
||||
|
||||
tarName = filepath.Join(c.Opts.OutDir, filepath.Join(fDir...), fmt.Sprintf("%s%s.cbt", baseNoExt(fileName), c.Opts.Suffix))
|
||||
tarName = filepath.Join(outDir, fmt.Sprintf("%s%s.cbt", baseNoExt(fileName), c.Opts.Suffix))
|
||||
} else {
|
||||
tarName = filepath.Join(c.Opts.OutDir, fmt.Sprintf("%s%s.cbt", baseNoExt(fileName), c.Opts.Suffix))
|
||||
}
|
||||
|
||||
+56
-3
@@ -29,7 +29,7 @@ func TestConvert(t *testing.T) {
|
||||
for _, file := range files {
|
||||
conv.Opts.Suffix = fmt.Sprintf("_%s%s", format, filepath.Ext(file.Path))
|
||||
|
||||
err = conv.Convert(file.Path, file.Stat)
|
||||
err = conv.Convert(file)
|
||||
if err != nil {
|
||||
t.Errorf("format %s: file %s: %v", format, file.Name, err)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func TestCover(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err = conv.Cover(file.Path, file.Stat)
|
||||
err = conv.Cover(file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func TestThumbnail(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err = conv.Thumbnail(file.Path, file.Stat)
|
||||
err = conv.Thumbnail(file)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -99,3 +99,56 @@ func TestThumbnail(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecursive(t *testing.T) {
|
||||
inDir, err := os.MkdirTemp(os.TempDir(), "cbc-in")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(inDir)
|
||||
|
||||
sub := filepath.Join(inDir, "chapter1")
|
||||
if err := os.MkdirAll(sub, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
src, err := os.ReadFile("testdata/test.cbz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(sub, "test.cbz"), src, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outDir, err := os.MkdirTemp(os.TempDir(), "cbc-out")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = outDir
|
||||
opts.Recursive = true
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{inDir})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(files) != 1 {
|
||||
t.Fatalf("expected 1 file, got %d", len(files))
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// output must mirror the input subtree relative to the input root, not the absolute path
|
||||
want := filepath.Join(outDir, "chapter1", "test.cbz")
|
||||
if _, err := os.Stat(want); err != nil {
|
||||
t.Errorf("expected output relative to input root at %s: %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1024,7 +1024,7 @@ func onThumbnail(ih iup.Ihandle) int {
|
||||
break
|
||||
}
|
||||
|
||||
if err := c.Thumbnail(file.Path, file.Stat); err != nil {
|
||||
if err := c.Thumbnail(file); err != nil {
|
||||
iup.PostMessage(iup.GetHandle("dlg"), err.Error(), 0, 0)
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -1067,7 +1067,7 @@ func onCover(ih iup.Ihandle) int {
|
||||
break
|
||||
}
|
||||
|
||||
if err := c.Cover(file.Path, file.Stat); err != nil {
|
||||
if err := c.Cover(file); err != nil {
|
||||
iup.PostMessage(iup.GetHandle("dlg"), err.Error(), 0, 0)
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -1131,7 +1131,7 @@ func onConvert(ih iup.Ihandle) int {
|
||||
}
|
||||
} else {
|
||||
for _, file := range files {
|
||||
if err := c.Convert(file.Path, file.Stat); err != nil {
|
||||
if err := c.Convert(file); err != nil {
|
||||
convertErr(err)
|
||||
if errors.Is(err, context.Canceled) {
|
||||
break
|
||||
|
||||
+25
-12
@@ -68,8 +68,8 @@ func main() {
|
||||
if _, err := os.Stat(opts.OutDir); err != nil {
|
||||
if err := os.MkdirAll(opts.OutDir, 0775); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
files, err := conv.Files(args)
|
||||
@@ -142,14 +142,14 @@ func main() {
|
||||
|
||||
continue
|
||||
case opts.Cover:
|
||||
if err := conv.Cover(file.Path, file.Stat); err != nil {
|
||||
if err := conv.Cover(file); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
continue
|
||||
case opts.Thumbnail:
|
||||
if err = conv.Thumbnail(file.Path, file.Stat); err != nil {
|
||||
if err = conv.Thumbnail(file); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func main() {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := conv.Convert(file.Path, file.Stat); err != nil {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -279,27 +279,27 @@ func parseFlags() (cbconvert.Options, []string) {
|
||||
|
||||
switch os.Args[1] {
|
||||
case "convert":
|
||||
_ = convert.Parse(os.Args[2:])
|
||||
operands := parseArgs(convert, os.Args[2:])
|
||||
if !pipe {
|
||||
args = convert.Args()
|
||||
args = operands
|
||||
}
|
||||
case "cover":
|
||||
opts.Cover = true
|
||||
_ = cover.Parse(os.Args[2:])
|
||||
operands := parseArgs(cover, os.Args[2:])
|
||||
if !pipe {
|
||||
args = cover.Args()
|
||||
args = operands
|
||||
}
|
||||
case "thumbnail":
|
||||
opts.Thumbnail = true
|
||||
_ = thumbnail.Parse(os.Args[2:])
|
||||
operands := parseArgs(thumbnail, os.Args[2:])
|
||||
if !pipe {
|
||||
args = thumbnail.Args()
|
||||
args = operands
|
||||
}
|
||||
case "meta":
|
||||
opts.Meta = true
|
||||
_ = meta.Parse(os.Args[2:])
|
||||
operands := parseArgs(meta, os.Args[2:])
|
||||
if !pipe {
|
||||
args = meta.Args()
|
||||
args = operands
|
||||
}
|
||||
case "version":
|
||||
opts.Version = true
|
||||
@@ -314,6 +314,19 @@ func parseFlags() (cbconvert.Options, []string) {
|
||||
return opts, args
|
||||
}
|
||||
|
||||
// parseArgs parses flags interspersed with file/dir operands.
|
||||
func parseArgs(fs *flag.FlagSet, args []string) []string {
|
||||
var operands []string
|
||||
|
||||
_ = fs.Parse(args)
|
||||
for fs.NArg() > 0 {
|
||||
operands = append(operands, fs.Arg(0))
|
||||
_ = fs.Parse(fs.Args()[1:])
|
||||
}
|
||||
|
||||
return operands
|
||||
}
|
||||
|
||||
// piped checks if we have piped stdin.
|
||||
func piped() bool {
|
||||
f, err := os.Stdin.Stat()
|
||||
|
||||
Reference in New Issue
Block a user