From 719fd1a81146f03e8deabe494ff70fba7376ff68 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Wed, 8 Jan 2020 20:51:49 +0100 Subject: [PATCH] Backend: Use mutex in convert so that it can be canceled Signed-off-by: Michael Mayer --- internal/api/index.go | 2 +- internal/commands/convert.go | 2 +- internal/photoprism/convert.go | 50 ++++++++++++++++++++--------- internal/photoprism/convert_test.go | 10 +++--- internal/photoprism/import.go | 2 +- internal/photoprism/index.go | 2 +- 6 files changed, 45 insertions(+), 23 deletions(-) diff --git a/internal/api/index.go b/internal/api/index.go index 2921db06f..501a269d4 100644 --- a/internal/api/index.go +++ b/internal/api/index.go @@ -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 { diff --git a/internal/commands/convert.go b/internal/commands/convert.go index 62d3192d8..3c2b2c645 100644 --- a/internal/commands/convert.go +++ b/internal/commands/convert.go @@ -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) diff --git a/internal/photoprism/convert.go b/internal/photoprism/convert.go index 0cabc43e8..461d49f9d 100644 --- a/internal/photoprism/convert.go +++ b/internal/photoprism/convert.go @@ -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()) diff --git a/internal/photoprism/convert_test.go b/internal/photoprism/convert_test.go index 3cbb0a4e3..fab0ac1b0 100644 --- a/internal/photoprism/convert_test.go +++ b/internal/photoprism/convert_test.go @@ -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) diff --git a/internal/photoprism/import.go b/internal/photoprism/import.go index 53ff63a26..0347d58f7 100644 --- a/internal/photoprism/import.go +++ b/internal/photoprism/import.go @@ -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] { diff --git a/internal/photoprism/index.go b/internal/photoprism/index.go index e1b539d77..fa032f17d 100644 --- a/internal/photoprism/index.go +++ b/internal/photoprism/index.go @@ -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] {