package convertor import ( "bufio" "errors" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/lang" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg" "image/color" "io" "regexp" "strconv" "strings" ) type ProgressBarContract interface { GetContainer() *fyne.Container GetProgressbar(totalDuration float64, filePath string) ffmpeg.ProgressContract ProcessEndedWithError(errorText string) ProcessEndedWithSuccess(file *ffmpeg.File) } type progressBar struct { container *fyne.Container label *widget.Label progressbar *widget.ProgressBar errorBlock *container.Scroll messageError *canvas.Text statusMessage *canvas.Text buttonPlay *widget.Button ffmpegService ffmpeg.UtilitiesContract } func NewProgressBar(ffmpegService ffmpeg.UtilitiesContract) ProgressBarContract { label := widget.NewLabel("") progressbar := widget.NewProgressBar() statusMessage := canvas.NewText("", theme.Color(theme.ColorNamePrimary)) messageError := canvas.NewText("", theme.Color(theme.ColorNameError)) buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() { }) buttonPlay.Hide() errorBlock := container.NewHScroll(messageError) errorBlock.Hide() content := container.NewVBox( container.NewHScroll(label), progressbar, container.NewHScroll(container.NewHBox( buttonPlay, statusMessage, )), errorBlock, ) content.Hide() return &progressBar{ container: content, label: label, progressbar: progressbar, errorBlock: errorBlock, messageError: messageError, statusMessage: statusMessage, buttonPlay: buttonPlay, ffmpegService: ffmpegService, } } func (p *progressBar) GetContainer() *fyne.Container { return p.container } func (p *progressBar) GetProgressbar(totalDuration float64, filePath string) ffmpeg.ProgressContract { p.label.Text = filePath p.statusMessage.Color = theme.Color(theme.ColorNamePrimary) p.statusMessage.Text = lang.L("inProgressQueue") p.messageError.Text = "" fyne.Do(func() { p.buttonPlay.Hide() if p.errorBlock.Visible() { p.errorBlock.Hide() } p.statusMessage.Refresh() p.container.Refresh() p.errorBlock.Refresh() }) p.progressbar.Value = 0 return NewProgress(totalDuration, p.progressbar) } func (p *progressBar) ProcessEndedWithError(errorText string) { fyne.Do(func() { p.statusMessage.Color = theme.Color(theme.ColorNameError) p.statusMessage.Text = lang.L("errorQueue") p.messageError.Text = errorText p.errorBlock.Show() }) } func (p *progressBar) ProcessEndedWithSuccess(file *ffmpeg.File) { fyne.Do(func() { p.statusMessage.Color = color.RGBA{R: 49, G: 127, B: 114, A: 255} p.statusMessage.Text = lang.L("completedQueue") p.buttonPlay.Show() p.buttonPlay.OnTapped = func() { p.buttonPlay.Disable() go func() { ffplay, err := p.ffmpegService.GetFFplay() if err == nil { _ = ffplay.Play(file) } fyne.Do(func() { p.buttonPlay.Enable() }) }() } }) } type Progress struct { totalDuration float64 progressbar *widget.ProgressBar protocol string } func NewProgress(totalDuration float64, progressbar *widget.ProgressBar) ffmpeg.ProgressContract { return &Progress{ totalDuration: totalDuration, progressbar: progressbar, protocol: "pipe:", } } func (p *Progress) GetProtocole() string { return p.protocol } func (p *Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error { isProcessCompleted := false var errorText string p.progressbar.Value = 0 p.progressbar.Max = p.totalDuration fyne.Do(func() { p.progressbar.Refresh() }) progress := 0.0 go func() { scannerErr := bufio.NewReader(stdErr) for { line, _, err := scannerErr.ReadLine() if err != nil { if err == io.EOF { break } continue } data := strings.TrimSpace(string(line)) errorText = data } }() scannerOut := bufio.NewReader(stdOut) for { line, _, err := scannerOut.ReadLine() if err != nil { if err == io.EOF { break } continue } data := strings.TrimSpace(string(line)) if strings.Contains(data, "progress=end") { p.progressbar.Value = p.totalDuration fyne.Do(func() { p.progressbar.Refresh() }) isProcessCompleted = true break } re := regexp.MustCompile(`frame=(\d+)`) a := re.FindAllStringSubmatch(data, -1) if len(a) > 0 && len(a[len(a)-1]) > 0 { c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1]) if err != nil { continue } progress = float64(c) } if p.progressbar.Value != progress { p.progressbar.Value = progress fyne.Do(func() { p.progressbar.Refresh() }) } } if isProcessCompleted == false { if len(errorText) == 0 { errorText = lang.L("errorConverter") } return errors.New(errorText) } return nil }