Added queues.

Reworked the architecture.
This commit is contained in:
2024-02-17 19:08:58 +06:00
parent c4ec958576
commit a1c9143685
23 changed files with 996 additions and 434 deletions

View File

@@ -1,173 +0,0 @@
package convertor
import (
"errors"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper"
"io"
"os/exec"
"regexp"
"strconv"
"strings"
)
type ServiceContract interface {
RunConvert(setting ConvertSetting, progress ProgressContract) error
GetTotalDuration(file *File) (float64, error)
GetFFmpegVesrion() (string, error)
GetFFprobeVersion() (string, error)
ChangeFFmpegPath(path string) (bool, error)
ChangeFFprobePath(path string) (bool, error)
GetRunningProcesses() map[int]*exec.Cmd
}
type ProgressContract interface {
GetProtocole() string
Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error
}
type FFPathUtilities struct {
FFmpeg string
FFprobe string
}
type runningProcesses struct {
items map[int]*exec.Cmd
numberOfStarts int
}
type Service struct {
ffPathUtilities *FFPathUtilities
runningProcesses runningProcesses
}
type File struct {
Path string
Name string
Ext string
}
type ConvertSetting struct {
VideoFileInput *File
VideoFileOut *File
OverwriteOutputFiles bool
}
type ConvertData struct {
totalDuration float64
}
func NewService(ffPathUtilities FFPathUtilities) *Service {
return &Service{
ffPathUtilities: &ffPathUtilities,
runningProcesses: runningProcesses{items: map[int]*exec.Cmd{}, numberOfStarts: 0},
}
}
func (s Service) RunConvert(setting ConvertSetting, progress ProgressContract) error {
overwriteOutputFiles := "-n"
if setting.OverwriteOutputFiles == true {
overwriteOutputFiles = "-y"
}
args := []string{overwriteOutputFiles, "-i", setting.VideoFileInput.Path, "-c:v", "libx264", "-progress", progress.GetProtocole(), setting.VideoFileOut.Path}
cmd := exec.Command(s.ffPathUtilities.FFmpeg, args...)
helper.PrepareBackgroundCommand(cmd)
stdOut, err := cmd.StdoutPipe()
if err != nil {
return err
}
stdErr, err := cmd.StderrPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}
index := s.runningProcesses.numberOfStarts
s.runningProcesses.numberOfStarts++
s.runningProcesses.items[index] = cmd
errProgress := progress.Run(stdOut, stdErr)
err = cmd.Wait()
delete(s.runningProcesses.items, index)
if errProgress != nil {
return errProgress
}
if err != nil {
return err
}
return nil
}
func (s Service) 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(s.ffPathUtilities.FFprobe, args...)
helper.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
}
return strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
}
func (s Service) GetFFmpegVesrion() (string, error) {
cmd := exec.Command(s.ffPathUtilities.FFmpeg, "-version")
helper.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 (s Service) GetFFprobeVersion() (string, error) {
cmd := exec.Command(s.ffPathUtilities.FFprobe, "-version")
helper.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 (s Service) ChangeFFmpegPath(path string) (bool, error) {
cmd := exec.Command(path, "-version")
helper.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
return false, err
}
if strings.Contains(strings.TrimSpace(string(out)), "ffmpeg") == false {
return false, nil
}
s.ffPathUtilities.FFmpeg = path
return true, nil
}
func (s Service) ChangeFFprobePath(path string) (bool, error) {
cmd := exec.Command(path, "-version")
helper.PrepareBackgroundCommand(cmd)
out, err := cmd.CombinedOutput()
if err != nil {
return false, err
}
if strings.Contains(strings.TrimSpace(string(out)), "ffprobe") == false {
return false, nil
}
s.ffPathUtilities.FFprobe = path
return true, nil
}
func (s Service) GetRunningProcesses() map[int]*exec.Cmd {
return s.runningProcesses.items
}

View File

@@ -5,11 +5,9 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/widget"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel"
"github.com/nicksnyder/go-i18n/v2/i18n"
"image/color"
"path/filepath"
@@ -17,7 +15,7 @@ import (
type ViewContract interface {
Main(
runConvert func(setting HandleConvertSetting, progressbar *widget.ProgressBar) error,
runConvert func(setting HandleConvertSetting),
)
SelectFFPath(
ffmpegPath string,
@@ -29,12 +27,11 @@ type ViewContract interface {
}
type View struct {
w fyne.Window
localizerService localizer.ServiceContract
app kernel.AppContract
}
type HandleConvertSetting struct {
VideoFileInput *File
VideoFileInput kernel.File
DirectoryForSave string
OverwriteOutputFiles bool
}
@@ -45,15 +42,14 @@ type enableFormConversionStruct struct {
form *widget.Form
}
func NewView(w fyne.Window, localizerService localizer.ServiceContract) *View {
func NewView(app kernel.AppContract) *View {
return &View{
w: w,
localizerService: localizerService,
app: app,
}
}
func (v View) Main(
runConvert func(setting HandleConvertSetting, progressbar *widget.ProgressBar) error,
runConvert func(setting HandleConvertSetting),
) {
form := &widget.Form{}
@@ -61,13 +57,11 @@ func (v View) Main(
conversionMessage.TextSize = 16
conversionMessage.TextStyle = fyne.TextStyle{Bold: true}
progress := widget.NewProgressBar()
fileVideoForConversion, fileVideoForConversionMessage, fileInput := v.getButtonFileVideoForConversion(form, progress, conversionMessage)
fileVideoForConversion, fileVideoForConversionMessage, fileInput := v.getButtonFileVideoForConversion(form, conversionMessage)
buttonForSelectedDir, buttonForSelectedDirMessage, pathToSaveDirectory := v.getButtonForSelectingDirectoryForSaving()
isOverwriteOutputFiles := false
checkboxOverwriteOutputFilesTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
checkboxOverwriteOutputFilesTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "checkboxOverwriteOutputFilesTitle",
})
checkboxOverwriteOutputFiles := widget.NewCheck(checkboxOverwriteOutputFilesTitle, func(b bool) {
@@ -76,14 +70,14 @@ func (v View) Main(
form.Items = []*widget.FormItem{
{
Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "fileVideoForConversionTitle"}),
Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "fileVideoForConversionTitle"}),
Widget: fileVideoForConversion,
},
{
Widget: container.NewHScroll(fileVideoForConversionMessage),
},
{
Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "buttonForSelectedDirTitle"}),
Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{MessageID: "buttonForSelectedDirTitle"}),
Widget: buttonForSelectedDir,
},
{
@@ -93,7 +87,7 @@ func (v View) Main(
Widget: checkboxOverwriteOutputFiles,
},
}
form.SubmitText = v.localizerService.GetMessage(&i18n.LocalizeConfig{
form.SubmitText = v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "converterVideoFilesSubmitTitle",
})
@@ -105,7 +99,7 @@ func (v View) Main(
form.OnSubmit = func() {
if len(*pathToSaveDirectory) == 0 {
showConversionMessage(conversionMessage, errors.New(v.localizerService.GetMessage(&i18n.LocalizeConfig{
showConversionMessage(conversionMessage, errors.New(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "errorSelectedFolderSave",
})))
enableFormConversion(enableFormConversionStruct)
@@ -118,71 +112,61 @@ func (v View) Main(
form.Disable()
setting := HandleConvertSetting{
VideoFileInput: fileInput,
VideoFileInput: *fileInput,
DirectoryForSave: *pathToSaveDirectory,
OverwriteOutputFiles: isOverwriteOutputFiles,
}
err := runConvert(setting, progress)
if err != nil {
showConversionMessage(conversionMessage, err)
enableFormConversion(enableFormConversionStruct)
return
}
runConvert(setting)
enableFormConversion(enableFormConversionStruct)
fileVideoForConversionMessage.Text = ""
form.Disable()
}
converterVideoFilesTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
converterVideoFilesTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "converterVideoFilesTitle",
})
v.w.SetContent(widget.NewCard(converterVideoFilesTitle, "", container.NewVBox(form, conversionMessage, progress)))
v.app.GetWindow().SetContent(widget.NewCard(converterVideoFilesTitle, "", container.NewVBox(form, conversionMessage)))
form.Disable()
}
func (v View) getButtonFileVideoForConversion(form *widget.Form, progress *widget.ProgressBar, conversionMessage *canvas.Text) (*widget.Button, *canvas.Text, *File) {
fileInput := &File{}
func (v View) getButtonFileVideoForConversion(form *widget.Form, conversionMessage *canvas.Text) (*widget.Button, *canvas.Text, *kernel.File) {
fileInput := &kernel.File{}
fileVideoForConversionMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
fileVideoForConversionMessage.TextSize = 16
fileVideoForConversionMessage.TextStyle = fyne.TextStyle{Bold: true}
buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "choose",
})
var locationURI fyne.ListableURI
button := widget.NewButton(buttonTitle, func() {
fileDialog := dialog.NewFileOpen(
func(r fyne.URIReadCloser, err error) {
if err != nil {
fileVideoForConversionMessage.Text = err.Error()
setStringErrorStyle(fileVideoForConversionMessage)
return
}
if r == nil {
return
}
v.app.GetWindow().NewFileOpen(func(r fyne.URIReadCloser, err error) {
if err != nil {
fileVideoForConversionMessage.Text = err.Error()
setStringErrorStyle(fileVideoForConversionMessage)
return
}
if r == nil {
return
}
fileInput.Path = r.URI().Path()
fileInput.Name = r.URI().Name()
fileInput.Ext = r.URI().Extension()
fileInput.Path = r.URI().Path()
fileInput.Name = r.URI().Name()
fileInput.Ext = r.URI().Extension()
fileVideoForConversionMessage.Text = r.URI().Path()
setStringSuccessStyle(fileVideoForConversionMessage)
fileVideoForConversionMessage.Text = r.URI().Path()
setStringSuccessStyle(fileVideoForConversionMessage)
form.Enable()
progress.Value = 0
progress.Refresh()
conversionMessage.Text = ""
form.Enable()
conversionMessage.Text = ""
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
locationURI, err = storage.ListerForURI(listableURI)
}, v.w)
helper.FileDialogResize(fileDialog, v.w)
fileDialog.Show()
if locationURI != nil {
fileDialog.SetLocation(locationURI)
}
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
locationURI, err = storage.ListerForURI(listableURI)
}, locationURI)
})
return button, fileVideoForConversionMessage, fileInput
@@ -196,36 +180,30 @@ func (v View) getButtonForSelectingDirectoryForSaving() (button *widget.Button,
path := ""
dirPath = &path
buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "choose",
})
var locationURI fyne.ListableURI
button = widget.NewButton(buttonTitle, func() {
fileDialog := dialog.NewFolderOpen(
func(r fyne.ListableURI, err error) {
if err != nil {
buttonMessage.Text = err.Error()
setStringErrorStyle(buttonMessage)
return
}
if r == nil {
return
}
v.app.GetWindow().NewFolderOpen(func(r fyne.ListableURI, err error) {
if err != nil {
buttonMessage.Text = err.Error()
setStringErrorStyle(buttonMessage)
return
}
if r == nil {
return
}
path = r.Path()
path = r.Path()
buttonMessage.Text = r.Path()
setStringSuccessStyle(buttonMessage)
locationURI, _ = storage.ListerForURI(r)
buttonMessage.Text = r.Path()
setStringSuccessStyle(buttonMessage)
locationURI, _ = storage.ListerForURI(r)
}, v.w)
helper.FileDialogResize(fileDialog, v.w)
fileDialog.Show()
if locationURI != nil {
fileDialog.SetLocation(locationURI)
}
}, locationURI)
})
return

View File

@@ -4,10 +4,8 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/storage"
"fyne.io/fyne/v2/widget"
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper"
"github.com/nicksnyder/go-i18n/v2/i18n"
"image/color"
"net/url"
@@ -37,13 +35,13 @@ func (v View) SelectFFPath(
form := &widget.Form{
Items: []*widget.FormItem{
{
Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{
Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "titleDownloadLink",
}),
Widget: link,
},
{
Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{
Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "pathToFfmpeg",
}),
Widget: buttonFFmpeg,
@@ -52,7 +50,7 @@ func (v View) SelectFFPath(
Widget: container.NewHScroll(buttonFFmpegMessage),
},
{
Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{
Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "pathToFfprobe",
}),
Widget: buttonFFprobe,
@@ -64,7 +62,7 @@ func (v View) SelectFFPath(
Widget: errorMessage,
},
},
SubmitText: v.localizerService.GetMessage(&i18n.LocalizeConfig{
SubmitText: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "save",
}),
OnSubmit: func() {
@@ -76,15 +74,15 @@ func (v View) SelectFFPath(
}
if cancel != nil {
form.OnCancel = cancel
form.CancelText = v.localizerService.GetMessage(&i18n.LocalizeConfig{
form.CancelText = v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "cancel",
})
}
selectFFPathTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
selectFFPathTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "selectFFPathTitle",
})
v.w.SetContent(widget.NewCard(selectFFPathTitle, "", container.NewVBox(
v.app.GetWindow().SetContent(widget.NewCard(selectFFPathTitle, "", container.NewVBox(
form,
v.blockDownloadFFmpeg(donwloadFFmpeg),
)))
@@ -97,7 +95,7 @@ func (v View) getButtonSelectFile(path string) (filePath *string, button *widget
buttonMessage.TextSize = 16
buttonMessage.TextStyle = fyne.TextStyle{Bold: true}
buttonTitle := v.localizerService.GetMessage(&i18n.LocalizeConfig{
buttonTitle := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{
MessageID: "choose",
})
@@ -108,30 +106,24 @@ func (v View) getButtonSelectFile(path string) (filePath *string, button *widget
}
button = widget.NewButton(buttonTitle, func() {
fileDialog := dialog.NewFileOpen(
func(r fyne.URIReadCloser, err error) {
if err != nil {
buttonMessage.Text = err.Error()
setStringErrorStyle(buttonMessage)
return
}
if r == nil {
return
}
v.app.GetWindow().NewFileOpen(func(r fyne.URIReadCloser, err error) {
if err != nil {
buttonMessage.Text = err.Error()
setStringErrorStyle(buttonMessage)
return
}
if r == nil {
return
}
path = r.URI().Path()
path = r.URI().Path()
buttonMessage.Text = r.URI().Path()
setStringSuccessStyle(buttonMessage)
buttonMessage.Text = r.URI().Path()
setStringSuccessStyle(buttonMessage)
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
locationURI, _ = storage.ListerForURI(listableURI)
}, v.w)
helper.FileDialogResize(fileDialog, v.w)
fileDialog.Show()
if locationURI != nil {
fileDialog.SetLocation(locationURI)
}
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
locationURI, _ = storage.ListerForURI(listableURI)
}, locationURI)
})
return