From 77c810e2c06b89fff221f639b0ff01d51de277ac Mon Sep 17 00:00:00 2001
From: Googol Lee <i@googol.im>
Date: Wed, 18 Sep 2024 11:15:34 +0200
Subject: [PATCH] Split Ffprobe init.

---
 .../executable_worker/executable_worker.go    | 30 ++++++++++++++++
 .../executable_worker_test.go                 | 33 +++++++++++++++++
 .../executable_worker/ffmpeg_cli.go           | 14 ++------
 .../executable_worker/ffmpeg_cli_test.go      | 36 +++++++++++++++----
 4 files changed, 94 insertions(+), 19 deletions(-)

diff --git a/api/scanner/media_encoding/executable_worker/executable_worker.go b/api/scanner/media_encoding/executable_worker/executable_worker.go
index bfead7a..6ae0db2 100644
--- a/api/scanner/media_encoding/executable_worker/executable_worker.go
+++ b/api/scanner/media_encoding/executable_worker/executable_worker.go
@@ -1,8 +1,21 @@
 package executable_worker
 
+import (
+	"fmt"
+	"log"
+	"os/exec"
+	"strings"
+
+	"gopkg.in/vansante/go-ffprobe.v2"
+)
+
 func InitializeExecutableWorkers() {
 	Magick = newMagickCli()
 	Ffmpeg = newFfmpegCli()
+
+	if err := InitFfprobePath(); err != nil {
+		log.Println("ffprobe init fail:", err)
+	}
 }
 
 var Magick *MagickCli = nil
@@ -11,3 +24,20 @@ var Ffmpeg *FfmpegCli = nil
 type ExecutableWorker interface {
 	Path() string
 }
+
+func InitFfprobePath() error {
+	path, err := exec.LookPath("ffprobe")
+	if err != nil {
+		return fmt.Errorf("Executable ffprobe not found: %w", err)
+	}
+
+	version, err := exec.Command(path, "-version").Output()
+	if err != nil {
+		return fmt.Errorf("Executable ffprobe(%q) not executable: %w", path, err)
+	}
+
+	log.Println("Found ffprobe:", path, "version:", strings.Split(string(version), "\n")[0])
+	ffprobe.SetFFProbeBinPath(path)
+
+	return nil
+}
diff --git a/api/scanner/media_encoding/executable_worker/executable_worker_test.go b/api/scanner/media_encoding/executable_worker/executable_worker_test.go
index 756ffeb..6229a48 100644
--- a/api/scanner/media_encoding/executable_worker/executable_worker_test.go
+++ b/api/scanner/media_encoding/executable_worker/executable_worker_test.go
@@ -7,6 +7,7 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/photoview/photoview/api/scanner/media_encoding/executable_worker"
 	"github.com/photoview/photoview/api/test_utils"
 )
 
@@ -41,3 +42,35 @@ func setEnv(key, value string) func() {
 		os.Setenv(key, org)
 	}
 }
