feat: update
This commit is contained in:
67
backend/pkg/utils/exec.go
Normal file
67
backend/pkg/utils/exec.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"github.com/go-pay/errgroup"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExecCommand executes a command and streams its output in real-time
|
||||||
|
func ExecCommand(name string, args ...string) error {
|
||||||
|
cmd := exec.Command(name, args...)
|
||||||
|
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "stdout pipe error")
|
||||||
|
}
|
||||||
|
|
||||||
|
stderr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "stderr pipe error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return errors.Wrap(err, "command start error")
|
||||||
|
}
|
||||||
|
|
||||||
|
var eg errgroup.Group
|
||||||
|
eg.Go(func(ctx context.Context) error {
|
||||||
|
scanner := bufio.NewScanner(stdout)
|
||||||
|
for scanner.Scan() {
|
||||||
|
log.Info(scanner.Text())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
eg.Go(func(ctx context.Context) error {
|
||||||
|
scanner := bufio.NewScanner(stderr)
|
||||||
|
for scanner.Scan() {
|
||||||
|
log.Error(scanner.Text())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return errors.Wrap(err, "command wait error")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := eg.Wait(); err != nil {
|
||||||
|
return errors.Wrap(err, "command wait error")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecCommandOutput executes a command and returns its output
|
||||||
|
func ExecCommandOutput(name string, args ...string) ([]byte, error) {
|
||||||
|
cmd := exec.Command(name, args...)
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to execute command: %s", name)
|
||||||
|
}
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
@@ -1,120 +1,56 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"context"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-pay/errgroup"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetMediaDuration(path string) (int64, error) {
|
func GetMediaDuration(path string) (int64, error) {
|
||||||
// use ffprobe to get media duration
|
args := []string{
|
||||||
// ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 <file>
|
"-v", "error",
|
||||||
cmd := exec.Command("ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "default=noprint_wrappers=1:nokey=1", path)
|
"-show_entries", "format=duration",
|
||||||
durationOutput, err := cmd.Output()
|
"-of", "default=noprint_wrappers=1:nokey=1",
|
||||||
|
path,
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := ExecCommandOutput("ffprobe", args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "ffprobe error")
|
return 0, errors.Wrap(err, "ffprobe error")
|
||||||
}
|
}
|
||||||
duration := string(durationOutput)
|
|
||||||
duration = strings.TrimSpace(duration)
|
duration := strings.TrimSpace(string(output))
|
||||||
durationFloat, err := strconv.ParseFloat(duration, 64)
|
durationFloat, err := strconv.ParseFloat(duration, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, errors.Wrap(err, "duration conversion error")
|
return 0, errors.Wrap(err, "duration conversion error")
|
||||||
}
|
}
|
||||||
|
|
||||||
return int64(durationFloat), nil
|
return int64(durationFloat), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CutMedia(input, output string, start, end int64) error {
|
func CutMedia(input, output string, start, end int64) error {
|
||||||
// ffmpeg -ss 00:00:00 -i input.mp4 -to 00:01:00 -c copy output.mp4
|
args := []string{
|
||||||
cmd := exec.Command("ffmpeg", "-y", "-ss", strconv.FormatInt(start, 10), "-i", input, "-t", strconv.FormatInt(end, 10), "-c", "copy", output)
|
"-y",
|
||||||
|
"-ss", strconv.FormatInt(start, 10),
|
||||||
stdout, err := cmd.StdoutPipe()
|
"-i", input,
|
||||||
if err != nil {
|
"-t", strconv.FormatInt(end, 10),
|
||||||
log.Errorf("Error creating stdout pipe: %v", err)
|
"-c", "copy",
|
||||||
return err
|
output,
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe()
|
return ExecCommand("ffmpeg", args...)
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error creating stderr pipe: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
log.Errorf("Error starting command: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var eg errgroup.Group
|
|
||||||
eg.Go(func(ctx context.Context) error {
|
|
||||||
scanner := bufio.NewScanner(stdout)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log.Info(scanner.Text())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
eg.Go(func(ctx context.Context) error {
|
|
||||||
scanner := bufio.NewScanner(stderr)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log.Error(scanner.Text())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
log.Errorf("Error waiting for command: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
log.Errorf("Error waiting for command: %v", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFrameImageFromVideo extracts target time frame from a video file and saves it as an image.
|
// GetFrameImageFromVideo extracts target time frame from a video file and saves it as an image.
|
||||||
func GetFrameImageFromVideo(input, output string, time int64) error {
|
func GetFrameImageFromVideo(input, output string, time int64) error {
|
||||||
// ffmpeg -y -i input.mp4 -ss 00:00:01 -vframes 1 output.jpg
|
args := []string{
|
||||||
cmd := exec.Command("ffmpeg", "-y", "-i", input, "-ss", strconv.FormatInt(time, 10), "-vframes", "1", output)
|
"-y",
|
||||||
stdout, err := cmd.StdoutPipe()
|
"-i", input,
|
||||||
if err != nil {
|
"-ss", strconv.FormatInt(time, 10),
|
||||||
return errors.Wrap(err, "stdout pipe error")
|
"-vframes", "1",
|
||||||
|
output,
|
||||||
}
|
}
|
||||||
|
|
||||||
stderr, err := cmd.StderrPipe()
|
return ExecCommand("ffmpeg", args...)
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "stderr pipe error")
|
|
||||||
}
|
|
||||||
if err := cmd.Start(); err != nil {
|
|
||||||
return errors.Wrap(err, "command start error")
|
|
||||||
}
|
|
||||||
var eg errgroup.Group
|
|
||||||
eg.Go(func(ctx context.Context) error {
|
|
||||||
scanner := bufio.NewScanner(stdout)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log.Info(scanner.Text())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
eg.Go(func(ctx context.Context) error {
|
|
||||||
scanner := bufio.NewScanner(stderr)
|
|
||||||
for scanner.Scan() {
|
|
||||||
log.Error(scanner.Text())
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err := cmd.Wait(); err != nil {
|
|
||||||
return errors.Wrap(err, "command wait error")
|
|
||||||
}
|
|
||||||
if err := eg.Wait(); err != nil {
|
|
||||||
return errors.Wrap(err, "command wait error")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user