Add FFmpeg utilities configuration UI and automated downloading
Introduce a new UI for configuring FFmpeg, FFprobe, and FFplay paths with file selection and error handling. Add platform-specific logic for downloading and extracting FFmpeg binaries directly within the application, improving user experience.
This commit is contained in:
parent
b24155caf6
commit
c60b9f7b0c
@ -1,7 +1,12 @@
|
|||||||
package setting
|
package setting
|
||||||
|
|
||||||
func (s *setting) GetFFmpegPath() string {
|
func (s *setting) GetFFmpegPath() string {
|
||||||
return s.fyneApp.Preferences().String("ffmpegPath")
|
path := s.fyneApp.Preferences().String("ffmpegPath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffmpeg"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setting) SetFFmpegPath(path string) {
|
func (s *setting) SetFFmpegPath(path string) {
|
||||||
@ -9,7 +14,12 @@ func (s *setting) SetFFmpegPath(path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *setting) GetFFprobePath() string {
|
func (s *setting) GetFFprobePath() string {
|
||||||
return s.fyneApp.Preferences().String("ffprobePath")
|
path := s.fyneApp.Preferences().String("ffprobePath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffprobe"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setting) SetFFprobePath(path string) {
|
func (s *setting) SetFFprobePath(path string) {
|
||||||
@ -17,7 +27,12 @@ func (s *setting) SetFFprobePath(path string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *setting) GetFFplayPath() string {
|
func (s *setting) GetFFplayPath() string {
|
||||||
return s.fyneApp.Preferences().String("ffplayPath")
|
path := s.fyneApp.Preferences().String("ffplayPath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffplay"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *setting) SetFFplayPath(path string) {
|
func (s *setting) SetFFplayPath(path string) {
|
||||||
|
@ -1,8 +1,58 @@
|
|||||||
package controller
|
package controller
|
||||||
|
|
||||||
import "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view"
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/download/service"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view"
|
||||||
|
)
|
||||||
|
|
||||||
func (c *controller) convertor() {
|
func (c *controller) convertor() {
|
||||||
content := view.Convertor()
|
content := view.Convertor()
|
||||||
c.window.SetContent(content)
|
c.window.SetContent(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *controller) settingConvertor(isAllowCancellation bool) {
|
||||||
|
ffmpegPath := c.app.GetFFmpegService().GetFFmpegPath()
|
||||||
|
ffprobePath := c.app.GetFFmpegService().GetFFprobePath()
|
||||||
|
ffplayPath := c.app.GetFFmpegService().GetFFplayPath()
|
||||||
|
|
||||||
|
var cancel func()
|
||||||
|
cancel = nil
|
||||||
|
if isAllowCancellation {
|
||||||
|
cancel = func() {
|
||||||
|
c.convertor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content := view.ConfiguringFFmpegUtilities(
|
||||||
|
c.window,
|
||||||
|
ffmpegPath,
|
||||||
|
ffprobePath,
|
||||||
|
ffplayPath,
|
||||||
|
c.saveSettingConvertor,
|
||||||
|
cancel,
|
||||||
|
service.DownloadFFmpeg(c.app, c.saveSettingConvertor),
|
||||||
|
)
|
||||||
|
c.window.SetContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) saveSettingConvertor(ffmpegPath string, ffprobePath string, ffplayPath string) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
err = c.app.GetFFmpegService().ChangeFFmpeg(ffmpegPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.app.GetFFmpegService().ChangeFFprobe(ffprobePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.app.GetFFmpegService().ChangeFFplay(ffplayPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.convertor()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -13,7 +13,7 @@ type ControllerContract interface {
|
|||||||
|
|
||||||
type controller struct {
|
type controller struct {
|
||||||
app application.AppContract
|
app application.AppContract
|
||||||
window window.MainWindowContract
|
window window.WindowContract
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewController(app application.AppContract) ControllerContract {
|
func NewController(app application.AppContract) ControllerContract {
|
||||||
@ -26,11 +26,10 @@ func NewController(app application.AppContract) ControllerContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) Start() {
|
func (c *controller) Start() {
|
||||||
c.window.Show()
|
|
||||||
|
|
||||||
isDefault, err := c.initLanguage()
|
isDefault, err := c.initLanguage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.startWithError(err)
|
c.startWithError(err)
|
||||||
|
c.window.Show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,14 +45,21 @@ func (c *controller) Start() {
|
|||||||
c.verificareaFFmpeg()
|
c.verificareaFFmpeg()
|
||||||
})
|
})
|
||||||
c.window.SetContent(content)
|
c.window.SetContent(content)
|
||||||
|
c.window.Show()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.window.InitLayout()
|
c.window.InitLayout()
|
||||||
c.verificareaFFmpeg()
|
c.verificareaFFmpeg()
|
||||||
|
c.window.Show()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *controller) verificareaFFmpeg() {
|
func (c *controller) verificareaFFmpeg() {
|
||||||
|
if !c.app.GetFFmpegService().UtilityCheck() {
|
||||||
|
c.settingConvertor(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.convertor()
|
c.convertor()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
internal/ffmpeg/download/gui/download_anyos.go
Normal file
14
internal/ffmpeg/download/gui/download_anyos.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//go:build !windows && !linux
|
||||||
|
// +build !windows,!linux
|
||||||
|
|
||||||
|
package gui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DownloadFFmpeg(donwloadFFmpeg func(progressBar *widget.ProgressBar, progressMessage *canvas.Text) error) fyne.CanvasObject {
|
||||||
|
return container.NewVBox()
|
||||||
|
}
|
59
internal/ffmpeg/download/gui/download_linux.go
Normal file
59
internal/ffmpeg/download/gui/download_linux.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package gui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DownloadFFmpeg(donwloadFFmpeg func(progressBar *widget.ProgressBar, progressMessage *canvas.Text) error) fyne.CanvasObject {
|
||||||
|
errorDownloadFFmpegMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
errorDownloadFFmpegMessage.TextSize = 16
|
||||||
|
errorDownloadFFmpegMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
progressDownloadFFmpegMessage := canvas.NewText("", color.RGBA{R: 49, G: 127, B: 114, A: 255})
|
||||||
|
progressDownloadFFmpegMessage.TextSize = 16
|
||||||
|
progressDownloadFFmpegMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
progressBar := widget.NewProgressBar()
|
||||||
|
|
||||||
|
var buttonDownloadFFmpeg *widget.Button
|
||||||
|
|
||||||
|
buttonDownloadFFmpeg = widget.NewButton(lang.L("download"), func() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonDownloadFFmpeg.Disable()
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
err := donwloadFFmpeg(progressBar, progressDownloadFFmpegMessage)
|
||||||
|
if err != nil {
|
||||||
|
errorDownloadFFmpegMessage.Text = err.Error()
|
||||||
|
}
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonDownloadFFmpeg.Enable()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
downloadFFmpegFromSiteMessage := lang.L("downloadFFmpegFromSite")
|
||||||
|
|
||||||
|
return container.NewVBox(
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
widget.NewCard(lang.L("buttonDownloadFFmpeg"), "", container.NewVBox(
|
||||||
|
widget.NewRichTextFromMarkdown(
|
||||||
|
downloadFFmpegFromSiteMessage+" [https://github.com/BtbN/FFmpeg-Builds/releases](https://github.com/BtbN/FFmpeg-Builds/releases)",
|
||||||
|
),
|
||||||
|
buttonDownloadFFmpeg,
|
||||||
|
container.NewHScroll(errorDownloadFFmpegMessage),
|
||||||
|
progressDownloadFFmpegMessage,
|
||||||
|
progressBar,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
59
internal/ffmpeg/download/gui/download_windows.go
Normal file
59
internal/ffmpeg/download/gui/download_windows.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package gui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DownloadFFmpeg(donwloadFFmpeg func(progressBar *widget.ProgressBar, progressMessage *canvas.Text) error) fyne.CanvasObject {
|
||||||
|
errorDownloadFFmpegMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
errorDownloadFFmpegMessage.TextSize = 16
|
||||||
|
errorDownloadFFmpegMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
progressDownloadFFmpegMessage := canvas.NewText("", color.RGBA{R: 49, G: 127, B: 114, A: 255})
|
||||||
|
progressDownloadFFmpegMessage.TextSize = 16
|
||||||
|
progressDownloadFFmpegMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
progressBar := widget.NewProgressBar()
|
||||||
|
|
||||||
|
var buttonDownloadFFmpeg *widget.Button
|
||||||
|
|
||||||
|
buttonDownloadFFmpeg = widget.NewButton(lang.L("download"), func() {
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonDownloadFFmpeg.Disable()
|
||||||
|
})
|
||||||
|
err := donwloadFFmpeg(progressBar, progressDownloadFFmpegMessage)
|
||||||
|
if err != nil {
|
||||||
|
errorDownloadFFmpegMessage.Text = err.Error()
|
||||||
|
}
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonDownloadFFmpeg.Enable()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
|
||||||
|
downloadFFmpegFromSiteMessage := lang.L("downloadFFmpegFromSite")
|
||||||
|
|
||||||
|
return container.NewVBox(
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
widget.NewCard(lang.L("buttonDownloadFFmpeg"), "", container.NewVBox(
|
||||||
|
widget.NewRichTextFromMarkdown(
|
||||||
|
downloadFFmpegFromSiteMessage+" [https://github.com/BtbN/FFmpeg-Builds/releases](https://github.com/BtbN/FFmpeg-Builds/releases)",
|
||||||
|
),
|
||||||
|
buttonDownloadFFmpeg,
|
||||||
|
container.NewHScroll(errorDownloadFFmpegMessage),
|
||||||
|
progressDownloadFFmpegMessage,
|
||||||
|
progressBar,
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
}
|
21
internal/ffmpeg/download/service/download.go
Normal file
21
internal/ffmpeg/download/service/download.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"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/ffmpeg/download/gui"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DownloadFFmpeg(app application.AppContract, save func(ffmpegPath string, ffprobePath string, ffplayPath string) error) fyne.CanvasObject {
|
||||||
|
return gui.DownloadFFmpeg(func(progressBar *widget.ProgressBar, progressMessage *canvas.Text) error {
|
||||||
|
var err error
|
||||||
|
err = startDownload(app, progressBar, progressMessage, save)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
15
internal/ffmpeg/download/service/download_anyos.go
Normal file
15
internal/ffmpeg/download/service/download_anyos.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//go:build !windows && !linux
|
||||||
|
// +build !windows,!linux
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startDownload(app application.AppContract, progressBar *widget.ProgressBar, progressMessage *canvas.Text, save func(ffmpegPath string, ffprobePath string, ffplayPath string) error) error {
|
||||||
|
return nil
|
||||||
|
}
|
236
internal/ffmpeg/download/service/download_linux.go
Normal file
236
internal/ffmpeg/download/service/download_linux.go
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
//go:build linux
|
||||||
|
// +build linux
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application"
|
||||||
|
"github.com/ulikunitz/xz"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startDownload(app application.AppContract, progressBar *widget.ProgressBar, progressMessage *canvas.Text, save func(ffmpegPath string, ffprobePath string, ffplayPath string) error) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
dir, err := localSharePath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dir = filepath.Join(dir, "fyne", app.FyneApp().UniqueID())
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("downloadRun")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
err = downloadFile(dir+"/ffmpeg.tar.xz", "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz", progressBar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("unzipRun")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
err = unTarXz(dir+"/ffmpeg.tar.xz", dir, progressBar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = os.Remove(dir + "/ffmpeg.tar.xz")
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("testFF")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
err = save(
|
||||||
|
dir+"/ffmpeg-master-latest-linux64-gpl/bin/ffmpeg",
|
||||||
|
dir+"/ffmpeg-master-latest-linux64-gpl/bin/ffprobe",
|
||||||
|
dir+"/ffmpeg-master-latest-linux64-gpl/bin/ffplay",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("completedQueue")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func localSharePath() (string, error) {
|
||||||
|
xdgDataHome := os.Getenv("XDG_DATA_HOME")
|
||||||
|
if xdgDataHome != "" {
|
||||||
|
return xdgDataHome, nil
|
||||||
|
}
|
||||||
|
homeDir, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return filepath.Join(homeDir, ".local", "share"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadFile(filepath string, url string, progressBar *widget.ProgressBar) (err error) {
|
||||||
|
progressBar.Value = 0
|
||||||
|
progressBar.Max = 100
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
f, err := os.OpenFile(filepath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
buf := make([]byte, 32*1024)
|
||||||
|
var downloaded int64
|
||||||
|
for {
|
||||||
|
n, err := resp.Body.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
f.Write(buf[:n])
|
||||||
|
downloaded += int64(n)
|
||||||
|
progressBar.Value = float64(downloaded) / float64(resp.ContentLength) * 100
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unTarXz(fileTar string, directory string, progressBar *widget.ProgressBar) error {
|
||||||
|
progressBar.Value = 0
|
||||||
|
progressBar.Max = 100
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
f, err := os.Open(fileTar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
xzReader, err := xz.NewReader(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tarReader := tar.NewReader(xzReader)
|
||||||
|
|
||||||
|
totalFiles := 0
|
||||||
|
for {
|
||||||
|
_, err := tarReader.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
totalFiles++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewind back to the beginning of the file to re-process
|
||||||
|
_, err = f.Seek(0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
xzReader, err = xz.NewReader(f)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tarReader = tar.NewReader(xzReader)
|
||||||
|
|
||||||
|
// We count the number of files already unpacked
|
||||||
|
unpackedFiles := 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
header, err := tarReader.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetPath := filepath.Join(directory, header.Name)
|
||||||
|
switch header.Typeflag {
|
||||||
|
case tar.TypeDir:
|
||||||
|
err := os.MkdirAll(targetPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case tar.TypeReg:
|
||||||
|
outFile, err := os.Create(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(outFile, tarReader)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return errors.New("unsupported file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
unpackedFiles++
|
||||||
|
progressBar.Value = float64(unpackedFiles) / float64(totalFiles) * 100
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
ffmpegPath := filepath.Join(directory, "ffmpeg-master-latest-linux64-gpl", "bin", "ffmpeg")
|
||||||
|
err = os.Chmod(ffmpegPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ffprobePath := filepath.Join(directory, "ffmpeg-master-latest-linux64-gpl", "bin", "ffprobe")
|
||||||
|
err = os.Chmod(ffprobePath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ffplayPath := filepath.Join(directory, "ffmpeg-master-latest-linux64-gpl", "bin", "ffplay")
|
||||||
|
err = os.Chmod(ffplayPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
175
internal/ffmpeg/download/service/download_windows.go
Normal file
175
internal/ffmpeg/download/service/download_windows.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func startDownload(app application.AppContract, progressBar *widget.ProgressBar, progressMessage *canvas.Text, save func(ffmpegPath string, ffprobePath string, ffplayPath string) error) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
dir := os.Getenv("APPDATA")
|
||||||
|
dir = filepath.Join(dir, "fyne", app.FyneApp().UniqueID())
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("downloadRun")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
err = downloadFile(dir+"/ffmpeg.zip", "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip", progressBar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("unzipRun")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
err = unZip(dir+"/ffmpeg.zip", dir, progressBar)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_ = os.Remove(dir + "/ffmpeg.zip")
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("testFF")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
err = save(
|
||||||
|
dir+"/ffmpeg-master-latest-win64-gpl/bin/ffmpeg.exe",
|
||||||
|
dir+"/ffmpeg-master-latest-win64-gpl/bin/ffprobe.exe",
|
||||||
|
dir+"/ffmpeg-master-latest-win64-gpl/bin/ffplay.exe",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressMessage.Text = lang.L("completedQueue")
|
||||||
|
progressMessage.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func downloadFile(filepath string, url string, progressBar *widget.ProgressBar) (err error) {
|
||||||
|
progressBar.Value = 0
|
||||||
|
progressBar.Max = 100
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
f, err := os.OpenFile(filepath, os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
buf := make([]byte, 32*1024)
|
||||||
|
var downloaded int64
|
||||||
|
for {
|
||||||
|
n, err := resp.Body.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
f.Write(buf[:n])
|
||||||
|
downloaded += int64(n)
|
||||||
|
progressBar.Value = float64(downloaded) / float64(resp.ContentLength) * 100
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unZip(fileZip string, directory string, progressBar *widget.ProgressBar) error {
|
||||||
|
progressBar.Value = 0
|
||||||
|
progressBar.Max = 100
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
archive, err := zip.OpenReader(fileZip)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer archive.Close()
|
||||||
|
|
||||||
|
totalBytes := int64(0)
|
||||||
|
for _, f := range archive.File {
|
||||||
|
totalBytes += int64(f.UncompressedSize64)
|
||||||
|
}
|
||||||
|
|
||||||
|
unpackedBytes := int64(0)
|
||||||
|
|
||||||
|
for _, f := range archive.File {
|
||||||
|
filePath := filepath.Join(directory, f.Name)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(filePath, filepath.Clean(directory)+string(os.PathSeparator)) {
|
||||||
|
return errors.New("invalid file path")
|
||||||
|
}
|
||||||
|
if f.FileInfo().IsDir() {
|
||||||
|
os.MkdirAll(filePath, os.ModePerm)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dstFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fileInArchive, err := f.Open()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead, err := io.Copy(dstFile, fileInArchive)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
unpackedBytes += bytesRead
|
||||||
|
progressBar.Value = float64(unpackedBytes) / float64(totalBytes) * 100
|
||||||
|
fyne.Do(func() {
|
||||||
|
progressBar.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
dstFile.Close()
|
||||||
|
fileInArchive.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,19 +1,52 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type FFmpegContract interface {
|
type FFmpegContract interface {
|
||||||
SetPath(path string)
|
GetPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ffmpeg struct {
|
type ffmpeg struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFFmpeg(path string) FFmpegContract {
|
func newFFmpeg(path string) (FFmpegContract, error) {
|
||||||
return &ffmpeg{
|
if path == "" {
|
||||||
path: path,
|
return nil, errors.New(lang.L("errorFFmpeg"))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ffmpeg) SetPath(path string) {
|
isCheck, err := checkFFmpegPath(path)
|
||||||
f.path = path
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isCheck == false {
|
||||||
|
return nil, errors.New(lang.L("errorFFmpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ffmpeg{
|
||||||
|
path: path,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffmpeg) GetPath() string {
|
||||||
|
return f.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFFmpegPath(path string) (bool, error) {
|
||||||
|
cmd := exec.Command(path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.TrimSpace(string(out)), "ffmpeg") == false {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,52 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type FFplayContract interface {
|
type FFplayContract interface {
|
||||||
SetPath(path string)
|
GetPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ffplay struct {
|
type ffplay struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFFplay(path string) FFplayContract {
|
func newFFplay(path string) (FFplayContract, error) {
|
||||||
return &ffplay{
|
if path == "" {
|
||||||
path: path,
|
return nil, errors.New(lang.L("errorFFplay"))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ffplay) SetPath(path string) {
|
isCheck, err := checkFFplayPath(path)
|
||||||
f.path = path
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isCheck == false {
|
||||||
|
return nil, errors.New(lang.L("errorFFplay"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ffplay{
|
||||||
|
path: path,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffplay) GetPath() string {
|
||||||
|
return f.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFFplayPath(path string) (bool, error) {
|
||||||
|
cmd := exec.Command(path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.TrimSpace(string(out)), "ffplay") == false {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,52 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type FFprobeContract interface {
|
type FFprobeContract interface {
|
||||||
SetPath(path string)
|
GetPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ffprobe struct {
|
type ffprobe struct {
|
||||||
path string
|
path string
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFFprobe(path string) FFprobeContract {
|
func newFFprobe(path string) (FFprobeContract, error) {
|
||||||
return &ffprobe{
|
if path == "" {
|
||||||
path: path,
|
return nil, errors.New(lang.L("errorFFprobe"))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ffprobe) SetPath(path string) {
|
isCheck, err := checkFFprobePath(path)
|
||||||
f.path = path
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isCheck == false {
|
||||||
|
return nil, errors.New(lang.L("errorFFprobe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ffprobe{
|
||||||
|
path: path,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffprobe) GetPath() string {
|
||||||
|
return f.path
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkFFprobePath(path string) (bool, error) {
|
||||||
|
cmd := exec.Command(path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if strings.Contains(strings.TrimSpace(string(out)), "ffprobe") == false {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,25 @@
|
|||||||
package ffmpeg
|
package ffmpeg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UtilitiesContract interface {
|
type UtilitiesContract interface {
|
||||||
GetFFmpeg() FFmpegContract
|
UtilityCheck() bool
|
||||||
GetFFprobe() FFprobeContract
|
|
||||||
GetFFplay() FFplayContract
|
GetFFmpeg() (FFmpegContract, error)
|
||||||
|
GetFFmpegPath() string
|
||||||
|
ChangeFFmpeg(path string) error
|
||||||
|
|
||||||
|
GetFFprobe() (FFprobeContract, error)
|
||||||
|
GetFFprobePath() string
|
||||||
|
ChangeFFprobe(path string) error
|
||||||
|
|
||||||
|
GetFFplay() (FFplayContract, error)
|
||||||
|
GetFFplayPath() string
|
||||||
|
ChangeFFplay(path string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type utilities struct {
|
type utilities struct {
|
||||||
@ -23,26 +35,131 @@ func NewUtilities(setting setting.SettingContract) UtilitiesContract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *utilities) GetFFmpeg() FFmpegContract {
|
func (u *utilities) UtilityCheck() bool {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
_, err = u.GetFFmpeg()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.GetFFprobe()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = u.GetFFplay()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFmpeg() (FFmpegContract, error) {
|
||||||
if u.ffmpeg == nil {
|
if u.ffmpeg == nil {
|
||||||
u.ffmpeg = newFFmpeg(u.setting.GetFFmpegPath())
|
createFFmpeg, err := newFFmpeg(u.setting.GetFFmpegPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.ffmpeg = createFFmpeg
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.ffmpeg
|
return u.ffmpeg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *utilities) GetFFprobe() FFprobeContract {
|
func (u *utilities) GetFFmpegPath() string {
|
||||||
if u.ffprobe != nil {
|
ffmpegService, err := u.GetFFmpeg()
|
||||||
u.ffprobe = newFFprobe(u.setting.GetFFprobePath())
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ffmpegService.GetPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.ffprobe
|
func (u *utilities) ChangeFFmpeg(path string) error {
|
||||||
|
if path == "" {
|
||||||
|
return errors.New(lang.L("errorFFmpeg"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *utilities) GetFFplay() FFplayContract {
|
createFFmpeg, err := newFFmpeg(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.ffmpeg = createFFmpeg
|
||||||
|
u.setting.SetFFmpegPath(path)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFprobe() (FFprobeContract, error) {
|
||||||
|
if u.ffprobe == nil {
|
||||||
|
createFFprobe, err := newFFprobe(u.setting.GetFFprobePath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.ffprobe = createFFprobe
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.ffprobe, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFprobePath() string {
|
||||||
|
ffprobeService, err := u.GetFFprobe()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ffprobeService.GetPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) ChangeFFprobe(path string) error {
|
||||||
|
if path == "" {
|
||||||
|
return errors.New(lang.L("errorFFprobe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
createFFprobe, err := newFFprobe(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.ffprobe = createFFprobe
|
||||||
|
u.setting.SetFFprobePath(path)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFplay() (FFplayContract, error) {
|
||||||
if u.ffplay == nil {
|
if u.ffplay == nil {
|
||||||
u.ffplay = newFFplay(u.setting.GetFFplayPath())
|
createFFplay, err := newFFplay(u.setting.GetFFplayPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.ffplay = createFFplay
|
||||||
}
|
}
|
||||||
|
|
||||||
return u.ffplay
|
return u.ffplay, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFplayPath() string {
|
||||||
|
ffplayService, err := u.GetFFplay()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ffplayService.GetPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) ChangeFFplay(path string) error {
|
||||||
|
if path == "" {
|
||||||
|
return errors.New(lang.L("errorFFplay"))
|
||||||
|
}
|
||||||
|
|
||||||
|
createFFplay, err := newFFplay(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.ffplay = createFFplay
|
||||||
|
u.setting.SetFFplayPath(path)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
129
internal/gui/view/configuring_ffmpeg_utilities.go
Normal file
129
internal/gui/view/configuring_ffmpeg_utilities.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/gui/window"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"image/color"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ConfiguringFFmpegUtilities(
|
||||||
|
window window.WindowContract,
|
||||||
|
currentPathFFmpeg string,
|
||||||
|
currentPathFFprobe string,
|
||||||
|
currentPathFFplay string,
|
||||||
|
save func(ffmpegPath string, ffprobePath string, ffplayPath string) error,
|
||||||
|
cancel func(),
|
||||||
|
donwloadFFmpeg fyne.CanvasObject,
|
||||||
|
) fyne.CanvasObject {
|
||||||
|
errorMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
errorMessage.TextSize = 16
|
||||||
|
errorMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
link := widget.NewHyperlink("https://ffmpeg.org/download.html", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "download.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
ffmpegPath, buttonFFmpeg, buttonFFmpegMessage := configuringFFmpegUtilitiesButtonSelectFile(window, currentPathFFmpeg)
|
||||||
|
ffprobePath, buttonFFprobe, buttonFFprobeMessage := configuringFFmpegUtilitiesButtonSelectFile(window, currentPathFFprobe)
|
||||||
|
ffplayPath, buttonFFplay, buttonFFplayMessage := configuringFFmpegUtilitiesButtonSelectFile(window, currentPathFFplay)
|
||||||
|
|
||||||
|
form := &widget.Form{
|
||||||
|
Items: []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("titleDownloadLink"),
|
||||||
|
Widget: link,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("pathToFfmpeg"),
|
||||||
|
Widget: buttonFFmpeg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(buttonFFmpegMessage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("pathToFfprobe"),
|
||||||
|
Widget: buttonFFprobe,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(buttonFFprobeMessage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("pathToFfplay"),
|
||||||
|
Widget: buttonFFplay,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(buttonFFplayMessage),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(errorMessage),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubmitText: lang.L("save"),
|
||||||
|
OnSubmit: func() {
|
||||||
|
err := save(*ffmpegPath, *ffprobePath, *ffplayPath)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage.Text = err.Error()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if cancel != nil {
|
||||||
|
form.OnCancel = cancel
|
||||||
|
form.CancelText = lang.L("cancel")
|
||||||
|
}
|
||||||
|
|
||||||
|
selectFFPathTitle := lang.L("selectFFPathTitle")
|
||||||
|
|
||||||
|
return widget.NewCard(selectFFPathTitle, "", container.NewVBox(
|
||||||
|
form,
|
||||||
|
donwloadFFmpeg,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func configuringFFmpegUtilitiesButtonSelectFile(window window.WindowContract, path string) (filePath *string, button *widget.Button, buttonMessage *canvas.Text) {
|
||||||
|
filePath = &path
|
||||||
|
|
||||||
|
buttonMessage = canvas.NewText(path, color.RGBA{R: 49, G: 127, B: 114, A: 255})
|
||||||
|
buttonMessage.TextSize = 16
|
||||||
|
buttonMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
buttonTitle := lang.L("choose")
|
||||||
|
|
||||||
|
var locationURI fyne.ListableURI
|
||||||
|
if len(path) > 0 {
|
||||||
|
listableURI := storage.NewFileURI(filepath.Dir(path))
|
||||||
|
locationURI, _ = storage.ListerForURI(listableURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
button = widget.NewButton(buttonTitle, func() {
|
||||||
|
window.NewFileOpen(func(r fyne.URIReadCloser, err error) {
|
||||||
|
if err != nil {
|
||||||
|
buttonMessage.Text = err.Error()
|
||||||
|
utils.SetStringErrorStyle(buttonMessage)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path = r.URI().Path()
|
||||||
|
|
||||||
|
buttonMessage.Text = r.URI().Path()
|
||||||
|
utils.SetStringSuccessStyle(buttonMessage)
|
||||||
|
|
||||||
|
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
|
||||||
|
locationURI, _ = storage.ListerForURI(listableURI)
|
||||||
|
}, locationURI)
|
||||||
|
})
|
||||||
|
|
||||||
|
return filePath, button, buttonMessage
|
||||||
|
}
|
@ -3,15 +3,18 @@ package window
|
|||||||
import (
|
import (
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/container"
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/dialog"
|
||||||
"fyne.io/fyne/v2/lang"
|
"fyne.io/fyne/v2/lang"
|
||||||
"fyne.io/fyne/v2/widget"
|
"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"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MainWindowContract interface {
|
type WindowContract interface {
|
||||||
SetContent(content fyne.CanvasObject)
|
SetContent(content fyne.CanvasObject)
|
||||||
Show()
|
Show()
|
||||||
InitLayout()
|
InitLayout()
|
||||||
|
NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
type mainWindow struct {
|
type mainWindow struct {
|
||||||
@ -20,7 +23,7 @@ type mainWindow struct {
|
|||||||
progressBarService application.ProgressBarContract
|
progressBarService application.ProgressBarContract
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMainWindow(fyneWindow fyne.Window, progressBarService application.ProgressBarContract) MainWindowContract {
|
func NewMainWindow(fyneWindow fyne.Window, progressBarService application.ProgressBarContract) WindowContract {
|
||||||
fyneWindow.Resize(fyne.Size{Width: 1039, Height: 599})
|
fyneWindow.Resize(fyne.Size{Width: 1039, Height: 599})
|
||||||
fyneWindow.CenterOnScreen()
|
fyneWindow.CenterOnScreen()
|
||||||
|
|
||||||
@ -40,6 +43,16 @@ func (w *mainWindow) InitLayout() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog {
|
||||||
|
fileDialog := dialog.NewFileOpen(callback, w.fyneWindow)
|
||||||
|
utils.FileDialogResize(fileDialog, w.fyneWindow)
|
||||||
|
fileDialog.Show()
|
||||||
|
if location != nil {
|
||||||
|
fileDialog.SetLocation(location)
|
||||||
|
}
|
||||||
|
return fileDialog
|
||||||
|
}
|
||||||
|
|
||||||
func (w *mainWindow) SetContent(content fyne.CanvasObject) {
|
func (w *mainWindow) SetContent(content fyne.CanvasObject) {
|
||||||
fyne.Do(func() {
|
fyne.Do(func() {
|
||||||
if w.layout == nil {
|
if w.layout == nil {
|
||||||
|
11
internal/utils/dialog.go
Normal file
11
internal/utils/dialog.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/dialog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FileDialogResize(fileDialog *dialog.FileDialog, w fyne.Window) {
|
||||||
|
contentSize := w.Content().Size()
|
||||||
|
fileDialog.Resize(fyne.Size{Width: contentSize.Width - 50, Height: contentSize.Height - 50})
|
||||||
|
}
|
8
internal/utils/path_separator.go
Normal file
8
internal/utils/path_separator.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
func PathSeparator() string {
|
||||||
|
return "/"
|
||||||
|
}
|
8
internal/utils/path_separator_window.go
Normal file
8
internal/utils/path_separator_window.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
func PathSeparator() string {
|
||||||
|
return "\\"
|
||||||
|
}
|
12
internal/utils/prepare_background_command.go
Normal file
12
internal/utils/prepare_background_command.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
//go:build !windows
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrepareBackgroundCommand(cmd *exec.Cmd) {
|
||||||
|
|
||||||
|
}
|
13
internal/utils/prepare_background_command_windows.go
Normal file
13
internal/utils/prepare_background_command_windows.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PrepareBackgroundCommand(cmd *exec.Cmd) {
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
|
||||||
|
}
|
21
internal/utils/text.go
Normal file
21
internal/utils/text.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetStringErrorStyle(text *canvas.Text) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
text.Color = color.RGBA{R: 255, G: 0, B: 0, A: 255}
|
||||||
|
text.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetStringSuccessStyle(text *canvas.Text) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
text.Color = color.RGBA{R: 49, G: 127, B: 114, A: 255}
|
||||||
|
text.Refresh()
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user