+
+func TestInitFfprobePath(t *testing.T) {
+	t.Run("PathFail", func(t *testing.T) {
+		err := executable_worker.InitFfprobePath()
+		if err == nil {
+			t.Fatalf("InitFfprobePath() returns nil, want an error")
+		}
+	})
+
+	t.Run("VersionFail", func(t *testing.T) {
+		donePath := setPathWithCurrent("./testdata/bin")
+		defer donePath()
+
+		doneEnv := setEnv("FAIL_WITH", "expect failure")
+		defer doneEnv()
+
+		err := executable_worker.InitFfprobePath()
+		if err == nil {
+			t.Fatalf("InitFfprobePath() returns nil, want an error")
+		}
+	})
+
+	t.Run("Succeed", func(t *testing.T) {
+		donePath := setPathWithCurrent("./testdata/bin")
+		defer donePath()
+
+		err := executable_worker.InitFfprobePath()
+		if err != nil {
+			t.Fatalf("InitFfprobePath() returns %v, want nil", err)
+		}
+	})
+}
diff --git a/api/scanner/media_encoding/executable_worker/ffmpeg_cli.go b/api/scanner/media_encoding/executable_worker/ffmpeg_cli.go
index f06ae81..22c6de8 100644
--- a/api/scanner/media_encoding/executable_worker/ffmpeg_cli.go
+++ b/api/scanner/media_encoding/executable_worker/ffmpeg_cli.go
@@ -16,17 +16,6 @@ type FfmpegCli struct {
 }
 
 func newFfmpegCli() *FfmpegCli {
-	if path, err := exec.LookPath("ffprobe"); err == nil {
-		if version, err := exec.Command(path, "-version").Output(); err == nil {
-			log.Println("Found ffprobe:", path, "version:", strings.Split(string(version), "\n")[0])
-			ffprobe.SetFFProbeBinPath(path)
-		} else {
-			log.Println("Executable ffprobe not executable:", path)
-		}
-	} else {
-		log.Println("Executable ffprobe not found")
-	}
-
 	if utils.EnvDisableVideoEncoding.GetBool() {
 		log.Printf("Executable worker disabled (%s=%q): ffmpeg\n", utils.EnvDisableVideoEncoding.GetName(), utils.EnvDisableVideoEncoding.GetValue())
 		return nil
@@ -45,6 +34,7 @@ func newFfmpegCli() *FfmpegCli {
 	}
 
 	codec := utils.EnvVideoCodec.GetValue()
+	fmt.Println("codec:", codec)
 	if codec == "" {
 		codec = "h264"
 	}
@@ -83,7 +73,7 @@ func (worker *FfmpegCli) EncodeMp4(inputPath string, outputPath string) error {
 
 func (worker *FfmpegCli) EncodeVideoThumbnail(inputPath string, outputPath string, probeData *ffprobe.ProbeData) error {
 
-	thumbnailOffsetSeconds := fmt.Sprintf("%d", int(probeData.Format.DurationSeconds*0.25))
+	thumbnailOffsetSeconds := fmt.Sprintf("%.f", probeData.Format.DurationSeconds*0.25)
 
 	args := []string{
 		"-ss", thumbnailOffsetSeconds, // grab frame at time offset
diff --git a/api/scanner/media_encoding/executable_worker/ffmpeg_cli_test.go b/api/scanner/media_encoding/executable_worker/ffmpeg_cli_test.go
index bd6fea7..bf1fa54 100644
--- a/api/scanner/media_encoding/executable_worker/ffmpeg_cli_test.go
+++ b/api/scanner/media_encoding/executable_worker/ffmpeg_cli_test.go
@@ -5,10 +5,11 @@ import (
 	"testing"
 
 	"github.com/photoview/photoview/api/scanner/media_encoding/executable_worker"
+	"github.com/photoview/photoview/api/utils"
 	"gopkg.in/vansante/go-ffprobe.v2"
 )
 
-func TestFfmpegWorkerNotExist(t *testing.T) {
+func TestFfmpegNotExist(t *testing.T) {
 	done := setPathWithCurrent()
 	defer done()
 
@@ -19,7 +20,7 @@ func TestFfmpegWorkerNotExist(t *testing.T) {
 	}
 }
 
-func TestFfmpegWorkerIgnore(t *testing.T) {
+func TestFfmpegIgnore(t *testing.T) {
 	donePath := setPathWithCurrent("./testdata/bin")
 	defer donePath()
 
@@ -33,7 +34,7 @@ func TestFfmpegWorkerIgnore(t *testing.T) {
 	}
 }
 
-func TestFfmpegWorker(t *testing.T) {
+func TestFfmpeg(t *testing.T) {
 	done := setPathWithCurrent("./testdata/bin")
 	defer done()
 
@@ -47,11 +48,11 @@ func TestFfmpegWorker(t *testing.T) {
 		doneEnv := setEnv("FAIL_WITH", "expect failure")
 		defer doneEnv()
 
-		err := executable_worker.Ffmpeg.EncodeMp4("input_fail", "output")
+		err := executable_worker.Ffmpeg.EncodeMp4("input", "output")
 		if err == nil {
 			t.Fatalf("Ffmpeg.EncodeMp4(...) = nil, should be an error.")
 		}
-		if got, want := err.Error(), `^encoding video with ".*/testdata/bin/ffmpeg" .* error: .*$`; !regexp.MustCompile(want).MatchString(got) {
+		if got, want := err.Error(), `^encoding video with ".*/testdata/bin/ffmpeg" \[-i input -vcodec h264 .* output\] error: .*$`; !regexp.MustCompile(want).MatchString(got) {
 			t.Errorf("Ffmpeg.EncodeMp4(...) = %q, should be as reg pattern %q", got, want)
 		}
 	})
@@ -72,11 +73,11 @@ func TestFfmpegWorker(t *testing.T) {
 		doneEnv := setEnv("FAIL_WITH", "expect failure")
 		defer doneEnv()
 
-		err := executable_worker.Ffmpeg.EncodeVideoThumbnail("input_fail", "output", probeData)
+		err := executable_worker.Ffmpeg.EncodeVideoThumbnail("input", "output", probeData)
 		if err == nil {
 			t.Fatalf("Ffmpeg.EncodeVideoThumbnail(...) = nil, should be an error.")
 		}
-		if got, want := err.Error(), `^encoding video thumbnail with ".*/testdata/bin/ffmpeg" .* error: .*$`; !regexp.MustCompile(want).MatchString(got) {
+		if got, want := err.Error(), `^encoding video thumbnail with ".*/testdata/bin/ffmpeg" \[-ss 2 -i input .* output\] error: .*$`; !regexp.MustCompile(want).MatchString(got) {
 			t.Errorf("Ffmpeg.EncodeVideoThumbnail(...) = %q, should be as reg pattern %q", got, want)
 		}
 	})
@@ -88,3 +89,24 @@ func TestFfmpegWorker(t *testing.T) {
 		}
 	})
 }
+
+func TestFfmpegWithCustomCodec(t *testing.T) {
+	doneCodec := setEnv(utils.EnvVideoCodec.GetName(), "codec_custom")
+	defer doneCodec()
+
+	donePath := setPathWithCurrent("./testdata/bin")
+	defer donePath()
+
+	executable_worker.InitializeExecutableWorkers()
+
+	doneEnv := setEnv("FAIL_WITH", "expect failure")
+	defer doneEnv()
+
+	err := executable_worker.Ffmpeg.EncodeMp4("input", "output")
+	if err == nil {
+		t.Fatalf("Ffmpeg.EncodeMp4(...) = nil, should be an error.")
+	}
+	if got, want := err.Error(), `^encoding video with ".*/testdata/bin/ffmpeg" \[-i input -vcodec codec_custom .* output\] error: .*$`; !regexp.MustCompile(want).MatchString(got) {
+		t.Errorf("Ffmpeg.EncodeMp4(...) = %q, should be as reg pattern %q", got, want)
+	}
+}
