This commit is contained in:
69
backend_v1/pkg/utils/exec.go
Normal file
69
backend_v1/pkg/utils/exec.go
Normal file
@@ -0,0 +1,69 @@
|
||||
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 {
|
||||
log.Infof("Executing command: %s %v", name, args)
|
||||
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) {
|
||||
log.Infof("Executing command: %s %v", name, args)
|
||||
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
|
||||
}
|
||||
62
backend_v1/pkg/utils/ffmpeg.go
Normal file
62
backend_v1/pkg/utils/ffmpeg.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GetMediaDuration(path string) (int64, error) {
|
||||
args := []string{
|
||||
"-v", "error",
|
||||
"-show_entries", "format=duration",
|
||||
"-of", "default=noprint_wrappers=1:nokey=1",
|
||||
path,
|
||||
}
|
||||
|
||||
output, err := ExecCommandOutput("ffprobe", args...)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "ffprobe error")
|
||||
}
|
||||
|
||||
duration := strings.TrimSpace(string(output))
|
||||
durationFloat, err := strconv.ParseFloat(duration, 64)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "duration conversion error")
|
||||
}
|
||||
|
||||
return int64(durationFloat), nil
|
||||
}
|
||||
|
||||
func CutMedia(input, output string, start, end int64) error {
|
||||
args := []string{
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
"-nostats",
|
||||
"-v", "error",
|
||||
"-ss", strconv.FormatInt(start, 10),
|
||||
"-i", input,
|
||||
"-t", strconv.FormatInt(end, 10),
|
||||
"-c", "copy",
|
||||
output,
|
||||
}
|
||||
|
||||
return ExecCommand("ffmpeg", args...)
|
||||
}
|
||||
|
||||
// GetFrameImageFromVideo extracts target time frame from a video file and saves it as an image.
|
||||
func GetFrameImageFromVideo(input, output string, time int64) error {
|
||||
args := []string{
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
"-nostats",
|
||||
"-v", "error",
|
||||
"-i", input,
|
||||
"-ss", strconv.FormatInt(time, 10),
|
||||
"-vframes", "1",
|
||||
output,
|
||||
}
|
||||
|
||||
return ExecCommand("ffmpeg", args...)
|
||||
}
|
||||
49
backend_v1/pkg/utils/ffmpeg_test.go
Normal file
49
backend_v1/pkg/utils/ffmpeg_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/rogeecn/fabfile"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_GetMediaDuration(t *testing.T) {
|
||||
Convey("test_get_media_duration", t, func() {
|
||||
target := fabfile.MustFind("fixtures/input.mp4")
|
||||
duration, err := GetMediaDuration(target)
|
||||
So(err, ShouldBeNil)
|
||||
t.Logf("duration is: %d", duration)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_CutMedia(t *testing.T) {
|
||||
Convey("test_cut_media", t, func() {
|
||||
input := fabfile.MustFind("fixtures/input.mp4")
|
||||
output := fabfile.MustFind("fixtures/output.mp4")
|
||||
|
||||
t.Logf("INPUT: %s", input)
|
||||
t.Logf("OUTPUT: %s", output)
|
||||
|
||||
err := CutMedia(input, output, 0, 10)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// check output duration
|
||||
duration, err := GetMediaDuration(output)
|
||||
So(err, ShouldBeNil)
|
||||
t.Logf("output duration is: %d", duration)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetFrameImageFromVideo(t *testing.T) {
|
||||
Convey("test_get_frame_image_from_video", t, func() {
|
||||
input := fabfile.MustFind("fixtures/input.mp4")
|
||||
output := filepath.Join(filepath.Dir(input), "output.jpg")
|
||||
|
||||
t.Logf("INPUT: %s", input)
|
||||
t.Logf("OUTPUT: %s", output)
|
||||
|
||||
err := GetFrameImageFromVideo(input, output, 1)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
}
|
||||
19
backend_v1/pkg/utils/fiber.go
Normal file
19
backend_v1/pkg/utils/fiber.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
func FullURI(ctx fiber.Ctx) string {
|
||||
fullURL := string(ctx.Request().URI().FullURI())
|
||||
u, err := url.Parse(fullURL)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
u.Scheme = ctx.Scheme()
|
||||
u.Host = ctx.Host()
|
||||
|
||||
return u.String()
|
||||
}
|
||||
42
backend_v1/pkg/utils/md5.go
Normal file
42
backend_v1/pkg/utils/md5.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Compare file md5
|
||||
func CompareFileMd5(file, md5 string) (bool, error) {
|
||||
fileMd5, err := GetFileMd5(file)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return fileMd5 == md5, nil
|
||||
}
|
||||
|
||||
// GetFileMd5
|
||||
func GetFileMd5(file string) (string, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%x", h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// GetFileSize
|
||||
func GetFileSize(file string) (int64, error) {
|
||||
fi, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return fi.Size(), nil
|
||||
}
|
||||
45
backend_v1/pkg/utils/posts.go
Normal file
45
backend_v1/pkg/utils/posts.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package utils
|
||||
|
||||
import "strings"
|
||||
|
||||
// FormatTitle
|
||||
// Format the title of a media file by replacing spaces with underscores and removing special characters
|
||||
func FormatTitle(title string) string {
|
||||
// remove file ext from title
|
||||
if strings.Contains(title, ".") {
|
||||
title = strings.Split(title, ".")[0]
|
||||
}
|
||||
|
||||
// replace all spaces with underscores
|
||||
replacements := []string{
|
||||
" ", "",
|
||||
"!", "",
|
||||
"@", "",
|
||||
"#", "",
|
||||
"$", "",
|
||||
"%", "",
|
||||
"^", "",
|
||||
"&", "",
|
||||
"*", "",
|
||||
"(", "(",
|
||||
")", ")",
|
||||
"[", "【",
|
||||
"]", "】",
|
||||
"{", "《",
|
||||
"}", "》",
|
||||
":", ":",
|
||||
";", "",
|
||||
"'", "",
|
||||
"\"", "",
|
||||
"<", "",
|
||||
">", "",
|
||||
",", "",
|
||||
".", "",
|
||||
"?", "",
|
||||
}
|
||||
|
||||
replacer := strings.NewReplacer(replacements...)
|
||||
title = replacer.Replace(title)
|
||||
|
||||
return title
|
||||
}
|
||||
25
backend_v1/pkg/utils/random_name.go
Normal file
25
backend_v1/pkg/utils/random_name.go
Normal file
File diff suppressed because one or more lines are too long
11
backend_v1/pkg/utils/random_name_test.go
Normal file
11
backend_v1/pkg/utils/random_name_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNames_Random(t *testing.T) {
|
||||
for i := 0; i < 10; i++ {
|
||||
|
||||
name := RandomNickname()
|
||||
t.Logf("name: %s", name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user