package ffmpeg import ( "errors" "fyne.io/fyne/v2/lang" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils" "os/exec" "strconv" "strings" "unicode" ) type FFprobeContract interface { GetPath() string 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) 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 }