Backend: Use mutex in convert so that it can be canceled

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-01-08 20:51:49 +01:00
parent b37d4472e4
commit 719fd1a811
6 changed files with 45 additions and 23 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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())

View file

@ -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)

View file

@ -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] {

View file

@ -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] {