Backend: Use mutex in convert so that it can be canceled
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
b37d4472e4
commit
719fd1a811
6 changed files with 45 additions and 23 deletions
|
@ -61,7 +61,7 @@ func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
|||
|
||||
if f.ConvertRaw && !conf.ReadOnly() {
|
||||
convert := photoprism.NewConvert(conf)
|
||||
convert.Path(conf.OriginalsPath())
|
||||
convert.Start(conf.OriginalsPath())
|
||||
}
|
||||
|
||||
if f.CreateThumbs {
|
||||
|
|
|
@ -32,7 +32,7 @@ func convertAction(ctx *cli.Context) error {
|
|||
|
||||
convert := photoprism.NewConvert(conf)
|
||||
|
||||
convert.Path(conf.OriginalsPath())
|
||||
convert.Start(conf.OriginalsPath())
|
||||
|
||||
elapsed := time.Since(start)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package photoprism
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
@ -8,6 +9,7 @@ import (
|
|||
|
||||
"github.com/photoprism/photoprism/internal/config"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/mutex"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
)
|
||||
|
||||
|
@ -21,11 +23,27 @@ func NewConvert(conf *config.Config) *Convert {
|
|||
return &Convert{conf: conf}
|
||||
}
|
||||
|
||||
// Path converts all files in a directory to JPEG if possible.
|
||||
func (c *Convert) Path(path string) {
|
||||
// Start converts all files in a directory to JPEG if possible.
|
||||
func (c *Convert) Start(path string) {
|
||||
if err := mutex.Worker.Start(); err != nil {
|
||||
event.Error(fmt.Sprintf("convert: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
defer mutex.Worker.Stop()
|
||||
|
||||
err := filepath.Walk(path, func(filename string, fileInfo os.FileInfo, err error) error {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
log.Errorf("convert: %s [panic]", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if mutex.Worker.Canceled() {
|
||||
return errors.New("convert: canceled")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("Walk", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -33,14 +51,14 @@ func (c *Convert) Path(path string) {
|
|||
return nil
|
||||
}
|
||||
|
||||
mediaFile, err := NewMediaFile(filename)
|
||||
mf, err := NewMediaFile(filename)
|
||||
|
||||
if err != nil || !(mediaFile.IsRaw() || mediaFile.IsHEIF() || mediaFile.IsImageOther()) {
|
||||
if err != nil || !(mf.IsRaw() || mf.IsHEIF() || mf.IsImageOther()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := c.ToJpeg(mediaFile); err != nil {
|
||||
log.Warnf("file could not be converted to JPEG: \"%s\"", filename)
|
||||
if _, err := c.ToJpeg(mf); err != nil {
|
||||
log.Warnf("convert: %s (%s)", err.Error(), filename)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -56,17 +74,19 @@ func (c *Convert) ConvertCommand(image *MediaFile, jpegFilename string, xmpFilen
|
|||
if image.IsRaw() {
|
||||
if c.conf.SipsBin() != "" {
|
||||
result = exec.Command(c.conf.SipsBin(), "-s format jpeg", image.filename, "--out "+jpegFilename)
|
||||
} else if c.conf.DarktableBin() != "" && xmpFilename != "" {
|
||||
result = exec.Command(c.conf.DarktableBin(), image.filename, xmpFilename, jpegFilename)
|
||||
} else if c.conf.DarktableBin() != "" {
|
||||
result = exec.Command(c.conf.DarktableBin(), image.filename, jpegFilename)
|
||||
if xmpFilename != "" {
|
||||
result = exec.Command(c.conf.DarktableBin(), image.filename, xmpFilename, jpegFilename)
|
||||
} else {
|
||||
result = exec.Command(c.conf.DarktableBin(), image.filename, jpegFilename)
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("no binary for raw to jpeg conversion could be found: %s", image.Filename())
|
||||
return nil, fmt.Errorf("convert: no binary for raw to jpeg could be found (%s)", image.Filename())
|
||||
}
|
||||
} else if image.IsHEIF() {
|
||||
result = exec.Command(c.conf.HeifConvertBin(), image.filename, jpegFilename)
|
||||
} else {
|
||||
return nil, fmt.Errorf("image type not supported for conversion: %s", image.Type())
|
||||
return nil, fmt.Errorf("convert: image type not supported for conversion (%s)", image.Type())
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
@ -75,7 +95,7 @@ func (c *Convert) ConvertCommand(image *MediaFile, jpegFilename string, xmpFilen
|
|||
// ToJpeg converts a single image file to JPEG if possible.
|
||||
func (c *Convert) ToJpeg(image *MediaFile) (*MediaFile, error) {
|
||||
if !image.Exists() {
|
||||
return nil, fmt.Errorf("can not convert to jpeg, file does not exist: %s", image.Filename())
|
||||
return nil, fmt.Errorf("convert: can not convert to jpeg, file does not exist (%s)", image.Filename())
|
||||
}
|
||||
|
||||
if image.IsJpeg() {
|
||||
|
@ -93,10 +113,10 @@ func (c *Convert) ToJpeg(image *MediaFile) (*MediaFile, error) {
|
|||
}
|
||||
|
||||
if c.conf.ReadOnly() {
|
||||
return nil, fmt.Errorf("can not convert to jpeg in read only mode: %s", image.Filename())
|
||||
return nil, fmt.Errorf("convert: disabled in read only mode (%s)", image.Filename())
|
||||
}
|
||||
|
||||
log.Infof("converting \"%s\" to \"%s\"", image.filename, jpegFilename)
|
||||
log.Infof("convert: \"%s\" -> \"%s\"", image.filename, jpegFilename)
|
||||
|
||||
fileName := image.RelativeFilename(c.conf.OriginalsPath())
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ func TestConvert_ToJpeg(t *testing.T) {
|
|||
assert.Equal(t, "Canon EOS 6D", infoRaw.CameraModel)
|
||||
}
|
||||
|
||||
func TestConvert_Path(t *testing.T) {
|
||||
func TestConvert_Start(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ func TestConvert_Path(t *testing.T) {
|
|||
|
||||
convert := NewConvert(conf)
|
||||
|
||||
convert.Path(conf.ImportPath())
|
||||
convert.Start(conf.ImportPath())
|
||||
|
||||
jpegFilename := conf.ImportPath() + "/raw/canon_eos_6d.jpg"
|
||||
|
||||
|
@ -92,7 +92,9 @@ func TestConvert_Path(t *testing.T) {
|
|||
|
||||
image, err := NewMediaFile(jpegFilename)
|
||||
|
||||
assert.Nil(t, err)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
assert.Equal(t, jpegFilename, image.filename, "FileName must be the same")
|
||||
|
||||
|
@ -106,7 +108,7 @@ func TestConvert_Path(t *testing.T) {
|
|||
|
||||
os.Remove(existingJpegFilename)
|
||||
|
||||
convert.Path(conf.ImportPath())
|
||||
convert.Start(conf.ImportPath())
|
||||
|
||||
newHash := file.Hash(existingJpegFilename)
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ func (imp *Import) Start(importPath string) {
|
|||
}()
|
||||
|
||||
if mutex.Worker.Canceled() {
|
||||
return errors.New("importing canceled")
|
||||
return errors.New("import: canceled")
|
||||
}
|
||||
|
||||
if err != nil || done[filename] {
|
||||
|
|
|
@ -86,7 +86,7 @@ func (ind *Index) Start(options IndexOptions) map[string]bool {
|
|||
}()
|
||||
|
||||
if mutex.Worker.Canceled() {
|
||||
return errors.New("indexing canceled")
|
||||
return errors.New("index: canceled")
|
||||
}
|
||||
|
||||
if err != nil || done[filename] {
|
||||
|
|
Loading…
Reference in a new issue