From 9bb835beaf4dbc88f795ff6c38ba7efe04130ac2 Mon Sep 17 00:00:00 2001 From: Leonid Nikitin Date: Sun, 8 Jun 2025 17:26:49 +0500 Subject: [PATCH] Make a choice of the encoder in the form Made a choice of the encoder by categories: video, audio and photo. --- internal/controller/convertor.go | 7 + internal/gui/view/convertor.go | 138 +++++++++++++++--- .../convertor/encoders/h264_nvenc/view.go | 64 ++++++++ .../view/convertor/encoders/libx264/view.go | 64 ++++++++ .../view/convertor/encoders/libx265/view.go | 64 ++++++++ internal/gui/window/layout.go | 3 +- internal/gui/window/main.go | 5 +- 7 files changed, 322 insertions(+), 23 deletions(-) create mode 100644 internal/gui/view/convertor/encoders/h264_nvenc/view.go create mode 100644 internal/gui/view/convertor/encoders/libx264/view.go create mode 100644 internal/gui/view/convertor/encoders/libx265/view.go diff --git a/internal/controller/convertor.go b/internal/controller/convertor.go index 898e3fd..aae050a 100644 --- a/internal/controller/convertor.go +++ b/internal/controller/convertor.go @@ -7,11 +7,18 @@ import ( ) func (c *controller) convertor() { + formats, err := c.app.GetConvertorService().GetSupportFormats() + if err != nil { + c.startWithError(err) + return + } + content := view.Convertor( c.window, c.addFileForConversion, c.app.GetSetting().GetDirectoryForSaving(), c.setDirectoryForSaving, + formats, ) c.window.SetContent(content) } diff --git a/internal/gui/view/convertor.go b/internal/gui/view/convertor.go index 8f52592..37e70ff 100644 --- a/internal/gui/view/convertor.go +++ b/internal/gui/view/convertor.go @@ -1,17 +1,18 @@ package view import ( - "errors" "fyne.io/fyne/v2" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/lang" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor/encoder" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg" + encoder2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view/convertor/encoders" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/window" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "image/color" "os" "path/filepath" @@ -22,12 +23,14 @@ func Convertor( addFileForConversion func(file ffmpeg.File), directoryForSavingPath string, directoryForSaving func(path string), + formats encoder.ConvertorFormatsContract, ) fyne.CanvasObject { form := newFormConvertor( window, addFileForConversion, directoryForSavingPath, directoryForSaving, + formats, ) converterVideoFilesTitle := lang.L("converterVideoFilesTitle") @@ -48,6 +51,7 @@ func newFormConvertor( addFileForConversion func(file ffmpeg.File), directoryForSavingPath string, directoryForSaving func(path string), + formats encoder.ConvertorFormatsContract, ) *formConvertor { f := widget.NewForm() f.SubmitText = lang.L("converterVideoFilesSubmitTitle") @@ -61,6 +65,12 @@ func newFormConvertor( fileForConversion := formConvertor.newFileForConversion() directoryForSavingButton := formConvertor.newDirectoryForSaving(directoryForSavingPath) + isOverwriteOutputFiles := false + checkboxOverwriteOutputFiles := widget.NewCheck(lang.L("checkboxOverwriteOutputFilesTitle"), func(b bool) { + isOverwriteOutputFiles = b + }) + checkboxOverwriteOutputFiles.SetChecked(isOverwriteOutputFiles) + selectEncoder := formConvertor.newSelectEncoder(formats) items := []*widget.FormItem{ { @@ -78,9 +88,25 @@ func newFormConvertor( { Widget: container.NewHScroll(directoryForSavingButton.message), }, + + { + Widget: checkboxOverwriteOutputFiles, + }, + { + Widget: selectEncoder.SelectFileType, + }, + { + Text: lang.L("selectFormat"), + Widget: selectEncoder.SelectFormat, + }, + { + Text: lang.L("selectEncoder"), + Widget: selectEncoder.SelectEncoder, + }, } formConvertor.form.Items = items formConvertor.items = items + formConvertor.changeEncoder(selectEncoder.Encoder) return formConvertor } @@ -92,17 +118,13 @@ func (f *formConvertor) getForm() *widget.Form { type fileForConversion struct { button *widget.Button message *canvas.Text - file *kernel.File - - changeCallbacks map[int]func(err error) + file *ffmpeg.File } func (f *formConvertor) newFileForConversion() *fileForConversion { message := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255}) fileForConversion := &fileForConversion{ message: message, - - changeCallbacks: map[int]func(err error){}, } buttonTitle := lang.L("choose") + "\n" + @@ -123,7 +145,6 @@ func (f *formConvertor) newFileForConversion() *fileForConversion { fileForConversion.message.Text = err.Error() fileForConversion.message.Refresh() }) - fileForConversion.eventSelectFile(err) return } if r == nil { @@ -136,8 +157,6 @@ func (f *formConvertor) newFileForConversion() *fileForConversion { Ext: r.URI().Extension(), }) - fileForConversion.eventSelectFile(nil) - listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path())) locationURI, _ = storage.ListerForURI(listableURI) }, locationURI) @@ -166,8 +185,6 @@ func (f *formConvertor) newFileForConversion() *fileForConversion { Ext: uri.Extension(), }) - fileForConversion.eventSelectFile(nil) - listableURI := storage.NewFileURI(filepath.Dir(uri.Path())) locationURI, _ = storage.ListerForURI(listableURI) } @@ -175,7 +192,6 @@ func (f *formConvertor) newFileForConversion() *fileForConversion { if isError { fileForConversion.message.Text = lang.L("errorDragAndDropFile") utils.SetStringErrorStyle(fileForConversion.message) - fileForConversion.eventSelectFile(errors.New(fileForConversion.message.Text)) } else { fyne.Do(func() { fileForConversion.message.Text = "" @@ -238,12 +254,98 @@ func (f *formConvertor) newDirectoryForSaving(directoryForSavingPath string) *di return directoryForSaving } -func (c *fileForConversion) addChangeCallback(callback func(err error)) { - c.changeCallbacks[len(c.changeCallbacks)] = callback +type selectEncoder struct { + SelectFileType *widget.RadioGroup + SelectFormat *widget.Select + SelectEncoder *widget.Select + Encoder encoder2.EncoderContract } -func (c *fileForConversion) eventSelectFile(err error) { - for _, changeCallback := range c.changeCallbacks { - changeCallback(err) +func (f *formConvertor) newSelectEncoder(formats encoder.ConvertorFormatsContract) *selectEncoder { + selectEncoder := &selectEncoder{} + + encoderMap := map[int]encoder2.EncoderDataContract{} + selectEncoder.SelectEncoder = widget.NewSelect([]string{}, func(s string) { + if encoderMap[selectEncoder.SelectEncoder.SelectedIndex()] == nil { + return + } + selectEncoderData := encoderMap[selectEncoder.SelectEncoder.SelectedIndex()] + selectEncoder.Encoder = selectEncoderData.NewEncoder() + f.changeEncoder(selectEncoder.Encoder) + }) + + formatSelected := "" + selectEncoder.SelectFormat = widget.NewSelect([]string{}, func(s string) { + if formatSelected == s { + return + } + formatSelected = s + format, err := formats.GetFormat(s) + if err != nil { + return + } + var encoderOptions []string + encoderMap = map[int]encoder2.EncoderDataContract{} + for _, e := range format.GetEncoders() { + encoderMap[len(encoderMap)] = e + encoderOptions = append(encoderOptions, lang.L("encoder_"+e.GetTitle())) + } + selectEncoder.SelectEncoder.SetOptions(encoderOptions) + selectEncoder.SelectEncoder.SetSelectedIndex(0) + }) + + var fileTypeOptions []string + for _, fileType := range encoder2.GetListFileType() { + fileTypeOptions = append(fileTypeOptions, fileType.Name()) } + + encoderGroupVideo := lang.L("encoderGroupVideo") + encoderGroupAudio := lang.L("encoderGroupAudio") + encoderGroupImage := lang.L("encoderGroupImage") + encoderGroup := map[string]string{ + encoderGroupVideo: "video", + encoderGroupAudio: "audio", + encoderGroupImage: "image", + } + selectEncoder.SelectFileType = widget.NewRadioGroup([]string{encoderGroupVideo, encoderGroupAudio, encoderGroupImage}, func(s string) { + groupCode := encoderGroup[s] + + var formatOptions []string + for _, f := range formats.GetFormats() { + if groupCode != f.GetFileType().Name() { + continue + } + formatOptions = append(formatOptions, f.GetTitle()) + } + selectEncoder.SelectFormat.SetOptions(formatOptions) + if groupCode == encoder2.FileType(encoder2.Video).Name() { + selectEncoder.SelectFormat.SetSelected("mp4") + } else { + selectEncoder.SelectFormat.SetSelectedIndex(0) + } + }) + selectEncoder.SelectFileType.Horizontal = true + selectEncoder.SelectFileType.Required = true + selectEncoder.SelectFileType.SetSelected(encoderGroupVideo) + + return selectEncoder +} + +func (f *formConvertor) changeEncoder(encoder encoder2.EncoderContract) { + var items []*widget.FormItem + + if encoders.Views[encoder.GetName()] != nil { + items = encoders.Views[encoder.GetName()](encoder) + } + + f.changeItems(items) +} + +func (f *formConvertor) changeItems(items []*widget.FormItem) { + fyne.Do(func() { + f.form.Items = f.items + f.form.Refresh() + f.form.Items = append(f.form.Items, items...) + f.form.Refresh() + }) } diff --git a/internal/gui/view/convertor/encoders/h264_nvenc/view.go b/internal/gui/view/convertor/encoders/h264_nvenc/view.go new file mode 100644 index 0000000..a506a12 --- /dev/null +++ b/internal/gui/view/convertor/encoders/h264_nvenc/view.go @@ -0,0 +1,64 @@ +package h264_nvenc + +import ( + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/lang" + "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/h264_nvenc" +) + +func View(encoder encoder.EncoderContract) []*widget.FormItem { + items := []*widget.FormItem{} + + items = append(items, presetParameter(encoder)...) + + return items +} + +func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem { + parameter, err := encoder.GetParameter("preset") + if err != nil { + return nil + } + + presets := map[string]string{} + presetsForSelect := []string{} + presetDefault := "" + + for _, name := range h264_nvenc.Presets { + title := name + presetsForSelect = append(presetsForSelect, name) + presets[title] = name + if name == parameter.Get() { + presetDefault = title + } + } + + elementSelect := widget.NewSelect(presetsForSelect, func(s string) { + if presets[s] == "" { + return + } + parameter.Set(presets[s]) + }) + elementSelect.SetSelected(presetDefault) + elementSelect.Hide() + + checkboxTitle := lang.L("parameterCheckbox") + elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) { + if b == true { + parameter.SetEnable() + elementSelect.Show() + return + } + parameter.SetDisable() + elementSelect.Hide() + }) + + return []*widget.FormItem{ + { + Text: lang.L("formPreset"), + Widget: container.NewVBox(elementCheckbox, elementSelect), + }, + } +} diff --git a/internal/gui/view/convertor/encoders/libx264/view.go b/internal/gui/view/convertor/encoders/libx264/view.go new file mode 100644 index 0000000..8457d94 --- /dev/null +++ b/internal/gui/view/convertor/encoders/libx264/view.go @@ -0,0 +1,64 @@ +package libx264 + +import ( + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/lang" + "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx264" +) + +func View(encoder encoder.EncoderContract) []*widget.FormItem { + items := []*widget.FormItem{} + + items = append(items, presetParameter(encoder)...) + + return items +} + +func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem { + parameter, err := encoder.GetParameter("preset") + if err != nil { + return nil + } + + presets := map[string]string{} + presetsForSelect := []string{} + presetDefault := "" + + for _, name := range libx264.Presets { + title := lang.L("preset_" + name) + presetsForSelect = append(presetsForSelect, title) + presets[title] = name + if name == parameter.Get() { + presetDefault = title + } + } + + elementSelect := widget.NewSelect(presetsForSelect, func(s string) { + if presets[s] == "" { + return + } + parameter.Set(presets[s]) + }) + elementSelect.SetSelected(presetDefault) + elementSelect.Hide() + + checkboxTitle := lang.L("parameterCheckbox") + elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) { + if b == true { + parameter.SetEnable() + elementSelect.Show() + return + } + parameter.SetDisable() + elementSelect.Hide() + }) + + return []*widget.FormItem{ + { + Text: lang.L("formPreset"), + Widget: container.NewVBox(elementCheckbox, elementSelect), + }, + } +} diff --git a/internal/gui/view/convertor/encoders/libx265/view.go b/internal/gui/view/convertor/encoders/libx265/view.go new file mode 100644 index 0000000..f0fccf0 --- /dev/null +++ b/internal/gui/view/convertor/encoders/libx265/view.go @@ -0,0 +1,64 @@ +package libx265 + +import ( + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/lang" + "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx265" +) + +func View(encoder encoder.EncoderContract) []*widget.FormItem { + items := []*widget.FormItem{} + + items = append(items, presetParameter(encoder)...) + + return items +} + +func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem { + parameter, err := encoder.GetParameter("preset") + if err != nil { + return nil + } + + presets := map[string]string{} + presetsForSelect := []string{} + presetDefault := "" + + for _, name := range libx265.Presets { + title := lang.L("preset_" + name) + presetsForSelect = append(presetsForSelect, title) + presets[title] = name + if name == parameter.Get() { + presetDefault = title + } + } + + elementSelect := widget.NewSelect(presetsForSelect, func(s string) { + if presets[s] == "" { + return + } + parameter.Set(presets[s]) + }) + elementSelect.SetSelected(presetDefault) + elementSelect.Hide() + + checkboxTitle := lang.L("parameterCheckbox") + elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) { + if b == true { + parameter.SetEnable() + elementSelect.Show() + return + } + parameter.SetDisable() + elementSelect.Hide() + }) + + return []*widget.FormItem{ + { + Text: lang.L("formPreset"), + Widget: container.NewVBox(elementCheckbox, elementSelect), + }, + } +} diff --git a/internal/gui/window/layout.go b/internal/gui/window/layout.go index b5423cd..33e4b25 100644 --- a/internal/gui/window/layout.go +++ b/internal/gui/window/layout.go @@ -7,7 +7,6 @@ import ( "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/application" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor" ) @@ -21,7 +20,7 @@ type layout struct { rContainer RightMainContainerContract } -func NewLayout(progressBarService application.ProgressBarContract, itemsToConvert convertor.ItemsToConvertContract, queueLayout QueueLayoutContract) LayoutContract { +func NewLayout(progressBarService convertor.ProgressBarContract, itemsToConvert convertor.ItemsToConvertContract, queueLayout QueueLayoutContract) LayoutContract { rContainer := newRightContainer(progressBarService.GetContainer(), itemsToConvert, queueLayout) layoutContainer := container.NewAdaptiveGrid(2, widget.NewLabel(""), rContainer.GetCanvasObject()) diff --git a/internal/gui/window/main.go b/internal/gui/window/main.go index 990c9d0..98ff5f4 100644 --- a/internal/gui/window/main.go +++ b/internal/gui/window/main.go @@ -3,7 +3,6 @@ package window import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/dialog" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor" "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils" ) @@ -22,13 +21,13 @@ type mainWindow struct { fyneWindow fyne.Window layout LayoutContract itemsToConvert convertor.ItemsToConvertContract - progressBarService application.ProgressBarContract + progressBarService convertor.ProgressBarContract queueLayout QueueLayoutContract } func NewMainWindow( fyneWindow fyne.Window, - progressBarService application.ProgressBarContract, + progressBarService convertor.ProgressBarContract, itemsToConvert convertor.ItemsToConvertContract, queueLayout QueueLayoutContract, ) WindowContract {