Files
ffui/progress.go
T

130 lines
2.8 KiB
Go
Raw Normal View History

2022-03-19 02:35:23 +02:00
package main
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net"
"os"
"os/exec"
2022-03-19 02:35:23 +02:00
"path"
"regexp"
"strconv"
"strings"
tea "github.com/charmbracelet/bubbletea"
)
func getProgressSocket(inFileName string, teaP *tea.Program) string {
cmd := exec.Command("ffprobe", "-show_format", "-show_streams", "-of", "json", inFileName)
probe, err := cmd.Output()
2022-03-19 02:35:23 +02:00
if err != nil {
panic(err)
}
totalDuration, err := probeDuration(string(probe))
2022-03-19 02:35:23 +02:00
if err != nil {
panic(err)
}
return TempSock(totalDuration, teaP)
}
func TempSock(totalDuration float64, teaP *tea.Program) string {
// serve
sockFileName := path.Join(os.TempDir(), fmt.Sprintf("%d_sock", rand.Int()))
l, err := net.Listen("unix", sockFileName)
if err != nil {
panic(err)
}
go func() {
re := regexp.MustCompile(`out_time_ms=(\d+)`)
speedRe := regexp.MustCompile(`speed=(\d+\.\d+x)`)
totalSizeRe := regexp.MustCompile(`total_size=(\d+)`)
2022-03-19 02:35:23 +02:00
fd, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
buf := make([]byte, 1024)
data := ""
progress := ""
estimate := 0
2022-03-19 02:35:23 +02:00
for {
_, err := fd.Read(buf)
if err != nil {
return
}
data = string(buf)
a := re.FindAllStringSubmatch(data, -1)
cp := ""
if len(a) > 0 && len(a[len(a)-1]) > 0 {
c, _ := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1])
cp = fmt.Sprintf("%.2f", float64(c)/totalDuration/1000000)
}
if strings.Contains(data, "progress=end") {
totalSize := totalSizeRe.FindString(data)
if len(totalSize) > 0 && strings.Split(totalSize, "=")[1] == "0" {
// Command failed. Don't send a finishedEncodingVideo message.
// encode() will take care of reporting the error.
continue
}
2022-03-19 02:35:23 +02:00
cp = "done"
teaP.Send(finishedEncodingVideo{})
return
}
if cp == "" {
cp = ".0"
}
if cp != progress {
progress = cp
progressFloat, err := strconv.ParseFloat(progress, 64)
if err == nil {
teaP.Send(updateProgress{
progress: progressFloat,
2022-03-19 02:35:23 +02:00
})
}
}
speedMatch := speedRe.FindString(data)
if len(speedMatch) > 0 {
trimmedSpeed := strings.TrimSuffix(strings.Split(speedMatch, "=")[1], "x")
speed, _ := strconv.ParseFloat(trimmedSpeed, 32)
progressFloat, _ := strconv.ParseFloat(progress, 64)
remainingDuration := totalDuration - (totalDuration * progressFloat)
estimate = int(remainingDuration / speed)
}
teaP.Send(updateEstimate{
estimate: estimate,
})
2022-03-19 02:35:23 +02:00
}
}()
return sockFileName
}
type probeFormat struct {
Duration string `json:"duration"`
}
type probeData struct {
Format probeFormat `json:"format"`
}
func probeDuration(a string) (float64, error) {
pd := probeData{}
err := json.Unmarshal([]byte(a), &pd)
if err != nil {
return 0, err
}
f, err := strconv.ParseFloat(pd.Format.Duration, 64)
if err != nil {
return 0, err
}
return f, nil
}