Leonid Nikitin d7428683e4
Add GetFFprobeVersion method to retrieve FFprobe version details
Extended `FFprobeContract` with `GetVersion` to fetch FFprobe version. Implemented version extraction in `utilities` and `ffprobe` to support version retrieval functionality.
2025-06-09 23:25:13 +05:00

125 lines
2.9 KiB
Go

package ffmpeg
import (
"errors"
"fyne.io/fyne/v2/lang"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
"os/exec"
"regexp"
"strconv"
"strings"
"unicode"
)
type FFprobeContract interface {
GetPath() string
GetVersion() (string, error)
GetTotalDuration(file *File) (float64, error)
}
type ffprobe struct {
path string
}
func newFFprobe(path string) (FFprobeContract, error) {
if path == "" {
return nil, errors.New(lang.L("errorFFprobe"))
}
isCheck, err := checkFFprobePath(path)
if err != nil {
return nil, err
}
if isCheck == false {
return nil, errors.New(lang.L("errorFFprobe"))
}
return &ffprobe{
path: path,
}, nil
}
func (f *ffprobe) GetPath() string {
return f.path
}
func (f *ffprobe) GetVersion() (string, error) {
cmd := exec.Command(f.path, "-version")
utils.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
text := regexp.MustCompile("\r?\n").Split(strings.TrimSpace(string(out)), -1)
return text[0], nil
}
func (f *ffprobe) GetTotalDuration(file *File) (duration float64, err error) {
args := []string{"-v", "error", "-select_streams", "v:0", "-count_packets", "-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", file.Path}
cmd := exec.Command(f.path, args...)
utils.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
errString := strings.TrimSpace(string(out))
if len(errString) > 1 {
return 0, errors.New(errString)
}
return 0, err
}
frames := strings.TrimSpace(string(out))
if len(frames) == 0 {
return f.getAlternativeTotalDuration(file)
}
duration, err = strconv.ParseFloat(frames, 64)
if err != nil {
// fix .mts duration
return strconv.ParseFloat(getFirstDigits(frames), 64)
}
return duration, err
}
func (f *ffprobe) getAlternativeTotalDuration(file *File) (duration float64, err error) {
args := []string{"-v", "error", "-select_streams", "a:0", "-count_packets", "-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", file.Path}
cmd := exec.Command(f.path, args...)
utils.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
errString := strings.TrimSpace(string(out))
if len(errString) > 1 {
return 0, errors.New(errString)
}
return 0, err
}
frames := strings.TrimSpace(string(out))
if len(frames) == 0 {
return 0, errors.New("error getting number of frames")
}
return strconv.ParseFloat(frames, 64)
}
func checkFFprobePath(path string) (bool, error) {
cmd := exec.Command(path, "-version")
utils.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
return false, err
}
if strings.Contains(strings.TrimSpace(string(out)), "ffprobe") == false {
return false, nil
}
return true, nil
}
func getFirstDigits(s string) string {
result := ""
for _, r := range s {
if unicode.IsDigit(r) {
result += string(r)
} else {
break
}
}
return result
}