diff --git a/README.md b/README.md index 769b0cd..7ab1146 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ ## Установка через fyne: 1. go install fyne.io/fyne/v2/cmd/fyne@latest -2. fyne get git.kor-elf.net/kor-elf/gui-for-ffmpeg/src +2. fyne get git.kor-elf.net/kor-elf/gui-for-ffmpeg ## Скомпилировать через исходники: 1. git clone https://git.kor-elf.net/kor-elf/gui-for-ffmpeg.git -2. Переходим в папку проекта и там переходим в папку src: **cd gui-for-ffmpeg/src** +2. Переходим в папку проекта и там переходим в папку src: **cd gui-for-ffmpeg** 3. Ознакамливаемся, что нужно ещё установить для Вашей ОС для простого запуска (через go run) тут: https://docs.fyne.io/started/ 4. *(не обязательный шаг)* Просто запустить можно так: **go run main.go** 5. go install github.com/fyne-io/fyne-cross@latest @@ -35,9 +35,8 @@ ## Работа с переводами: 1. go install -v github.com/nicksnyder/go-i18n/v2/goi18n@latest -2. Переходим в папке проекта в папку src: **cd ./src** -3. goi18n merge -sourceLanguage ru -outdir languages languages/active.\*.toml languages/translate.\*.toml -4. В файлах **languages/translate.\*.toml** переводим текст на нужный язык -5. goi18n merge -sourceLanguage ru -outdir languages languages/active.\*.toml languages/translate.\*.toml +2. goi18n merge -sourceLanguage ru -outdir languages languages/active.\*.toml languages/translate.\*.toml +3. В файлах **languages/translate.\*.toml** переводим текст на нужный язык +4. goi18n merge -sourceLanguage ru -outdir languages languages/active.\*.toml languages/translate.\*.toml Более подробно можно почитать тут: https://github.com/nicksnyder/go-i18n \ No newline at end of file diff --git a/src/convertor/repository.go b/convertor/repository.go similarity index 94% rename from src/convertor/repository.go rename to convertor/repository.go index 3f26bf5..e31f64a 100644 --- a/src/convertor/repository.go +++ b/convertor/repository.go @@ -1,7 +1,7 @@ package convertor import ( - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/setting" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/setting" ) type RepositoryContract interface { diff --git a/src/convertor/view.go b/convertor/view.go similarity index 56% rename from src/convertor/view.go rename to convertor/view.go index 7a18160..0510768 100644 --- a/src/convertor/view.go +++ b/convertor/view.go @@ -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/src/helper" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/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 diff --git a/src/convertor/view_setting.go b/convertor/view_setting.go similarity index 65% rename from src/convertor/view_setting.go rename to convertor/view_setting.go index c09acba..62e8ad5 100644 --- a/src/convertor/view_setting.go +++ b/convertor/view_setting.go @@ -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/src/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 diff --git a/src/convertor/view_setting_button_download_ffmpeg_anyos.go b/convertor/view_setting_button_download_ffmpeg_anyos.go similarity index 100% rename from src/convertor/view_setting_button_download_ffmpeg_anyos.go rename to convertor/view_setting_button_download_ffmpeg_anyos.go diff --git a/src/convertor/view_setting_button_download_ffmpeg_windows.go b/convertor/view_setting_button_download_ffmpeg_windows.go similarity index 85% rename from src/convertor/view_setting_button_download_ffmpeg_windows.go rename to convertor/view_setting_button_download_ffmpeg_windows.go index a573284..2dcb47a 100644 --- a/src/convertor/view_setting_button_download_ffmpeg_windows.go +++ b/convertor/view_setting_button_download_ffmpeg_windows.go @@ -29,7 +29,7 @@ func (v View) blockDownloadFFmpeg( var buttonDownloadFFmpeg *widget.Button - buttonDownloadFFmpeg = widget.NewButton(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + buttonDownloadFFmpeg = widget.NewButton(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "download", }), func() { buttonDownloadFFmpeg.Disable() @@ -42,13 +42,13 @@ func (v View) blockDownloadFFmpeg( buttonDownloadFFmpeg.Enable() }) - downloadFFmpegFromSiteMessage := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + downloadFFmpegFromSiteMessage := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "downloadFFmpegFromSite", }) return container.NewVBox( canvas.NewLine(colornames.Darkgreen), - widget.NewCard(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + widget.NewCard(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "buttonDownloadFFmpeg", }), "", container.NewVBox( widget.NewRichTextFromMarkdown( diff --git a/src/data/.gitignore b/data/.gitignore similarity index 100% rename from src/data/.gitignore rename to data/.gitignore diff --git a/error/view.go b/error/view.go new file mode 100644 index 0000000..4845ab0 --- /dev/null +++ b/error/view.go @@ -0,0 +1,64 @@ +package error + +import ( + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "github.com/nicksnyder/go-i18n/v2/i18n" +) + +type ViewContract interface { + PanicError(err error) +} + +type View struct { + app kernel.AppContract +} + +func NewView(app kernel.AppContract) *View { + return &View{ + app: app, + } +} + +func (v View) PanicError(err error) { + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "error", + }) + + v.app.GetWindow().SetContent(container.NewBorder( + container.NewVBox( + widget.NewLabel(messageHead), + widget.NewLabel(err.Error()), + ), + nil, + nil, + nil, + localizer.LanguageSelectionForm(v.app.GetLocalizerService(), func(lang kernel.Lang) { + v.PanicError(err) + }), + )) +} + +func (v View) PanicErrorWriteDirectoryData() { + message := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorDatabase", + }) + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "error", + }) + + v.app.GetWindow().SetContent(container.NewBorder( + container.NewVBox( + widget.NewLabel(messageHead), + widget.NewLabel(message), + ), + nil, + nil, + nil, + localizer.LanguageSelectionForm(v.app.GetLocalizerService(), func(lang kernel.Lang) { + v.PanicErrorWriteDirectoryData() + }), + )) +} diff --git a/src/go.mod b/go.mod similarity index 97% rename from src/go.mod rename to go.mod index 66edcf3..89427e3 100644 --- a/src/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module git.kor-elf.net/kor-elf/gui-for-ffmpeg/src +module git.kor-elf.net/kor-elf/gui-for-ffmpeg go 1.21 diff --git a/src/go.sum b/go.sum similarity index 100% rename from src/go.sum rename to go.sum diff --git a/handler/convertor.go b/handler/convertor.go new file mode 100644 index 0000000..909e908 --- /dev/null +++ b/handler/convertor.go @@ -0,0 +1,130 @@ +package handler + +import ( + "errors" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" + "github.com/nicksnyder/go-i18n/v2/i18n" +) + +type ConvertorHandlerContract interface { + MainConvertor() + FfPathSelection() + GetFfmpegVersion() (string, error) + GetFfprobeVersion() (string, error) +} + +type ConvertorHandler struct { + app kernel.AppContract + convertorView convertor.ViewContract + convertorRepository convertor.RepositoryContract +} + +func NewConvertorHandler( + app kernel.AppContract, + convertorView convertor.ViewContract, + convertorRepository convertor.RepositoryContract, +) *ConvertorHandler { + return &ConvertorHandler{ + app: app, + convertorView: convertorView, + convertorRepository: convertorRepository, + } +} + +func (h ConvertorHandler) MainConvertor() { + if h.checkingFFPathUtilities() == true { + h.convertorView.Main(h.runConvert) + return + } + h.convertorView.SelectFFPath("", "", h.saveSettingFFPath, nil, h.downloadFFmpeg) +} + +func (h ConvertorHandler) FfPathSelection() { + ffmpeg, _ := h.convertorRepository.GetPathFfmpeg() + ffprobe, _ := h.convertorRepository.GetPathFfprobe() + h.convertorView.SelectFFPath(ffmpeg, ffprobe, h.saveSettingFFPath, h.MainConvertor, h.downloadFFmpeg) +} + +func (h ConvertorHandler) GetFfmpegVersion() (string, error) { + return h.app.GetConvertorService().GetFFmpegVesrion() +} + +func (h ConvertorHandler) GetFfprobeVersion() (string, error) { + return h.app.GetConvertorService().GetFFprobeVersion() +} + +func (h ConvertorHandler) runConvert(setting convertor.HandleConvertSetting) { + h.app.GetQueue().Add(&kernel.ConvertSetting{ + VideoFileInput: setting.VideoFileInput, + VideoFileOut: kernel.File{ + Path: setting.DirectoryForSave + helper.PathSeparator() + setting.VideoFileInput.Name + ".mp4", + Name: setting.VideoFileInput.Name, + Ext: ".mp4", + }, + OverwriteOutputFiles: setting.OverwriteOutputFiles, + }) +} + +func (h ConvertorHandler) checkingFFPathUtilities() bool { + if h.checkingFFPath() == true { + return true + } + + pathsToFF := getPathsToFF() + for _, item := range pathsToFF { + ffmpegChecking, _ := h.app.GetConvertorService().ChangeFFmpegPath(item.FFmpeg) + if ffmpegChecking == false { + continue + } + ffprobeChecking, _ := h.app.GetConvertorService().ChangeFFprobePath(item.FFprobe) + if ffprobeChecking == false { + continue + } + _, _ = h.convertorRepository.SavePathFfmpeg(item.FFmpeg) + _, _ = h.convertorRepository.SavePathFfprobe(item.FFprobe) + return true + } + + return false +} + +func (h ConvertorHandler) saveSettingFFPath(ffmpegPath string, ffprobePath string) error { + ffmpegChecking, _ := h.app.GetConvertorService().ChangeFFmpegPath(ffmpegPath) + if ffmpegChecking == false { + errorText := h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorFFmpeg", + }) + return errors.New(errorText) + } + + ffprobeChecking, _ := h.app.GetConvertorService().ChangeFFprobePath(ffprobePath) + if ffprobeChecking == false { + errorText := h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorFFprobe", + }) + return errors.New(errorText) + } + + _, _ = h.convertorRepository.SavePathFfmpeg(ffmpegPath) + _, _ = h.convertorRepository.SavePathFfprobe(ffprobePath) + + h.MainConvertor() + + return nil +} + +func (h ConvertorHandler) checkingFFPath() bool { + _, err := h.app.GetConvertorService().GetFFmpegVesrion() + if err != nil { + return false + } + + _, err = h.app.GetConvertorService().GetFFprobeVersion() + if err != nil { + return false + } + + return true +} diff --git a/src/handler/convertor_anyos.go b/handler/convertor_anyos.go similarity index 54% rename from src/handler/convertor_anyos.go rename to handler/convertor_anyos.go index 16b85a0..409c524 100644 --- a/src/handler/convertor_anyos.go +++ b/handler/convertor_anyos.go @@ -6,11 +6,11 @@ package handler import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" ) -func getPathsToFF() []convertor.FFPathUtilities { - return []convertor.FFPathUtilities{{"ffmpeg/bin/ffmpeg", "ffmpeg/bin/ffprobe"}, {"ffmpeg", "ffprobe"}} +func getPathsToFF() []kernel.FFPathUtilities { + return []kernel.FFPathUtilities{{"ffmpeg/bin/ffmpeg", "ffmpeg/bin/ffprobe"}, {"ffmpeg", "ffprobe"}} } func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progressMessage *canvas.Text) (err error) { diff --git a/src/handler/convertor_windows.go b/handler/convertor_windows.go similarity index 87% rename from src/handler/convertor_windows.go rename to handler/convertor_windows.go index 79732c5..9ea6702 100644 --- a/src/handler/convertor_windows.go +++ b/handler/convertor_windows.go @@ -8,7 +8,7 @@ import ( "errors" "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/convertor" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" "io" "net/http" @@ -17,8 +17,8 @@ import ( "strings" ) -func getPathsToFF() []convertor.FFPathUtilities { - return []convertor.FFPathUtilities{{"ffmpeg\\bin\\ffmpeg.exe", "ffmpeg\\bin\\ffprobe.exe"}} +func getPathsToFF() []kernel.FFPathUtilities { + return []kernel.FFPathUtilities{{"ffmpeg\\bin\\ffmpeg.exe", "ffmpeg\\bin\\ffprobe.exe"}} } func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progressMessage *canvas.Text) (err error) { @@ -29,7 +29,7 @@ func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progre return err } } - progressMessage.Text = h.localizerService.GetMessage(&i18n.LocalizeConfig{ + progressMessage.Text = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "downloadRun", }) progressMessage.Refresh() @@ -38,7 +38,7 @@ func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progre return err } - progressMessage.Text = h.localizerService.GetMessage(&i18n.LocalizeConfig{ + progressMessage.Text = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "unzipRun", }) progressMessage.Refresh() @@ -48,7 +48,7 @@ func (h ConvertorHandler) downloadFFmpeg(progressBar *widget.ProgressBar, progre } _ = os.Remove("ffmpeg/ffmpeg.zip") - progressMessage.Text = h.localizerService.GetMessage(&i18n.LocalizeConfig{ + progressMessage.Text = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "testFF", }) progressMessage.Refresh() diff --git a/src/handler/main.go b/handler/main.go similarity index 72% rename from src/handler/main.go rename to handler/main.go index 7253b05..e2e6398 100644 --- a/src/handler/main.go +++ b/handler/main.go @@ -1,27 +1,28 @@ package handler import ( - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" ) type MainHandler struct { + app kernel.AppContract convertorHandler ConvertorHandlerContract menuHandler MenuHandlerContract localizerRepository localizer.RepositoryContract - localizerService localizer.ServiceContract } func NewMainHandler( + app kernel.AppContract, convertorHandler ConvertorHandlerContract, menuHandler MenuHandlerContract, localizerRepository localizer.RepositoryContract, - localizerService localizer.ServiceContract, ) *MainHandler { return &MainHandler{ + app: app, convertorHandler: convertorHandler, menuHandler: menuHandler, localizerRepository: localizerRepository, - localizerService: localizerService, } } @@ -31,7 +32,7 @@ func (h MainHandler) Start() { h.menuHandler.LanguageSelection() return } - _ = h.localizerService.SetCurrentLanguageByCode(language) + _ = h.app.GetLocalizerService().SetCurrentLanguageByCode(language) h.convertorHandler.MainConvertor() } diff --git a/handler/menu.go b/handler/menu.go new file mode 100644 index 0000000..ca38d52 --- /dev/null +++ b/handler/menu.go @@ -0,0 +1,149 @@ +package handler + +import ( + "fyne.io/fyne/v2" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/menu" + "github.com/nicksnyder/go-i18n/v2/i18n" +) + +type MenuHandlerContract interface { + GetMainMenu() *fyne.MainMenu + LanguageSelection() +} + +type MenuHandler struct { + app kernel.AppContract + convertorHandler ConvertorHandlerContract + menuView menu.ViewContract + localizerView localizer.ViewContract + localizerRepository localizer.RepositoryContract + localizerListener localizerListenerContract +} + +func NewMenuHandler( + app kernel.AppContract, + convertorHandler ConvertorHandlerContract, + menuView menu.ViewContract, + localizerView localizer.ViewContract, + localizerRepository localizer.RepositoryContract, + localizerListener localizerListenerContract, +) *MenuHandler { + return &MenuHandler{ + app: app, + convertorHandler: convertorHandler, + menuView: menuView, + localizerView: localizerView, + localizerRepository: localizerRepository, + localizerListener: localizerListener, + } +} + +func (h MenuHandler) GetMainMenu() *fyne.MainMenu { + settings := h.getMenuSettings() + help := h.getMenuHelp() + + return fyne.NewMainMenu(settings, help) +} + +func (h MenuHandler) getMenuSettings() *fyne.Menu { + quit := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "exit", + }), nil) + quit.IsQuit = true + h.localizerListener.AddMenuItem("exit", quit) + + languageSelection := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "changeLanguage", + }), h.LanguageSelection) + h.localizerListener.AddMenuItem("changeLanguage", languageSelection) + + ffPathSelection := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "changeFFPath", + }), h.convertorHandler.FfPathSelection) + h.localizerListener.AddMenuItem("changeFFPath", ffPathSelection) + + settings := fyne.NewMenu(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "settings", + }), languageSelection, ffPathSelection, quit) + h.localizerListener.AddMenu("settings", settings) + + return settings +} + +func (h MenuHandler) getMenuHelp() *fyne.Menu { + about := fyne.NewMenuItem(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "about", + }), h.openAbout) + h.localizerListener.AddMenuItem("about", about) + + help := fyne.NewMenu(h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "help", + }), about) + h.localizerListener.AddMenu("help", help) + + return help +} + +func (h MenuHandler) openAbout() { + ffmpeg, err := h.convertorHandler.GetFfmpegVersion() + if err != nil { + ffmpeg = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorFFmpegVersion", + }) + } + ffprobe, err := h.convertorHandler.GetFfprobeVersion() + if err != nil { + ffprobe = h.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorFFprobeVersion", + }) + } + + h.menuView.About(ffmpeg, ffprobe) +} + +func (h MenuHandler) LanguageSelection() { + h.localizerView.LanguageSelection(func(lang kernel.Lang) { + _, _ = h.localizerRepository.Save(lang.Code) + h.convertorHandler.MainConvertor() + }) +} + +type menuItems struct { + menuItem map[string]*fyne.MenuItem + menu map[string]*fyne.Menu +} + +type LocalizerListener struct { + menuItems *menuItems +} + +type localizerListenerContract interface { + AddMenu(messageID string, menu *fyne.Menu) + AddMenuItem(messageID string, menuItem *fyne.MenuItem) +} + +func NewLocalizerListener() *LocalizerListener { + return &LocalizerListener{ + &menuItems{menuItem: map[string]*fyne.MenuItem{}, menu: map[string]*fyne.Menu{}}, + } +} + +func (l LocalizerListener) AddMenu(messageID string, menu *fyne.Menu) { + l.menuItems.menu[messageID] = menu +} + +func (l LocalizerListener) AddMenuItem(messageID string, menuItem *fyne.MenuItem) { + l.menuItems.menuItem[messageID] = menuItem +} + +func (l LocalizerListener) Change(localizerService kernel.LocalizerContract) { + for messageID, menu := range l.menuItems.menuItem { + menu.Label = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) + } + for messageID, menu := range l.menuItems.menu { + menu.Label = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) + menu.Refresh() + } +} diff --git a/src/helper/helper.go b/helper/helper.go similarity index 100% rename from src/helper/helper.go rename to helper/helper.go diff --git a/src/helper/path_separator.go b/helper/path_separator.go similarity index 100% rename from src/helper/path_separator.go rename to helper/path_separator.go diff --git a/src/helper/path_separator_window.go b/helper/path_separator_window.go similarity index 100% rename from src/helper/path_separator_window.go rename to helper/path_separator_window.go diff --git a/src/helper/prepare_background_command.go b/helper/prepare_background_command.go similarity index 100% rename from src/helper/prepare_background_command.go rename to helper/prepare_background_command.go diff --git a/src/helper/prepare_background_command_windows.go b/helper/prepare_background_command_windows.go similarity index 100% rename from src/helper/prepare_background_command_windows.go rename to helper/prepare_background_command_windows.go diff --git a/src/icon.png b/icon.png similarity index 100% rename from src/icon.png rename to icon.png diff --git a/images/screenshot-gui-for-ffmpeg.png b/images/screenshot-gui-for-ffmpeg.png index 8f76a42..2183563 100644 Binary files a/images/screenshot-gui-for-ffmpeg.png and b/images/screenshot-gui-for-ffmpeg.png differ diff --git a/kernel/app.go b/kernel/app.go new file mode 100644 index 0000000..54a82f1 --- /dev/null +++ b/kernel/app.go @@ -0,0 +1,105 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "time" +) + +type AppContract interface { + GetAppFyne() fyne.App + GetWindow() WindowContract + GetQueue() QueueListContract + GetLocalizerService() LocalizerContract + GetConvertorService() ConvertorContract + AfterClosing() + RunConvertor() +} + +type App struct { + AppFyne fyne.App + Window WindowContract + Queue QueueListContract + + localizerService LocalizerContract + convertorService ConvertorContract +} + +func NewApp( + metadata *fyne.AppMetadata, + localizerService LocalizerContract, + queue QueueListContract, + queueLayoutObject QueueLayoutObjectContract, + convertorService ConvertorContract, +) *App { + app.SetMetadata(*metadata) + a := app.New() + + return &App{ + AppFyne: a, + Window: newWindow(a.NewWindow("GUI for FFmpeg"), NewLayout(queueLayoutObject, localizerService)), + Queue: queue, + + localizerService: localizerService, + convertorService: convertorService, + } +} + +func (a App) GetAppFyne() fyne.App { + return a.AppFyne +} + +func (a App) GetQueue() QueueListContract { + return a.Queue +} + +func (a App) GetWindow() WindowContract { + return a.Window +} + +func (a App) GetLocalizerService() LocalizerContract { + return a.localizerService +} + +func (a App) GetConvertorService() ConvertorContract { + return a.convertorService +} + +func (a App) AfterClosing() { + for _, cmd := range a.convertorService.GetRunningProcesses() { + _ = cmd.Process.Kill() + } +} + +func (a App) RunConvertor() { + go func() { + for { + time.Sleep(time.Millisecond * 3000) + queueId, queue := a.Queue.Next() + if queue == nil { + continue + } + queue.Status = StatusType(InProgress) + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + + totalDuration, err := a.convertorService.GetTotalDuration(&queue.Setting.VideoFileInput) + if err != nil { + queue.Status = StatusType(Error) + queue.Error = err + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + continue + } + progress := a.Window.GetLayout().NewProgressbar(queueId, totalDuration) + + err = a.convertorService.RunConvert(*queue.Setting, progress) + if err != nil { + queue.Status = StatusType(Error) + queue.Error = err + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + continue + } + queue.Status = StatusType(Completed) + a.Window.GetLayout().ChangeQueueStatus(queueId, queue) + } + }() +} diff --git a/src/convertor/service.go b/kernel/convertor.go similarity index 79% rename from src/convertor/service.go rename to kernel/convertor.go index bdeb256..8441fa1 100644 --- a/src/convertor/service.go +++ b/kernel/convertor.go @@ -1,8 +1,8 @@ -package convertor +package kernel import ( "errors" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/helper" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" "io" "os/exec" "regexp" @@ -10,7 +10,7 @@ import ( "strings" ) -type ServiceContract interface { +type ConvertorContract interface { RunConvert(setting ConvertSetting, progress ProgressContract) error GetTotalDuration(file *File) (float64, error) GetFFmpegVesrion() (string, error) @@ -35,35 +35,23 @@ type runningProcesses struct { numberOfStarts int } -type Service struct { +type Convertor 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, +func NewService(ffPathUtilities *FFPathUtilities) *Convertor { + return &Convertor{ + ffPathUtilities: ffPathUtilities, runningProcesses: runningProcesses{items: map[int]*exec.Cmd{}, numberOfStarts: 0}, } } -func (s Service) RunConvert(setting ConvertSetting, progress ProgressContract) error { +func (s Convertor) RunConvert(setting ConvertSetting, progress ProgressContract) error { overwriteOutputFiles := "-n" if setting.OverwriteOutputFiles == true { overwriteOutputFiles = "-y" @@ -103,7 +91,7 @@ func (s Service) RunConvert(setting ConvertSetting, progress ProgressContract) e return nil } -func (s Service) GetTotalDuration(file *File) (duration float64, err error) { +func (s Convertor) 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) @@ -118,7 +106,7 @@ func (s Service) GetTotalDuration(file *File) (duration float64, err error) { return strconv.ParseFloat(strings.TrimSpace(string(out)), 64) } -func (s Service) GetFFmpegVesrion() (string, error) { +func (s Convertor) GetFFmpegVesrion() (string, error) { cmd := exec.Command(s.ffPathUtilities.FFmpeg, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -129,7 +117,7 @@ func (s Service) GetFFmpegVesrion() (string, error) { return text[0], nil } -func (s Service) GetFFprobeVersion() (string, error) { +func (s Convertor) GetFFprobeVersion() (string, error) { cmd := exec.Command(s.ffPathUtilities.FFprobe, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -140,7 +128,7 @@ func (s Service) GetFFprobeVersion() (string, error) { return text[0], nil } -func (s Service) ChangeFFmpegPath(path string) (bool, error) { +func (s Convertor) ChangeFFmpegPath(path string) (bool, error) { cmd := exec.Command(path, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -154,7 +142,7 @@ func (s Service) ChangeFFmpegPath(path string) (bool, error) { return true, nil } -func (s Service) ChangeFFprobePath(path string) (bool, error) { +func (s Convertor) ChangeFFprobePath(path string) (bool, error) { cmd := exec.Command(path, "-version") helper.PrepareBackgroundCommand(cmd) out, err := cmd.CombinedOutput() @@ -168,6 +156,6 @@ func (s Service) ChangeFFprobePath(path string) (bool, error) { return true, nil } -func (s Service) GetRunningProcesses() map[int]*exec.Cmd { +func (s Convertor) GetRunningProcesses() map[int]*exec.Cmd { return s.runningProcesses.items } diff --git a/kernel/error.go b/kernel/error.go new file mode 100644 index 0000000..7f03ea1 --- /dev/null +++ b/kernel/error.go @@ -0,0 +1,20 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" +) + +func PanicErrorLang(err error, metadata *fyne.AppMetadata) { + app.SetMetadata(*metadata) + a := app.New() + window := a.NewWindow("GUI for FFmpeg") + window.SetContent(container.NewVBox( + widget.NewLabel("Произошла ошибка!"), + widget.NewLabel("произошла ошибка при получении языковых переводах. \n\r"+err.Error()), + )) + window.ShowAndRun() + panic(err.Error()) +} diff --git a/kernel/layout.go b/kernel/layout.go new file mode 100644 index 0000000..4b740d4 --- /dev/null +++ b/kernel/layout.go @@ -0,0 +1,288 @@ +package kernel + +import ( + "bufio" + "errors" + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + "github.com/nicksnyder/go-i18n/v2/i18n" + "image/color" + "io" + "regexp" + "strconv" + "strings" +) + +type LayoutContract interface { + SetContent(content fyne.CanvasObject) *fyne.Container + NewProgressbar(queueId int, totalDuration float64) ProgressContract + ChangeQueueStatus(queueId int, queue *Queue) +} + +type Layout struct { + layout *fyne.Container + queueLayoutObject QueueLayoutObjectContract + localizerService LocalizerContract +} + +func NewLayout(queueLayoutObject QueueLayoutObjectContract, localizerService LocalizerContract) *Layout { + layout := container.NewAdaptiveGrid(2, widget.NewLabel(""), container.NewVScroll(queueLayoutObject.GetCanvasObject())) + + return &Layout{ + layout: layout, + queueLayoutObject: queueLayoutObject, + localizerService: localizerService, + } +} + +func (l Layout) SetContent(content fyne.CanvasObject) *fyne.Container { + l.layout.Objects[0] = content + return l.layout +} + +func (l Layout) NewProgressbar(queueId int, totalDuration float64) ProgressContract { + progressbar := l.queueLayoutObject.GetProgressbar(queueId) + return NewProgress(totalDuration, progressbar, l.localizerService) +} + +func (l Layout) ChangeQueueStatus(queueId int, queue *Queue) { + l.queueLayoutObject.ChangeQueueStatus(queueId, queue) +} + +type QueueLayoutObjectContract interface { + GetCanvasObject() fyne.CanvasObject + GetProgressbar(queueId int) *widget.ProgressBar + ChangeQueueStatus(queueId int, queue *Queue) +} + +type QueueLayoutObject struct { + QueueListContract QueueListContract + + queue QueueListContract + container *fyne.Container + items map[int]QueueLayoutItem + localizerService LocalizerContract + layoutLocalizerListener LayoutLocalizerListenerContract +} + +type QueueLayoutItem struct { + CanvasObject fyne.CanvasObject + ProgressBar *widget.ProgressBar + StatusMessage *canvas.Text + MessageError *canvas.Text +} + +func NewQueueLayoutObject(queue QueueListContract, localizerService LocalizerContract, layoutLocalizerListener LayoutLocalizerListenerContract) *QueueLayoutObject { + title := widget.NewLabel(localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: "queue"}) + ":") + title.TextStyle.Bold = true + + layoutLocalizerListener.AddItem("queue", title) + + queueLayoutObject := &QueueLayoutObject{ + queue: queue, + container: container.NewVBox(title), + items: map[int]QueueLayoutItem{}, + localizerService: localizerService, + layoutLocalizerListener: layoutLocalizerListener, + } + + queue.AddListener(queueLayoutObject) + + return queueLayoutObject +} + +func (o QueueLayoutObject) GetCanvasObject() fyne.CanvasObject { + return o.container +} + +func (o QueueLayoutObject) GetProgressbar(queueId int) *widget.ProgressBar { + if item, ok := o.items[queueId]; ok { + return item.ProgressBar + } + return widget.NewProgressBar() +} + +func (o QueueLayoutObject) Add(id int, queue *Queue) { + progressBar := widget.NewProgressBar() + statusMessage := canvas.NewText(o.getStatusTitle(queue.Status), theme.PrimaryColor()) + messageError := canvas.NewText("", theme.ErrorColor()) + + content := container.NewVBox( + container.NewHScroll(widget.NewLabel(queue.Setting.VideoFileInput.Name)), + progressBar, + container.NewHScroll(statusMessage), + container.NewHScroll(messageError), + canvas.NewLine(theme.FocusColor()), + container.NewPadded(), + ) + o.items[id] = QueueLayoutItem{ + CanvasObject: content, + ProgressBar: progressBar, + StatusMessage: statusMessage, + MessageError: messageError, + } + o.container.Add(content) +} + +func (o QueueLayoutObject) Remove(id int) { + if item, ok := o.items[id]; ok { + o.container.Remove(item.CanvasObject) + o.items[id] = QueueLayoutItem{} + } +} + +func (o QueueLayoutObject) ChangeQueueStatus(queueId int, queue *Queue) { + if item, ok := o.items[queueId]; ok { + statusColor := o.getStatusColor(queue.Status) + item.StatusMessage.Text = o.getStatusTitle(queue.Status) + item.StatusMessage.Color = statusColor + item.StatusMessage.Refresh() + if queue.Error != nil { + item.MessageError.Text = queue.Error.Error() + item.MessageError.Color = statusColor + item.MessageError.Refresh() + } + } +} + +func (o QueueLayoutObject) getStatusColor(status StatusContract) color.Color { + if status == StatusType(Error) { + return theme.ErrorColor() + } + + if status == StatusType(Completed) { + return color.RGBA{R: 49, G: 127, B: 114, A: 255} + } + + return theme.PrimaryColor() +} + +func (o QueueLayoutObject) getStatusTitle(status StatusContract) string { + return o.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: status.name()}) +} + +type Progress struct { + totalDuration float64 + progressbar *widget.ProgressBar + protocol string + localizerService LocalizerContract +} + +func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService LocalizerContract) Progress { + return Progress{ + totalDuration: totalDuration, + progressbar: progressbar, + protocol: "pipe:", + localizerService: localizerService, + } +} + +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 + 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 + 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 + p.progressbar.Refresh() + } + } + + if isProcessCompleted == false { + if len(errorText) == 0 { + errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{ + MessageID: "errorConverter", + }) + } + return errors.New(errorText) + } + + return nil +} + +type LayoutLocalizerItem struct { + messageID string + object *widget.Label +} + +type LayoutLocalizerListener struct { + itemCurrentId int + items map[int]*LayoutLocalizerItem +} + +type LayoutLocalizerListenerContract interface { + AddItem(messageID string, object *widget.Label) +} + +func NewLayoutLocalizerListener() *LayoutLocalizerListener { + return &LayoutLocalizerListener{ + itemCurrentId: 0, + items: map[int]*LayoutLocalizerItem{}, + } +} + +func (l LayoutLocalizerListener) AddItem(messageID string, object *widget.Label) { + l.itemCurrentId += 1 + l.items[l.itemCurrentId] = &LayoutLocalizerItem{messageID: messageID, object: object} +} + +func (l LayoutLocalizerListener) Change(localizerService LocalizerContract) { + for _, item := range l.items { + item.object.Text = localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: item.messageID}) + item.object.Refresh() + } +} diff --git a/src/localizer/service.go b/kernel/localizer.go similarity index 62% rename from src/localizer/service.go rename to kernel/localizer.go index 1b27594..e002125 100644 --- a/src/localizer/service.go +++ b/kernel/localizer.go @@ -1,4 +1,4 @@ -package localizer +package kernel import ( "github.com/BurntSushi/toml" @@ -10,12 +10,17 @@ import ( "sort" ) -type ServiceContract interface { +type LocalizerContract interface { GetLanguages() []Lang GetMessage(localizeConfig *i18n.LocalizeConfig) string SetCurrentLanguage(lang Lang) error SetCurrentLanguageByCode(code string) error GetCurrentLanguage() *CurrentLanguage + AddListener(listener LocalizerListenerContract) +} + +type LocalizerListenerContract interface { + Change(localizerService LocalizerContract) } type Lang struct { @@ -29,13 +34,14 @@ type CurrentLanguage struct { localizerDefault *i18n.Localizer } -type Service struct { - bundle *i18n.Bundle - languages []Lang - currentLanguage *CurrentLanguage +type Localizer struct { + bundle *i18n.Bundle + languages []Lang + currentLanguage *CurrentLanguage + localizerListener map[int]LocalizerListenerContract } -func NewService(directory string, languageDefault language.Tag) (*Service, error) { +func NewLocalizer(directory string, languageDefault language.Tag) (*Localizer, error) { bundle := i18n.NewBundle(languageDefault) bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) @@ -46,7 +52,7 @@ func NewService(directory string, languageDefault language.Tag) (*Service, error localizerDefault := i18n.NewLocalizer(bundle, languageDefault.String()) - return &Service{ + return &Localizer{ bundle: bundle, languages: languages, currentLanguage: &CurrentLanguage{ @@ -57,6 +63,7 @@ func NewService(directory string, languageDefault language.Tag) (*Service, error localizer: localizerDefault, localizerDefault: localizerDefault, }, + localizerListener: map[int]LocalizerListenerContract{}, }, nil } @@ -81,14 +88,14 @@ func initLanguages(directory string, bundle *i18n.Bundle) ([]Lang, error) { return languages, nil } -func (s Service) GetLanguages() []Lang { - return s.languages +func (l Localizer) GetLanguages() []Lang { + return l.languages } -func (s Service) GetMessage(localizeConfig *i18n.LocalizeConfig) string { - message, err := s.GetCurrentLanguage().localizer.Localize(localizeConfig) +func (l Localizer) GetMessage(localizeConfig *i18n.LocalizeConfig) string { + message, err := l.GetCurrentLanguage().localizer.Localize(localizeConfig) if err != nil { - message, err = s.GetCurrentLanguage().localizerDefault.Localize(localizeConfig) + message, err = l.GetCurrentLanguage().localizerDefault.Localize(localizeConfig) if err != nil { return err.Error() } @@ -96,23 +103,34 @@ func (s Service) GetMessage(localizeConfig *i18n.LocalizeConfig) string { return message } -func (s Service) SetCurrentLanguage(lang Lang) error { - s.currentLanguage.Lang = lang - s.currentLanguage.localizer = i18n.NewLocalizer(s.bundle, lang.Code) +func (l Localizer) SetCurrentLanguage(lang Lang) error { + l.currentLanguage.Lang = lang + l.currentLanguage.localizer = i18n.NewLocalizer(l.bundle, lang.Code) + l.eventSetCurrentLanguage() return nil } -func (s Service) SetCurrentLanguageByCode(code string) error { +func (l Localizer) SetCurrentLanguageByCode(code string) error { lang, err := language.Parse(code) if err != nil { return err } title := cases.Title(lang).String(display.Self.Name(lang)) - return s.SetCurrentLanguage(Lang{Code: lang.String(), Title: title}) + return l.SetCurrentLanguage(Lang{Code: lang.String(), Title: title}) } -func (s Service) GetCurrentLanguage() *CurrentLanguage { - return s.currentLanguage +func (l Localizer) GetCurrentLanguage() *CurrentLanguage { + return l.currentLanguage +} + +func (l Localizer) AddListener(listener LocalizerListenerContract) { + l.localizerListener[len(l.localizerListener)] = listener +} + +func (l Localizer) eventSetCurrentLanguage() { + for _, listener := range l.localizerListener { + listener.Change(l) + } } type languagesSort []Lang diff --git a/kernel/queue.go b/kernel/queue.go new file mode 100644 index 0000000..d820fa6 --- /dev/null +++ b/kernel/queue.go @@ -0,0 +1,137 @@ +package kernel + +import ( + "errors" +) + +type Queue struct { + Setting *ConvertSetting + Status StatusContract + Error error +} + +type File struct { + Path string + Name string + Ext string +} + +type ConvertSetting struct { + VideoFileInput File + VideoFileOut File + OverwriteOutputFiles bool +} + +type StatusContract interface { + name() string + ordinal() int +} + +const ( + Waiting = iota + InProgress + Completed + Error +) + +type StatusType uint + +var statusTypeStrings = []string{ + "waiting", + "inProgress", + "completed", + "error", +} + +func (status StatusType) name() string { + return statusTypeStrings[status] +} + +func (status StatusType) ordinal() int { + return int(status) +} + +type QueueListenerContract interface { + Add(key int, queue *Queue) + Remove(key int) +} + +type QueueListContract interface { + AddListener(queueListener QueueListenerContract) + GetItems() map[int]*Queue + Add(setting *ConvertSetting) + Remove(key int) + GetItem(key int) (*Queue, error) + Next() (key int, queue *Queue) +} + +type QueueList struct { + currentKey *int + items map[int]*Queue + queueListener map[int]QueueListenerContract +} + +func NewQueueList() *QueueList { + currentKey := 0 + return &QueueList{ + currentKey: ¤tKey, + items: map[int]*Queue{}, + queueListener: map[int]QueueListenerContract{}, + } +} + +func (l QueueList) GetItems() map[int]*Queue { + return l.items +} + +func (l QueueList) Add(setting *ConvertSetting) { + queue := Queue{ + Setting: setting, + Status: StatusType(Waiting), + } + + *l.currentKey += 1 + l.items[*l.currentKey] = &queue + l.eventAdd(*l.currentKey, &queue) +} + +func (l QueueList) Remove(key int) { + if _, ok := l.items[key]; ok { + delete(l.items, key) + l.eventRemove(key) + } +} + +func (l QueueList) GetItem(key int) (*Queue, error) { + if item, ok := l.items[key]; ok { + return item, nil + } + + return nil, errors.New("key not found") +} + +func (l QueueList) AddListener(queueListener QueueListenerContract) { + l.queueListener[len(l.queueListener)] = queueListener +} + +func (l QueueList) eventAdd(key int, queue *Queue) { + for _, listener := range l.queueListener { + listener.Add(key, queue) + } +} + +func (l QueueList) eventRemove(key int) { + for _, listener := range l.queueListener { + listener.Remove(key) + } +} + +func (l QueueList) Next() (key int, queue *Queue) { + statusWaiting := StatusType(Waiting) + for key, item := range l.items { + if item.Status == statusWaiting { + return key, item + } + } + return -1, nil +} diff --git a/kernel/window.go b/kernel/window.go new file mode 100644 index 0000000..4d6d4c4 --- /dev/null +++ b/kernel/window.go @@ -0,0 +1,80 @@ +package kernel + +import ( + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/dialog" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/helper" + "time" +) + +type WindowContract interface { + SetContent(content fyne.CanvasObject) + SetMainMenu(menu *fyne.MainMenu) + NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog + NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog + ShowAndRun() + GetLayout() LayoutContract +} + +type Window struct { + windowFyne fyne.Window + layout LayoutContract +} + +func newWindow(w fyne.Window, layout LayoutContract) Window { + w.Resize(fyne.Size{Width: 1039, Height: 599}) + w.CenterOnScreen() + + go func() { + /** + * Bug fixed. + * When starting the program, sometimes the window was displayed incorrectly. + */ + time.Sleep(time.Millisecond * 500) + size := w.Canvas().Size() + size.Width += 1 + size.Height += 1 + w.Resize(size) + }() + + return Window{ + windowFyne: w, + layout: layout, + } +} + +func (w Window) SetContent(content fyne.CanvasObject) { + w.windowFyne.SetContent(w.layout.SetContent(content)) +} + +func (w Window) NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog { + fileDialog := dialog.NewFileOpen(callback, w.windowFyne) + helper.FileDialogResize(fileDialog, w.windowFyne) + fileDialog.Show() + if location != nil { + fileDialog.SetLocation(location) + } + return fileDialog +} + +func (w Window) NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog { + fileDialog := dialog.NewFolderOpen(callback, w.windowFyne) + helper.FileDialogResize(fileDialog, w.windowFyne) + fileDialog.Show() + if location != nil { + fileDialog.SetLocation(location) + } + return fileDialog +} + +func (w Window) SetMainMenu(menu *fyne.MainMenu) { + w.windowFyne.SetMainMenu(menu) +} + +func (w Window) ShowAndRun() { + w.windowFyne.ShowAndRun() +} + +func (w Window) GetLayout() LayoutContract { + return w.layout +} diff --git a/src/languages/active.en.toml b/languages/active.en.toml similarity index 93% rename from src/languages/active.en.toml rename to languages/active.en.toml index 2ffafeb..499b140 100644 --- a/src/languages/active.en.toml +++ b/languages/active.en.toml @@ -38,6 +38,10 @@ other = "Allow file to be overwritten" hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94" other = "choose" +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Completed" + [converterVideoFilesSubmitTitle] hash = "sha1-7ac460f3c24c9952082f2db6e4d62f752598709c" other = "Convert" @@ -110,6 +114,10 @@ other = "File for conversion:" hash = "sha1-6a45cef900c668effcb2ab10da05855c1fd10f6f" other = "Help" +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "In Progress" + [languageSelectionFormHead] hash = "sha1-0ff5fa82cf684112660128cba1711297acf11003" other = "Switch language" @@ -142,6 +150,10 @@ other = "Project website" hash = "sha1-fa2e4994a301bb24bc2a8fa166e5486ea95a7475" other = "**Program version:** {{.Version}}" +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Queue" + [save] hash = "sha1-4864057d626a868fa60f999bed3191d61d045ddc" other = "Save" @@ -165,3 +177,7 @@ other = "You can download it from here" [unzipRun] hash = "sha1-c554dad13026668a1f6adf3171837c5d51bbac36" other = "Unpacked..." + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Waiting" diff --git a/src/languages/active.kk.toml b/languages/active.kk.toml similarity index 94% rename from src/languages/active.kk.toml rename to languages/active.kk.toml index 990a3ad..d443d8a 100644 --- a/src/languages/active.kk.toml +++ b/languages/active.kk.toml @@ -38,6 +38,10 @@ other = "Файлды қайта жазуға рұқсат беріңіз" hash = "sha1-f60bb5f761024d973834b5e9d25ceebce2c85f94" other = "таңдау" +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Дайын" + [converterVideoFilesSubmitTitle] hash = "sha1-7ac460f3c24c9952082f2db6e4d62f752598709c" other = "Файлды түрлендіру" @@ -110,6 +114,10 @@ other = "Түрлендіруге арналған файл:" hash = "sha1-6a45cef900c668effcb2ab10da05855c1fd10f6f" other = "Анықтама" +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "Орындалуда" + [languageSelectionFormHead] hash = "sha1-0ff5fa82cf684112660128cba1711297acf11003" other = "Тілді ауыстыру" @@ -142,6 +150,10 @@ other = "Жобаның веб-сайты" hash = "sha1-fa2e4994a301bb24bc2a8fa166e5486ea95a7475" other = "**Бағдарлама нұсқасы:** {{.Version}}" +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Кезек" + [save] hash = "sha1-4864057d626a868fa60f999bed3191d61d045ddc" other = "Сақтау" @@ -165,3 +177,7 @@ other = "Сіз оны осы жерден жүктей аласыз" [unzipRun] hash = "sha1-c554dad13026668a1f6adf3171837c5d51bbac36" other = "Орамнан шығарылуда..." + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Күту" diff --git a/src/languages/active.ru.toml b/languages/active.ru.toml similarity index 95% rename from src/languages/active.ru.toml rename to languages/active.ru.toml index 7d94ea8..b163e1b 100644 --- a/src/languages/active.ru.toml +++ b/languages/active.ru.toml @@ -8,6 +8,7 @@ changeFFPath = "FFmpeg и FFprobe" changeLanguage = "Поменять язык" checkboxOverwriteOutputFilesTitle = "Разрешить перезаписать файл" choose = "выбрать" +completed = "Готово" converterVideoFilesSubmitTitle = "Конвертировать" converterVideoFilesTitle = "Конвертор видео файлов в mp4" download = "Скачать" @@ -26,6 +27,7 @@ ffmpegLGPL = "Это программное обеспечение исполь ffmpegTrademark = "**FFmpeg** — торговая марка **[Fabrice Bellard](http://bellard.org/)** , создателя проекта **[FFmpeg](https://ffmpeg.org/about.html)**." fileVideoForConversionTitle = "Файл для ковертации:" help = "Справка" +inProgress = "Выполняется" languageSelectionFormHead = "Переключить язык" languageSelectionHead = "Выберите язык" licenseLink = "Сведения о лицензии" @@ -34,9 +36,11 @@ pathToFfmpeg = "Путь к FFmpeg:" pathToFfprobe = "Путь к FFprobe:" programmLink = "Сайт проекта" programmVersion = "**Версия программы:** {{.Version}}" +queue = "Очередь" save = "Сохранить" selectFFPathTitle = "Укажите путь к FFmpeg и к FFprobe" settings = "Настройки" testFF = "Проверка FFmpeg на работоспособность..." titleDownloadLink = "Скачать можно от сюда" unzipRun = "Распаковывается..." +waiting = "В очереди" diff --git a/languages/translate.en.toml b/languages/translate.en.toml new file mode 100644 index 0000000..acb16ac --- /dev/null +++ b/languages/translate.en.toml @@ -0,0 +1,15 @@ +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Completed" + +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "In Progress" + +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Queue" + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Waiting" diff --git a/languages/translate.kk.toml b/languages/translate.kk.toml new file mode 100644 index 0000000..93b8581 --- /dev/null +++ b/languages/translate.kk.toml @@ -0,0 +1,15 @@ +[completed] +hash = "sha1-398c7d4f7b0d522afb930769c0fbb1a9f4b61fbe" +other = "Дайын" + +[inProgress] +hash = "sha1-eff79c40e2100ae5fadf3a7d99336025edcca8b5" +other = "Орындалуда" + +[queue] +hash = "sha1-aec93b16baeaf55fed871075c9494a460e4a91b8" +other = "Кезек" + +[waiting] +hash = "sha1-307429dd84150877080c4bbff2b340d1e7dadff2" +other = "Күту" diff --git a/src/localizer/repository.go b/localizer/repository.go similarity index 91% rename from src/localizer/repository.go rename to localizer/repository.go index 03c7fa3..46e36f2 100644 --- a/src/localizer/repository.go +++ b/localizer/repository.go @@ -1,7 +1,7 @@ package localizer import ( - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/setting" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/setting" ) type RepositoryContract interface { diff --git a/src/localizer/view.go b/localizer/view.go similarity index 67% rename from src/localizer/view.go rename to localizer/view.go index 351d9c9..c0e5af6 100644 --- a/src/localizer/view.go +++ b/localizer/view.go @@ -3,27 +3,26 @@ package localizer import ( "fyne.io/fyne/v2" "fyne.io/fyne/v2/widget" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" ) type ViewContract interface { - LanguageSelection(funcSelected func(lang Lang)) + LanguageSelection(funcSelected func(lang kernel.Lang)) } type View struct { - w fyne.Window - localizerService ServiceContract + app kernel.AppContract } -func NewView(w fyne.Window, localizerService ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - localizerService: localizerService, + app: app, } } -func (v View) LanguageSelection(funcSelected func(lang Lang)) { - languages := v.localizerService.GetLanguages() +func (v View) LanguageSelection(funcSelected func(lang kernel.Lang)) { + languages := v.app.GetLocalizerService().GetLanguages() listView := widget.NewList( func() int { return len(languages) @@ -36,18 +35,17 @@ func (v View) LanguageSelection(funcSelected func(lang Lang)) { block.SetText(languages[i].Title) }) listView.OnSelected = func(id widget.ListItemID) { - _ = v.localizerService.SetCurrentLanguage(languages[id]) + _ = v.app.GetLocalizerService().SetCurrentLanguage(languages[id]) funcSelected(languages[id]) } - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ + messageHead := v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "languageSelectionHead", }) - - v.w.SetContent(widget.NewCard(messageHead, "", listView)) + v.app.GetWindow().SetContent(widget.NewCard(messageHead, "", listView)) } -func LanguageSelectionForm(localizerService ServiceContract, funcSelected func(lang Lang)) fyne.CanvasObject { +func LanguageSelectionForm(localizerService kernel.LocalizerContract, funcSelected func(lang kernel.Lang)) fyne.CanvasObject { languages := localizerService.GetLanguages() currentLanguage := localizerService.GetCurrentLanguage() listView := widget.NewList( diff --git a/main.go b/main.go new file mode 100644 index 0000000..5b98be8 --- /dev/null +++ b/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "errors" + "fyne.io/fyne/v2" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/convertor" + error2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/error" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/handler" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/menu" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/migration" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/setting" + _ "github.com/mattn/go-sqlite3" + "golang.org/x/text/language" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + "os" +) + +var application kernel.AppContract +var ffPathUtilities *kernel.FFPathUtilities + +func init() { + iconResource, _ := fyne.LoadResourceFromPath("icon.png") + appMetadata := &fyne.AppMetadata{ + ID: "net.kor-elf.projects.gui-for-ffmpeg", + Name: "GUI for FFmpeg", + Version: "0.4.0", + Icon: iconResource, + } + + localizerService, err := kernel.NewLocalizer("languages", language.Russian) + if err != nil { + kernel.PanicErrorLang(err, appMetadata) + } + + ffPathUtilities = &kernel.FFPathUtilities{FFmpeg: "", FFprobe: ""} + convertorService := kernel.NewService(ffPathUtilities) + layoutLocalizerListener := kernel.NewLayoutLocalizerListener() + localizerService.AddListener(layoutLocalizerListener) + + queue := kernel.NewQueueList() + application = kernel.NewApp( + appMetadata, + localizerService, + queue, + kernel.NewQueueLayoutObject(queue, localizerService, layoutLocalizerListener), + convertorService, + ) +} + +func main() { + errorView := error2.NewView(application) + if canCreateFile("data/database") != true { + errorView.PanicErrorWriteDirectoryData() + application.GetWindow().ShowAndRun() + return + } + + db, err := gorm.Open(sqlite.Open("data/database"), &gorm.Config{}) + if err != nil { + errorView.PanicError(err) + application.GetWindow().ShowAndRun() + return + } + + defer appCloseWithDb(db) + + err = migration.Run(db) + if err != nil { + errorView.PanicError(err) + application.GetWindow().ShowAndRun() + return + } + + settingRepository := setting.NewRepository(db) + convertorRepository := convertor.NewRepository(settingRepository) + pathFFmpeg, err := convertorRepository.GetPathFfmpeg() + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { + errorView.PanicError(err) + application.GetWindow().ShowAndRun() + return + } + ffPathUtilities.FFmpeg = pathFFmpeg + + pathFFprobe, err := convertorRepository.GetPathFfprobe() + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { + errorView.PanicError(err) + application.GetWindow().ShowAndRun() + return + } + ffPathUtilities.FFprobe = pathFFprobe + + application.RunConvertor() + defer application.AfterClosing() + + localizerView := localizer.NewView(application) + convertorView := convertor.NewView(application) + convertorHandler := handler.NewConvertorHandler(application, convertorView, convertorRepository) + + localizerRepository := localizer.NewRepository(settingRepository) + menuView := menu.NewView(application) + localizerListener := handler.NewLocalizerListener() + application.GetLocalizerService().AddListener(localizerListener) + mainMenu := handler.NewMenuHandler(application, convertorHandler, menuView, localizerView, localizerRepository, localizerListener) + + mainHandler := handler.NewMainHandler(application, convertorHandler, mainMenu, localizerRepository) + mainHandler.Start() + + application.GetWindow().SetMainMenu(mainMenu.GetMainMenu()) + application.GetWindow().ShowAndRun() +} + +func appCloseWithDb(db *gorm.DB) { + sqlDB, err := db.DB() + if err == nil { + _ = sqlDB.Close() + } +} + +func canCreateFile(path string) bool { + file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) + if err != nil { + return false + } + _ = file.Close() + return true +} diff --git a/src/menu/view.go b/menu/view.go similarity index 92% rename from src/menu/view.go rename to menu/view.go index 377dd6e..f468498 100644 --- a/src/menu/view.go +++ b/menu/view.go @@ -5,7 +5,7 @@ import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/kernel" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/image/colornames" "net/url" @@ -16,23 +16,17 @@ type ViewContract interface { } type View struct { - w fyne.Window - app fyne.App - appVersion string - localizerService localizer.ServiceContract + app kernel.AppContract } -func NewView(w fyne.Window, app fyne.App, appVersion string, localizerService localizer.ServiceContract) *View { +func NewView(app kernel.AppContract) *View { return &View{ - w: w, - app: app, - appVersion: appVersion, - localizerService: localizerService, + app: app, } } func (v View) About(ffmpegVersion string, ffprobeVersion string) { - view := v.app.NewWindow(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + view := v.app.GetAppFyne().NewWindow(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "about", })) view.Resize(fyne.Size{Width: 793, Height: 550}) @@ -42,7 +36,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -50,7 +44,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/releases", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https", @@ -58,7 +52,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE", }) - licenseLinkOther := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLinkOther := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLinkOther", }), &url.URL{ Scheme: "https", @@ -66,16 +60,16 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE-3RD-PARTY.txt", }) - programmVersion := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmVersion := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmVersion", TemplateData: map[string]string{ - "Version": v.appVersion, + "Version": v.app.GetAppFyne().Metadata().Version, }, })) aboutText := widget.NewRichText( &widget.TextSegment{ - Text: v.localizerService.GetMessage(&i18n.LocalizeConfig{ + Text: v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "aboutText", }), }, @@ -84,10 +78,10 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { image.SetMinSize(fyne.Size{Width: 100, Height: 100}) image.FillMode = canvas.ImageFillContain - ffmpegTrademark := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffmpegTrademark := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "ffmpegTrademark", })) - ffmpegLGPL := widget.NewRichTextFromMarkdown(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + ffmpegLGPL := widget.NewRichTextFromMarkdown(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "ffmpegLGPL", })) @@ -105,7 +99,7 @@ func (v View) About(ffmpegVersion string, ffprobeVersion string) { )), v.getAboutFfmpeg(ffmpegVersion), v.getAboutFfprobe(ffprobeVersion), - widget.NewCard(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + widget.NewCard(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "AlsoUsedProgram", }), "", v.getOther()), )), @@ -123,7 +117,7 @@ func (v View) getAboutFfmpeg(version string) *fyne.Container { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -131,7 +125,7 @@ func (v View) getAboutFfmpeg(version string) *fyne.Container { Path: "", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https", @@ -153,7 +147,7 @@ func (v View) getAboutFfprobe(version string) *fyne.Container { programmName.TextStyle = fyne.TextStyle{Bold: true} programmName.TextSize = 20 - programmLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + programmLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "programmLink", }), &url.URL{ Scheme: "https", @@ -161,7 +155,7 @@ func (v View) getAboutFfprobe(version string) *fyne.Container { Path: "ffprobe.html", }) - licenseLink := widget.NewHyperlink(v.localizerService.GetMessage(&i18n.LocalizeConfig{ + licenseLink := widget.NewHyperlink(v.app.GetLocalizerService().GetMessage(&i18n.LocalizeConfig{ MessageID: "licenseLink", }), &url.URL{ Scheme: "https", diff --git a/src/migration/migration.go b/migration/migration.go similarity index 75% rename from src/migration/migration.go rename to migration/migration.go index 91787ff..932b98a 100644 --- a/src/migration/migration.go +++ b/migration/migration.go @@ -1,7 +1,7 @@ package migration import ( - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/setting" + "git.kor-elf.net/kor-elf/gui-for-ffmpeg/setting" "gorm.io/gorm" ) diff --git a/src/setting/entity.go b/setting/entity.go similarity index 100% rename from src/setting/entity.go rename to setting/entity.go diff --git a/src/setting/repository.go b/setting/repository.go similarity index 100% rename from src/setting/repository.go rename to setting/repository.go diff --git a/src/error/view.go b/src/error/view.go deleted file mode 100644 index 61bd0f4..0000000 --- a/src/error/view.go +++ /dev/null @@ -1,66 +0,0 @@ -package error - -import ( - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" - "github.com/nicksnyder/go-i18n/v2/i18n" -) - -type ViewContract interface { - PanicError(err error) -} - -type View struct { - w fyne.Window - localizerService localizer.ServiceContract -} - -func NewView(w fyne.Window, localizerService localizer.ServiceContract) *View { - return &View{ - w: w, - localizerService: localizerService, - } -} - -func (v View) PanicError(err error) { - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "error", - }) - - v.w.SetContent(container.NewBorder( - container.NewVBox( - widget.NewLabel(messageHead), - widget.NewLabel(err.Error()), - ), - nil, - nil, - nil, - localizer.LanguageSelectionForm(v.localizerService, func(lang localizer.Lang) { - v.PanicError(err) - }), - )) -} - -func (v View) PanicErrorWriteDirectoryData() { - message := v.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorDatabase", - }) - messageHead := v.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "error", - }) - - v.w.SetContent(container.NewBorder( - container.NewVBox( - widget.NewLabel(messageHead), - widget.NewLabel(message), - ), - nil, - nil, - nil, - localizer.LanguageSelectionForm(v.localizerService, func(lang localizer.Lang) { - v.PanicErrorWriteDirectoryData() - }), - )) -} diff --git a/src/handler/convertor.go b/src/handler/convertor.go deleted file mode 100644 index e878665..0000000 --- a/src/handler/convertor.go +++ /dev/null @@ -1,238 +0,0 @@ -package handler - -import ( - "bufio" - "errors" - "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/convertor" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/helper" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" - "github.com/nicksnyder/go-i18n/v2/i18n" - "io" - "regexp" - "strconv" - "strings" -) - -type ConvertorHandlerContract interface { - MainConvertor() - FfPathSelection() - GetFfmpegVersion() (string, error) - GetFfprobeVersion() (string, error) -} - -type ConvertorHandler struct { - convertorService convertor.ServiceContract - convertorView convertor.ViewContract - convertorRepository convertor.RepositoryContract - localizerService localizer.ServiceContract -} - -func NewConvertorHandler( - convertorService convertor.ServiceContract, - convertorView convertor.ViewContract, - convertorRepository convertor.RepositoryContract, - localizerService localizer.ServiceContract, -) *ConvertorHandler { - return &ConvertorHandler{ - convertorService: convertorService, - convertorView: convertorView, - convertorRepository: convertorRepository, - localizerService: localizerService, - } -} - -func (h ConvertorHandler) MainConvertor() { - if h.checkingFFPathUtilities() == true { - h.convertorView.Main(h.runConvert) - return - } - h.convertorView.SelectFFPath("", "", h.saveSettingFFPath, nil, h.downloadFFmpeg) -} - -func (h ConvertorHandler) FfPathSelection() { - ffmpeg, _ := h.convertorRepository.GetPathFfmpeg() - ffprobe, _ := h.convertorRepository.GetPathFfprobe() - h.convertorView.SelectFFPath(ffmpeg, ffprobe, h.saveSettingFFPath, h.MainConvertor, h.downloadFFmpeg) -} - -func (h ConvertorHandler) GetFfmpegVersion() (string, error) { - return h.convertorService.GetFFmpegVesrion() -} - -func (h ConvertorHandler) GetFfprobeVersion() (string, error) { - return h.convertorService.GetFFprobeVersion() -} - -func (h ConvertorHandler) runConvert(setting convertor.HandleConvertSetting, progressbar *widget.ProgressBar) error { - totalDuration, err := h.convertorService.GetTotalDuration(setting.VideoFileInput) - if err != nil { - return err - } - progress := NewProgress(totalDuration, progressbar, h.localizerService) - - return h.convertorService.RunConvert( - convertor.ConvertSetting{ - VideoFileInput: setting.VideoFileInput, - VideoFileOut: &convertor.File{ - Path: setting.DirectoryForSave + helper.PathSeparator() + setting.VideoFileInput.Name + ".mp4", - Name: setting.VideoFileInput.Name, - Ext: ".mp4", - }, - OverwriteOutputFiles: setting.OverwriteOutputFiles, - }, - progress, - ) -} - -func (h ConvertorHandler) checkingFFPathUtilities() bool { - if h.checkingFFPath() == true { - return true - } - - pathsToFF := getPathsToFF() - for _, item := range pathsToFF { - ffmpegChecking, _ := h.convertorService.ChangeFFmpegPath(item.FFmpeg) - if ffmpegChecking == false { - continue - } - ffprobeChecking, _ := h.convertorService.ChangeFFprobePath(item.FFprobe) - if ffprobeChecking == false { - continue - } - _, _ = h.convertorRepository.SavePathFfmpeg(item.FFmpeg) - _, _ = h.convertorRepository.SavePathFfprobe(item.FFprobe) - return true - } - - return false -} - -func (h ConvertorHandler) saveSettingFFPath(ffmpegPath string, ffprobePath string) error { - ffmpegChecking, _ := h.convertorService.ChangeFFmpegPath(ffmpegPath) - if ffmpegChecking == false { - errorText := h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorFFmpeg", - }) - return errors.New(errorText) - } - - ffprobeChecking, _ := h.convertorService.ChangeFFprobePath(ffprobePath) - if ffprobeChecking == false { - errorText := h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorFFprobe", - }) - return errors.New(errorText) - } - - _, _ = h.convertorRepository.SavePathFfmpeg(ffmpegPath) - _, _ = h.convertorRepository.SavePathFfprobe(ffprobePath) - - h.MainConvertor() - - return nil -} - -func (h ConvertorHandler) checkingFFPath() bool { - _, err := h.convertorService.GetFFmpegVesrion() - if err != nil { - return false - } - - _, err = h.convertorService.GetFFprobeVersion() - if err != nil { - return false - } - - return true -} - -type Progress struct { - totalDuration float64 - progressbar *widget.ProgressBar - protocol string - localizerService localizer.ServiceContract -} - -func NewProgress(totalDuration float64, progressbar *widget.ProgressBar, localizerService localizer.ServiceContract) Progress { - return Progress{ - totalDuration: totalDuration, - progressbar: progressbar, - protocol: "pipe:", - localizerService: localizerService, - } -} - -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 - 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 - 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 - p.progressbar.Refresh() - } - } - - if isProcessCompleted == false { - if len(errorText) == 0 { - errorText = p.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorConverter", - }) - } - return errors.New(errorText) - } - - return nil -} diff --git a/src/handler/menu.go b/src/handler/menu.go deleted file mode 100644 index bf7e332..0000000 --- a/src/handler/menu.go +++ /dev/null @@ -1,125 +0,0 @@ -package handler - -import ( - "fyne.io/fyne/v2" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/menu" - "github.com/nicksnyder/go-i18n/v2/i18n" -) - -type MenuHandlerContract interface { - GetMainMenu() *fyne.MainMenu - LanguageSelection() -} - -type menuItems struct { - menuItem map[string]*fyne.MenuItem - menu map[string]*fyne.Menu -} - -type MenuHandler struct { - convertorHandler ConvertorHandlerContract - menuView menu.ViewContract - localizerService localizer.ServiceContract - localizerView localizer.ViewContract - localizerRepository localizer.RepositoryContract - menuItems *menuItems -} - -func NewMenuHandler( - convertorHandler ConvertorHandlerContract, - menuView menu.ViewContract, - localizerService localizer.ServiceContract, - localizerView localizer.ViewContract, - localizerRepository localizer.RepositoryContract, -) *MenuHandler { - return &MenuHandler{ - convertorHandler: convertorHandler, - menuView: menuView, - localizerService: localizerService, - localizerView: localizerView, - localizerRepository: localizerRepository, - menuItems: &menuItems{menuItem: map[string]*fyne.MenuItem{}, menu: map[string]*fyne.Menu{}}, - } -} - -func (h MenuHandler) GetMainMenu() *fyne.MainMenu { - settings := h.getMenuSettings() - help := h.getMenuHelp() - - return fyne.NewMainMenu(settings, help) -} - -func (h MenuHandler) getMenuSettings() *fyne.Menu { - quit := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "exit", - }), nil) - quit.IsQuit = true - h.menuItems.menuItem["exit"] = quit - - languageSelection := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "changeLanguage", - }), h.LanguageSelection) - h.menuItems.menuItem["changeLanguage"] = languageSelection - - ffPathSelection := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "changeFFPath", - }), h.convertorHandler.FfPathSelection) - h.menuItems.menuItem["changeFFPath"] = ffPathSelection - - settings := fyne.NewMenu(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "settings", - }), languageSelection, ffPathSelection, quit) - h.menuItems.menu["settings"] = settings - - return settings -} - -func (h MenuHandler) getMenuHelp() *fyne.Menu { - about := fyne.NewMenuItem(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "about", - }), h.openAbout) - h.menuItems.menuItem["about"] = about - - help := fyne.NewMenu(h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "help", - }), about) - h.menuItems.menu["help"] = help - - return help -} - -func (h MenuHandler) openAbout() { - ffmpeg, err := h.convertorHandler.GetFfmpegVersion() - if err != nil { - ffmpeg = h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorFFmpegVersion", - }) - } - ffprobe, err := h.convertorHandler.GetFfprobeVersion() - if err != nil { - ffprobe = h.localizerService.GetMessage(&i18n.LocalizeConfig{ - MessageID: "errorFFprobeVersion", - }) - } - - h.menuView.About(ffmpeg, ffprobe) -} - -func (h MenuHandler) LanguageSelection() { - h.localizerView.LanguageSelection(func(lang localizer.Lang) { - _, _ = h.localizerRepository.Save(lang.Code) - h.menuMessageReload() - h.convertorHandler.MainConvertor() - }) -} - -func (h MenuHandler) menuMessageReload() { - for messageID, menu := range h.menuItems.menuItem { - menu.Label = h.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) - } - for messageID, menu := range h.menuItems.menu { - menu.Label = h.localizerService.GetMessage(&i18n.LocalizeConfig{MessageID: messageID}) - menu.Refresh() - } -} diff --git a/src/languages/translate.en.toml b/src/languages/translate.en.toml deleted file mode 100644 index 81cb622..0000000 --- a/src/languages/translate.en.toml +++ /dev/null @@ -1,3 +0,0 @@ -[testFF] -hash = "sha1-f5b8ed88e9609963035d2235be0a79bbec619976" -other = "Checking FFmpeg for serviceability..." diff --git a/src/languages/translate.kk.toml b/src/languages/translate.kk.toml deleted file mode 100644 index 8e64112..0000000 --- a/src/languages/translate.kk.toml +++ /dev/null @@ -1,3 +0,0 @@ -[testFF] -hash = "sha1-f5b8ed88e9609963035d2235be0a79bbec619976" -other = "FFmpeg функционалдығы тексерілуде..." diff --git a/src/main.go b/src/main.go deleted file mode 100644 index f992a23..0000000 --- a/src/main.go +++ /dev/null @@ -1,127 +0,0 @@ -package main - -import ( - "errors" - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/app" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/widget" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/convertor" - error2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/error" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/handler" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/localizer" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/menu" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/migration" - "git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/setting" - _ "github.com/mattn/go-sqlite3" - "golang.org/x/text/language" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "os" -) - -const appVersion string = "0.3.1" - -func main() { - a := app.New() - iconResource, err := fyne.LoadResourceFromPath("icon.png") - if err == nil { - a.SetIcon(iconResource) - } - w := a.NewWindow("GUI for FFmpeg") - w.Resize(fyne.Size{Width: 800, Height: 600}) - w.CenterOnScreen() - - localizerService, err := localizer.NewService("languages", language.Russian) - if err != nil { - panicErrorLang(w, err) - w.ShowAndRun() - return - } - - errorView := error2.NewView(w, localizerService) - if canCreateFile("data/database") != true { - errorView.PanicErrorWriteDirectoryData() - w.ShowAndRun() - return - } - - db, err := gorm.Open(sqlite.Open("data/database"), &gorm.Config{}) - if err != nil { - errorView.PanicError(err) - w.ShowAndRun() - return - } - - defer appCloseWithDb(db) - - err = migration.Run(db) - if err != nil { - errorView.PanicError(err) - w.ShowAndRun() - return - } - - settingRepository := setting.NewRepository(db) - convertorRepository := convertor.NewRepository(settingRepository) - pathFFmpeg, err := convertorRepository.GetPathFfmpeg() - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { - errorView.PanicError(err) - w.ShowAndRun() - return - } - pathFFprobe, err := convertorRepository.GetPathFfprobe() - if err != nil && errors.Is(err, gorm.ErrRecordNotFound) == false { - errorView.PanicError(err) - w.ShowAndRun() - return - } - - ffPathUtilities := convertor.FFPathUtilities{FFmpeg: pathFFmpeg, FFprobe: pathFFprobe} - - localizerView := localizer.NewView(w, localizerService) - convertorView := convertor.NewView(w, localizerService) - convertorService := convertor.NewService(ffPathUtilities) - defer appCloseWithConvert(convertorService) - convertorHandler := handler.NewConvertorHandler(convertorService, convertorView, convertorRepository, localizerService) - - localizerRepository := localizer.NewRepository(settingRepository) - menuView := menu.NewView(w, a, appVersion, localizerService) - mainMenu := handler.NewMenuHandler(convertorHandler, menuView, localizerService, localizerView, localizerRepository) - - mainHandler := handler.NewMainHandler(convertorHandler, mainMenu, localizerRepository, localizerService) - mainHandler.Start() - - w.SetMainMenu(mainMenu.GetMainMenu()) - - w.ShowAndRun() -} - -func appCloseWithDb(db *gorm.DB) { - sqlDB, err := db.DB() - if err == nil { - _ = sqlDB.Close() - } -} - -func appCloseWithConvert(convertorService convertor.ServiceContract) { - for _, cmd := range convertorService.GetRunningProcesses() { - _ = cmd.Process.Kill() - } -} - -func canCreateFile(path string) bool { - file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - return false - } - _ = file.Close() - return true -} - -func panicErrorLang(w fyne.Window, err error) { - w.SetContent(container.NewVBox( - widget.NewLabel("Произошла ошибка!"), - widget.NewLabel("произошла ошибка при получении языковых переводах. \n\r"+err.Error()), - )) -}