Compare commits
144 Commits
1e73a8dc7f
...
develop
Author | SHA1 | Date | |
---|---|---|---|
a8602914ce
|
|||
fb82846e9e
|
|||
4a9182d063
|
|||
799d257e9d
|
|||
6adbff9bbf
|
|||
fc4c916735
|
|||
aaf43c15aa
|
|||
04eb6b87f4
|
|||
26827d5ccd
|
|||
b56199fe8b
|
|||
f6958ffa97
|
|||
7f410ef700
|
|||
c4d205a79e
|
|||
c45c106f2f
|
|||
63c13de181
|
|||
57767de4b3
|
|||
c59c87d109
|
|||
0a22377cd6
|
|||
7930a907f1
|
|||
850cbbaf70
|
|||
f4604f94c6
|
|||
077d7a82a9
|
|||
e6db590937
|
|||
d7428683e4
|
|||
a9c59137af
|
|||
c8619cdc7f
|
|||
c49957e583
|
|||
39080cac14
|
|||
cae996a141
|
|||
fc4e585620
|
|||
690f84e2c8
|
|||
568d8f0897
|
|||
2909ef7cea
|
|||
1b1cdd5c22
|
|||
eb43669ae7
|
|||
29ca392880
|
|||
df8095fb16
|
|||
e48f363de0
|
|||
9bb835beaf
|
|||
9cdfa18fc8
|
|||
6c0abac1c5
|
|||
394824ce88
|
|||
6e8b148c81
|
|||
57637606c0
|
|||
c60b9f7b0c
|
|||
b24155caf6
|
|||
43d794373a
|
|||
3241b88158
|
|||
d69767f5e9
|
|||
7340f43d6e
|
|||
5ab11922b9
|
|||
5f72ce8c56
|
|||
5b15848048
|
|||
84b36dd29e
|
|||
82167f042f
|
|||
712ec2f182
|
|||
883bf376b0
|
|||
306383449a
|
|||
a831d56d93
|
|||
9d46db43c2
|
|||
46d210d6d5
|
|||
3149ca25e1
|
|||
992762ef0a
|
|||
411e6c554a
|
|||
bf3340e526
|
|||
6be10dbd75
|
|||
16b32e0167
|
|||
2a7d860cbf
|
|||
cf2a0933b4
|
|||
fa6c929ec8
|
|||
cce45ee791
|
|||
da7d9c8035
|
|||
17c570bf1d
|
|||
86886fb5d9
|
|||
f262d5f931
|
|||
12dc5c8ef9
|
|||
9aaee4c183
|
|||
2017617614
|
|||
21d4afcedb
|
|||
8347e9fbb2
|
|||
8d17a52f00
|
|||
4668da3223
|
|||
a3b30c4543
|
|||
3f358c8b7d
|
|||
7b7c15ad27
|
|||
a95692196e
|
|||
68d9c4bb66
|
|||
1ece1e443d
|
|||
1eb7ea4a93
|
|||
e766c6d465
|
|||
1f9f646f51
|
|||
d88586739a
|
|||
a3db2b8f89 | |||
d0539f5e90
|
|||
240ae7aa96
|
|||
0d05fdb307
|
|||
8e6fb90482
|
|||
bab8c1f383
|
|||
a1c9143685
|
|||
c4ec958576
|
|||
359db74251 | |||
154cd1c7dd
|
|||
a617635911
|
|||
48f8c577c0
|
|||
ee0a305972
|
|||
3dc59344cb
|
|||
f631c55eae | |||
d46d642e61
|
|||
a82d283c1a
|
|||
b7c363faaa
|
|||
2c0e20210f
|
|||
eec298bfd7
|
|||
2afc5f5b1a
|
|||
fd7ce5fa08
|
|||
05553f06b8
|
|||
0d5cfab38d
|
|||
d86c0d37af
|
|||
f09dd01b6d
|
|||
6358d5d8cc
|
|||
5025807b14
|
|||
0cd32bb0f0 | |||
f3e034356b
|
|||
6f0bbf7e29
|
|||
3c563d1966
|
|||
6df775955f
|
|||
d68382e418
|
|||
846986279c
|
|||
adf9bc9c27
|
|||
c572a3cabe | |||
7cc22e1553
|
|||
9bb19a0263
|
|||
fc38a1b20c
|
|||
2596e822bd
|
|||
4fa977347c
|
|||
77b847dde6
|
|||
ebc8832d4d
|
|||
5051c65ec6
|
|||
10aa917c24
|
|||
1070b796cc
|
|||
176189c9d0
|
|||
dddbfa65bc
|
|||
97dd0f4b32
|
|||
5a4c960201
|
|||
e288d5efbb
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fyne-cross/*
|
||||||
|
ffmpeg/*
|
14
FyneApp.toml
Normal file
14
FyneApp.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
Website = "https://gui-for-ffmpeg.projects.kor-elf.net/language/en"
|
||||||
|
|
||||||
|
[Details]
|
||||||
|
Icon = "assets/icon.png"
|
||||||
|
Name = "GUI for FFmpeg"
|
||||||
|
ID = "net.kor-elf.projects.gui-for-ffmpeg"
|
||||||
|
Version = "1.0.1"
|
||||||
|
Build = 98
|
||||||
|
|
||||||
|
[LinuxAndBSD]
|
||||||
|
GenericName = "GUI for FFmpeg"
|
||||||
|
Categories = ["AudioVideo", "Utility"]
|
||||||
|
Comment = "A simple interface for the FFmpeg console utility."
|
||||||
|
Keywords = ["ffmpeg", "media", "convert", "transcode", "audio", "video", "конвертер", "видео", "аудио", "кодек"]
|
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 kor-elf
|
Copyright (c) 2024 Leonid Nikitin (kor-elf)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
2426
LICENSE-3RD-PARTY.txt
Normal file
2426
LICENSE-3RD-PARTY.txt
Normal file
File diff suppressed because it is too large
Load Diff
88
Makefile
Normal file
88
Makefile
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
VERSION ?= $(shell grep '^ *Version *= *' FyneApp.toml | sed -E "s/.*=[[:space:]]*\"([0-9\.]+)\".*/\1/")
|
||||||
|
|
||||||
|
BUILD_TMP := fyne-cross/tmp
|
||||||
|
|
||||||
|
WINDOWS_AMD64 := gui-for-ffmpeg-$(VERSION)-windows-amd64
|
||||||
|
BUILD_TMP_WINDOWS_AMD64 := $(BUILD_TMP)/$(WINDOWS_AMD64)
|
||||||
|
|
||||||
|
LINUX_AMD64 := gui-for-ffmpeg-$(VERSION)-linux-amd64
|
||||||
|
BUILD_TMP_LINUX_AMD64 := $(BUILD_TMP)/$(LINUX_AMD64)
|
||||||
|
|
||||||
|
RELEASES := fyne-cross/releases/$(VERSION)
|
||||||
|
|
||||||
|
default:
|
||||||
|
# Run "make build-for-linux_amd64"
|
||||||
|
# Run "make build-for-windows_amd64"
|
||||||
|
# Build for all
|
||||||
|
# Run "make build"
|
||||||
|
|
||||||
|
build:
|
||||||
|
make build-for-linux_amd64
|
||||||
|
make build-for-windows_amd64
|
||||||
|
# $(RELEASES)/$(LINUX_AMD64).tar.gz
|
||||||
|
# $(RELEASES)/$(LINUX_AMD64).tar.gz.sha256
|
||||||
|
# $(RELEASES)/$(WINDOWS_AMD64).zip
|
||||||
|
# $(RELEASES)/$(WINDOWS_AMD64).zip.sha256
|
||||||
|
|
||||||
|
build-for-windows_amd64:
|
||||||
|
fyne-cross windows
|
||||||
|
|
||||||
|
@if [ -d $(BUILD_TMP_WINDOWS_AMD64) ]; then \
|
||||||
|
rm -rf $(BUILD_TMP_WINDOWS_AMD64)/*; \
|
||||||
|
else \
|
||||||
|
mkdir -p $(BUILD_TMP_WINDOWS_AMD64); \
|
||||||
|
fi
|
||||||
|
cp LICENSE $(BUILD_TMP_WINDOWS_AMD64)/LICENSE
|
||||||
|
cp LICENSE-3RD-PARTY.txt $(BUILD_TMP_WINDOWS_AMD64)/LICENSE-3RD-PARTY.txt
|
||||||
|
cp "fyne-cross/bin/windows-amd64/GUI for FFmpeg.exe" $(BUILD_TMP_WINDOWS_AMD64)/gui-for-ffmpeg.exe
|
||||||
|
cd $(BUILD_TMP) && 7z a -tzip $(WINDOWS_AMD64).zip $(WINDOWS_AMD64)
|
||||||
|
|
||||||
|
@if [ ! -d $(RELEASES) ]; then \
|
||||||
|
mkdir -p $(RELEASES); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
@if [ -f $(RELEASES)/$(WINDOWS_AMD64).zip ]; then \
|
||||||
|
rm $(RELEASES)/$(WINDOWS_AMD64).zip; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
@if [ -f $(RELEASES)/$(WINDOWS_AMD64).zip.sha256 ]; then \
|
||||||
|
rm $(RELEASES)/$(WINDOWS_AMD64).zip.sha256; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv $(BUILD_TMP)/$(WINDOWS_AMD64).zip $(RELEASES)/$(WINDOWS_AMD64).zip
|
||||||
|
cd $(RELEASES) && sha256sum $(WINDOWS_AMD64).zip > $(WINDOWS_AMD64).zip.sha256
|
||||||
|
# $(RELEASES)/$(WINDOWS_AMD64).zip
|
||||||
|
# $(RELEASES)/$(WINDOWS_AMD64).zip.sha256
|
||||||
|
|
||||||
|
build-for-linux_amd64:
|
||||||
|
fyne-cross linux
|
||||||
|
|
||||||
|
@if [ -d $(BUILD_TMP_LINUX_AMD64) ]; then \
|
||||||
|
rm -rf $(BUILD_TMP_LINUX_AMD64)/*; \
|
||||||
|
else \
|
||||||
|
mkdir -p $(BUILD_TMP_LINUX_AMD64); \
|
||||||
|
fi
|
||||||
|
cp -r dist/linux/* $(BUILD_TMP_LINUX_AMD64)/
|
||||||
|
cp LICENSE $(BUILD_TMP_LINUX_AMD64)/LICENSE
|
||||||
|
cp LICENSE-3RD-PARTY.txt $(BUILD_TMP_LINUX_AMD64)/LICENSE-3RD-PARTY.txt
|
||||||
|
cp fyne-cross/bin/linux-amd64/gui-for-ffmpeg $(BUILD_TMP_LINUX_AMD64)/usr/local/bin/gui-for-ffmpeg
|
||||||
|
cp assets/icon.png $(BUILD_TMP_LINUX_AMD64)/usr/local/share/pixmaps/gui-for-ffmpeg.png
|
||||||
|
|
||||||
|
cd $(BUILD_TMP) && tar -czvf $(LINUX_AMD64).tar.gz $(LINUX_AMD64)
|
||||||
|
|
||||||
|
@if [ ! -d $(RELEASES) ]; then \
|
||||||
|
mkdir -p $(RELEASES); \
|
||||||
|
fi
|
||||||
|
|
||||||
|
@if [ -f $(RELEASES)/$(LINUX_AMD64).tar.gz ]; then \
|
||||||
|
rm $(RELEASES)/$(LINUX_AMD64).tar.gz; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
@if [ -f $(RELEASES)/$(LINUX_AMD64).tar.gz.sha256 ]; then \
|
||||||
|
rm $(RELEASES)/$(LINUX_AMD64).tar.gz.sha256; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv $(BUILD_TMP)/$(LINUX_AMD64).tar.gz $(RELEASES)/$(LINUX_AMD64).tar.gz
|
||||||
|
cd $(RELEASES) && sha256sum $(LINUX_AMD64).tar.gz > $(LINUX_AMD64).tar.gz.sha256
|
||||||
|
# $(RELEASES)/$(LINUX_AMD64).tar.gz
|
||||||
|
# $(RELEASES)/$(LINUX_AMD64).tar.gz.sha256
|
40
README.md
40
README.md
@@ -1,3 +1,39 @@
|
|||||||
# ffmpeg-gui
|
# GUI for FFmpeg
|
||||||
|
|
||||||
Простенький интерфейс к программе ffmpeg.
|
<p>Простенький интерфейс для консольной утилиты FFmpeg. Но я <strong>не являюсь</strong> автором самой утилиты <strong>FFmpeg</strong>.</p>
|
||||||
|
<p><strong>FFmpeg</strong> — торговая марка <strong><a href="https://bellard.org/" target="_blank">Fabrice Bellard</a></strong>, создателя проекта <strong><a href="https://ffmpeg.org/about.html" target="_blank">FFmpeg</a></strong>.</p>
|
||||||
|
|
||||||
|
<p>Программное обеспечение является MIT (см. <a href="https://git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE">LICENSE</a>) и использует сторонние библиотеки, которые распространяются на их собственных условиях (см. <a href="https://git.kor-elf.net/kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE-3RD-PARTY.txt">LICENSE-3RD-PARTY.txt</a>).</p>
|
||||||
|
|
||||||
|
<img src="assets/screenshot-gui-for-ffmpeg.png" alt="Скриншот программы">
|
||||||
|
|
||||||
|
<p>Скачать скомпилированные готовые версии можно тут: <a href="https://git.kor-elf.net/kor-elf/gui-for-ffmpeg/releases">https://git.kor-elf.net/kor-elf/gui-for-ffmpeg/releases</a>.</p>
|
||||||
|
|
||||||
|
## Установка через fyne:
|
||||||
|
1. go install fyne.io/fyne/v2/cmd/fyne@latest
|
||||||
|
2. fyne get git.kor-elf.net/kor-elf/gui-for-ffmpeg
|
||||||
|
|
||||||
|
## Скомпилировать через Makefile:
|
||||||
|
1. git clone https://git.kor-elf.net/kor-elf/gui-for-ffmpeg.git
|
||||||
|
2. Переходим в папку проекта и там переходим в папку src: **cd gui-for-ffmpeg**
|
||||||
|
3. Ознакамливаемся, что нужно ещё установить для Вашей ОС для простого запуска (через go run) тут: https://docs.fyne.io/started/
|
||||||
|
4. go install github.com/fyne-io/fyne-cross@latest
|
||||||
|
* У Вас так же должен быть установлен docker
|
||||||
|
* О fyne-cross можно по подробней почитать тут: https://github.com/fyne-io/fyne-cross
|
||||||
|
5. * make build-for-linux_amd64
|
||||||
|
* make build-for-windows_amd64
|
||||||
|
* Или просто **make build**
|
||||||
|
6. Создаться папка с архивом в **fyne-cross/releases**
|
||||||
|
|
||||||
|
## Скомпилировать через исходники:
|
||||||
|
1. git clone https://git.kor-elf.net/kor-elf/gui-for-ffmpeg.git
|
||||||
|
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
|
||||||
|
* У Вас так же должен быть установлен docker
|
||||||
|
* О fyne-cross можно по подробней почитать тут: https://github.com/fyne-io/fyne-cross
|
||||||
|
6. * fyne-cross windows
|
||||||
|
* fyne-cross linux
|
||||||
|
7. Создаться папка **fyne-cross/dist** и там будет созданна папка с тем названием под которую Вы компилировали приложения (linux-amd64 или windows-amd64).
|
||||||
|
8. В папке **fyne-cross/dist/linux-amd64** или **fyne-cross/dist/windows-amd64** будут архивы, которые надо распаковать и пользоваться программой.
|
||||||
|
BIN
assets/icon.png
Normal file
BIN
assets/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
assets/screenshot-gui-for-ffmpeg.png
Normal file
BIN
assets/screenshot-gui-for-ffmpeg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
39
dist/linux/Makefile
vendored
Normal file
39
dist/linux/Makefile
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# If PREFIX isn't provided, we check for $(DESTDIR)/usr/local and use that if it exists.
|
||||||
|
# Otherwice we fall back to using /usr.
|
||||||
|
|
||||||
|
LOCAL != test -d $(DESTDIR)/usr/local && echo -n "/local" || echo -n ""
|
||||||
|
LOCAL ?= $(shell test -d $(DESTDIR)/usr/local && echo "/local" || echo "")
|
||||||
|
PREFIX ?= /usr$(LOCAL)
|
||||||
|
|
||||||
|
Name := "gui-for-ffmpeg"
|
||||||
|
Exec := "gui-for-ffmpeg"
|
||||||
|
Icon := "gui-for-ffmpeg.png"
|
||||||
|
|
||||||
|
default:
|
||||||
|
# User install
|
||||||
|
# Run "make user-install" to install in ~/.local/
|
||||||
|
# Run "make user-uninstall" to uninstall from ~/.local/
|
||||||
|
#
|
||||||
|
# System install
|
||||||
|
# Run "sudo make install" to install the application.
|
||||||
|
# Run "sudo make uninstall" to uninstall the application.
|
||||||
|
|
||||||
|
install:
|
||||||
|
install -Dm00644 usr/local/share/applications/$(Name).desktop $(DESTDIR)$(PREFIX)/share/applications/$(Name).desktop
|
||||||
|
install -Dm00755 usr/local/bin/$(Exec) $(DESTDIR)$(PREFIX)/bin/$(Exec)
|
||||||
|
install -Dm00644 usr/local/share/pixmaps/$(Icon) $(DESTDIR)$(PREFIX)/share/pixmaps/$(Icon)
|
||||||
|
uninstall:
|
||||||
|
-rm $(DESTDIR)$(PREFIX)/share/applications/$(Name).desktop
|
||||||
|
-rm $(DESTDIR)$(PREFIX)/bin/$(Exec)
|
||||||
|
-rm $(DESTDIR)$(PREFIX)/share/pixmaps/$(Icon)
|
||||||
|
|
||||||
|
user-install:
|
||||||
|
install -Dm00644 usr/local/share/applications/$(Name).desktop $(DESTDIR)$(HOME)/.local/share/applications/$(Name).desktop
|
||||||
|
install -Dm00755 usr/local/bin/$(Exec) $(DESTDIR)$(HOME)/.local/bin/$(Exec)
|
||||||
|
install -Dm00644 usr/local/share/pixmaps/$(Icon) $(DESTDIR)$(HOME)/.local/share/icons/$(Icon)
|
||||||
|
sed -i -e "s,Exec=$(Exec),Exec=$(DESTDIR)$(HOME)/.local/bin/$(Exec),g" $(DESTDIR)$(HOME)/.local/share/applications/$(Name).desktop
|
||||||
|
|
||||||
|
user-uninstall:
|
||||||
|
-rm $(DESTDIR)$(HOME)/.local/share/applications/$(Name).desktop
|
||||||
|
-rm $(DESTDIR)$(HOME)/.local/bin/$(Exec)
|
||||||
|
-rm $(DESTDIR)$(HOME)/.local/share/icons/$(Icon)
|
12
dist/linux/Readme-eng.txt
vendored
Normal file
12
dist/linux/Readme-eng.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
User install
|
||||||
|
Run "make user-install" to install in ~/.local/
|
||||||
|
Run "make user-uninstall" to uninstall from ~/.local/
|
||||||
|
|
||||||
|
System install
|
||||||
|
Run "sudo make install" to install the application.
|
||||||
|
Run "sudo make uninstall" to uninstall the application.
|
||||||
|
|
||||||
|
|
||||||
|
The program can be launched via the start menu in the Audio/Video or Standard section.
|
||||||
|
You can also call the program via the terminal:
|
||||||
|
gui-for-ffmpeg
|
12
dist/linux/Readme-rus.txt
vendored
Normal file
12
dist/linux/Readme-rus.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Установить для пользователя (рекомендуется)
|
||||||
|
Запустите "make user-install" для установки в домашнюю папку ~/.local/
|
||||||
|
Запустите "make user-uninstall" для удаления из домашней папки ~/.local/
|
||||||
|
|
||||||
|
Установить для всей системы
|
||||||
|
Запустить "sudo make install" Для установки в систему.
|
||||||
|
Запустить "sudo make uninstall" Для удаления из системы.
|
||||||
|
|
||||||
|
|
||||||
|
Программу можно запустить через пуск в разделе Аудио/Видео или Стандартные.
|
||||||
|
Также можно вызвать программу через терминал:
|
||||||
|
gui-for-ffmpeg
|
2
dist/linux/usr/local/bin/.gitignore
vendored
Normal file
2
dist/linux/usr/local/bin/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
9
dist/linux/usr/local/share/applications/gui-for-ffmpeg.desktop
vendored
Normal file
9
dist/linux/usr/local/share/applications/gui-for-ffmpeg.desktop
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=GUI for FFmpeg
|
||||||
|
GenericName=GUI for FFmpeg
|
||||||
|
Exec=gui-for-ffmpeg
|
||||||
|
Icon=gui-for-ffmpeg
|
||||||
|
Comment=A simple interface for the FFmpeg console utility.
|
||||||
|
Categories=AudioVideo;Utility;
|
||||||
|
Keywords=ffmpeg;media;convert;transcode;audio;video;конвертер;видео;аудио;кодек;
|
2
dist/linux/usr/local/share/pixmaps/.gitignore
vendored
Normal file
2
dist/linux/usr/local/share/pixmaps/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
45
go.mod
Normal file
45
go.mod
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
module git.kor-elf.net/kor-elf/gui-for-ffmpeg
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.9
|
||||||
|
|
||||||
|
require (
|
||||||
|
fyne.io/fyne/v2 v2.6.3
|
||||||
|
github.com/ulikunitz/xz v0.5.13
|
||||||
|
golang.org/x/image v0.30.0
|
||||||
|
golang.org/x/text v0.28.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
fyne.io/systray v1.11.0 // indirect
|
||||||
|
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/fredbi/uri v1.1.1 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
|
github.com/fyne-io/gl-js v0.2.0 // indirect
|
||||||
|
github.com/fyne-io/glfw-js v0.3.0 // indirect
|
||||||
|
github.com/fyne-io/image v0.1.1 // indirect
|
||||||
|
github.com/fyne-io/oksvg v0.1.0 // indirect
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 // indirect
|
||||||
|
github.com/go-text/render v0.2.0 // indirect
|
||||||
|
github.com/go-text/typesetting v0.3.0 // indirect
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
github.com/hack-pad/go-indexeddb v0.3.2 // indirect
|
||||||
|
github.com/hack-pad/safejs v0.1.1 // indirect
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade // indirect
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/rymdport/portal v0.4.2 // indirect
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
||||||
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
|
github.com/yuin/goldmark v1.7.13 // indirect
|
||||||
|
golang.org/x/net v0.43.0 // indirect
|
||||||
|
golang.org/x/sys v0.35.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
106
go.sum
Normal file
106
go.sum
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
fyne.io/fyne/v2 v2.6.1 h1:kjPJD4/rBS9m2nHJp+npPSuaK79yj6ObMTuzR6VQ1Is=
|
||||||
|
fyne.io/fyne/v2 v2.6.1/go.mod h1:YZt7SksjvrSNJCwbWFV32WON3mE1Sr7L41D29qMZ/lU=
|
||||||
|
fyne.io/fyne/v2 v2.6.3 h1:cvtM2KHeRuH+WhtHiA63z5wJVBkQ9+Ay0UMl9PxFHyA=
|
||||||
|
fyne.io/fyne/v2 v2.6.3/go.mod h1:NGSurpRElVoI1G3h+ab2df3O5KLGh1CGbsMMcX0bPIs=
|
||||||
|
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
||||||
|
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||||
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||||
|
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||||
|
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
|
||||||
|
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
||||||
|
github.com/fredbi/uri v1.1.1 h1:xZHJC08GZNIUhbP5ImTHnt5Ya0T8FI2VAwI/37kh2Ko=
|
||||||
|
github.com/fredbi/uri v1.1.1/go.mod h1:4+DZQ5zBjEwQCDmXW5JdIjz0PUA+yJbvtBv+u+adr5o=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/fyne-io/gl-js v0.1.0 h1:8luJzNs0ntEAJo+8x8kfUOXujUlP8gB3QMOxO2mUdpM=
|
||||||
|
github.com/fyne-io/gl-js v0.1.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
|
||||||
|
github.com/fyne-io/gl-js v0.2.0 h1:+EXMLVEa18EfkXBVKhifYB6OGs3HwKO3lUElA0LlAjs=
|
||||||
|
github.com/fyne-io/gl-js v0.2.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
|
||||||
|
github.com/fyne-io/glfw-js v0.2.0 h1:8GUZtN2aCoTPNqgRDxK5+kn9OURINhBEBc7M4O1KrmM=
|
||||||
|
github.com/fyne-io/glfw-js v0.2.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
|
||||||
|
github.com/fyne-io/glfw-js v0.3.0 h1:d8k2+Y7l+zy2pc7wlGRyPfTgZoqDf3AI4G+2zOWhWUk=
|
||||||
|
github.com/fyne-io/glfw-js v0.3.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
|
||||||
|
github.com/fyne-io/image v0.1.1 h1:WH0z4H7qfvNUw5l4p3bC1q70sa5+YWVt6HCj7y4VNyA=
|
||||||
|
github.com/fyne-io/image v0.1.1/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
|
||||||
|
github.com/fyne-io/oksvg v0.1.0 h1:7EUKk3HV3Y2E+qypp3nWqMXD7mum0hCw2KEGhI1fnBw=
|
||||||
|
github.com/fyne-io/oksvg v0.1.0/go.mod h1:dJ9oEkPiWhnTFNCmRgEze+YNprJF7YRbpjgpWS4kzoI=
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728 h1:RkGhqHxEVAvPM0/R+8g7XRwQnHatO0KAuVcwHo8q9W8=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20250301202403-da16c1255728/go.mod h1:SyRD8YfuKk+ZXlDqYiqe1qMSqjNgtHzBTG810KUagMc=
|
||||||
|
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
|
||||||
|
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
|
||||||
|
github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
|
||||||
|
github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY=
|
||||||
|
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
|
||||||
|
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||||
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||||
|
github.com/hack-pad/go-indexeddb v0.3.2 h1:DTqeJJYc1usa45Q5r52t01KhvlSN02+Oq+tQbSBI91A=
|
||||||
|
github.com/hack-pad/go-indexeddb v0.3.2/go.mod h1:QvfTevpDVlkfomY498LhstjwbPW6QC4VC/lxYb0Kom0=
|
||||||
|
github.com/hack-pad/safejs v0.1.1 h1:d5qPO0iQ7h2oVtpzGnLExE+Wn9AtytxIfltcS2b9KD8=
|
||||||
|
github.com/hack-pad/safejs v0.1.1/go.mod h1:HdS+bKF1NrE72VoXZeWzxFOVQVUSqZJAG0xNCnb+Tio=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20250421151639-a9d6ed1b3d45 h1:vFdvrlsVU+p/KFBWTq0lTG4fvWvG88sawGlCzM+RUEU=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20250421151639-a9d6ed1b3d45/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade h1:FmusiCI1wHw+XQbvL9M+1r/C3SPqKrmBaIOYwVfQoDE=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20250612000132-0ef82f21eade/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||||
|
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rymdport/portal v0.4.1 h1:2dnZhjf5uEaeDjeF/yBIeeRo6pNI2QAKm7kq1w/kbnA=
|
||||||
|
github.com/rymdport/portal v0.4.1/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||||
|
github.com/rymdport/portal v0.4.2 h1:7jKRSemwlTyVHHrTGgQg7gmNPJs88xkbKcIL3NlcmSU=
|
||||||
|
github.com/rymdport/portal v0.4.2/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||||
|
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/ulikunitz/xz v0.5.13 h1:ar98gWrjf4H1ev05fYP/o29PDZw9DrI3niHtnEqyuXA=
|
||||||
|
github.com/ulikunitz/xz v0.5.13/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/yuin/goldmark v1.7.11 h1:ZCxLyDMtz0nT2HFfsYG8WZ47Trip2+JyLysKcMYE5bo=
|
||||||
|
github.com/yuin/goldmark v1.7.11/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||||
|
github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA=
|
||||||
|
github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||||
|
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||||
|
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||||
|
golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4=
|
||||||
|
golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c=
|
||||||
|
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||||
|
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||||
|
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||||
|
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||||
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||||
|
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||||
|
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||||
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
137
internal/application/app.go
Normal file
137
internal/application/app.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package application
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AppContract interface {
|
||||||
|
FyneApp() fyne.App
|
||||||
|
GetSetting() setting.SettingContract
|
||||||
|
GetProgressBarService() convertor.ProgressBarContract
|
||||||
|
GetFFmpegService() ffmpeg.UtilitiesContract
|
||||||
|
GetConvertorService() convertor.ConvertorContract
|
||||||
|
GetItemsToConvert() convertor.ItemsToConvertContract
|
||||||
|
GetQueueService() convertor.QueueListContract
|
||||||
|
Run()
|
||||||
|
AfterClosing()
|
||||||
|
RunConvertor()
|
||||||
|
}
|
||||||
|
|
||||||
|
type application struct {
|
||||||
|
fyneApp fyne.App
|
||||||
|
setting setting.SettingContract
|
||||||
|
progressBarService convertor.ProgressBarContract
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract
|
||||||
|
itemsToConvert convertor.ItemsToConvertContract
|
||||||
|
queueService convertor.QueueListContract
|
||||||
|
convertorService convertor.ConvertorContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApp(
|
||||||
|
fyneApp fyne.App,
|
||||||
|
setting setting.SettingContract,
|
||||||
|
progressBarService convertor.ProgressBarContract,
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract,
|
||||||
|
itemsToConvert convertor.ItemsToConvertContract,
|
||||||
|
queueService convertor.QueueListContract,
|
||||||
|
convertorService convertor.ConvertorContract,
|
||||||
|
) AppContract {
|
||||||
|
return &application{
|
||||||
|
fyneApp: fyneApp,
|
||||||
|
setting: setting,
|
||||||
|
progressBarService: progressBarService,
|
||||||
|
ffmpegService: ffmpegService,
|
||||||
|
itemsToConvert: itemsToConvert,
|
||||||
|
queueService: queueService,
|
||||||
|
convertorService: convertorService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) FyneApp() fyne.App {
|
||||||
|
return a.fyneApp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetSetting() setting.SettingContract {
|
||||||
|
return a.setting
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetProgressBarService() convertor.ProgressBarContract {
|
||||||
|
return a.progressBarService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetFFmpegService() ffmpeg.UtilitiesContract {
|
||||||
|
return a.ffmpegService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetItemsToConvert() convertor.ItemsToConvertContract {
|
||||||
|
return a.itemsToConvert
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetQueueService() convertor.QueueListContract {
|
||||||
|
return a.queueService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) GetConvertorService() convertor.ConvertorContract {
|
||||||
|
return a.convertorService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) Run() {
|
||||||
|
a.fyneApp.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) RunConvertor() {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
time.Sleep(time.Millisecond * 3000)
|
||||||
|
queueId, queue := a.queueService.Next()
|
||||||
|
if queue == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.Status = convertor.StatusType(convertor.InProgress)
|
||||||
|
a.queueService.EventChangeQueue(queueId, queue)
|
||||||
|
|
||||||
|
if a.progressBarService.GetContainer().Hidden {
|
||||||
|
a.progressBarService.GetContainer().Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
totalDuration := float64(0)
|
||||||
|
ffprobe, err := a.ffmpegService.GetFFprobe()
|
||||||
|
if err == nil {
|
||||||
|
totalDuration, err = ffprobe.GetTotalDuration(&queue.Setting.FileInput)
|
||||||
|
if err != nil {
|
||||||
|
totalDuration = float64(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progress := a.progressBarService.GetProgressbar(
|
||||||
|
totalDuration,
|
||||||
|
queue.Setting.FileInput.Path,
|
||||||
|
)
|
||||||
|
|
||||||
|
err = a.convertorService.RunConvert(*queue.Setting, progress)
|
||||||
|
if err != nil {
|
||||||
|
queue.Status = convertor.StatusType(convertor.Error)
|
||||||
|
queue.Error = err
|
||||||
|
a.queueService.EventChangeQueue(queueId, queue)
|
||||||
|
a.progressBarService.ProcessEndedWithError(err.Error())
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
queue.Status = convertor.StatusType(convertor.Completed)
|
||||||
|
a.queueService.EventChangeQueue(queueId, queue)
|
||||||
|
a.progressBarService.ProcessEndedWithSuccess(&queue.Setting.FileOut)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *application) AfterClosing() {
|
||||||
|
for _, cmd := range a.convertorService.GetRunningProcesses() {
|
||||||
|
_ = cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
}
|
87
internal/application/convertor/convertor.go
Normal file
87
internal/application/convertor/convertor.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package convertor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConvertorContract interface {
|
||||||
|
RunConvert(setting ffmpeg.ConvertSetting, progress ffmpeg.ProgressContract) error
|
||||||
|
GetSupportFormats() (encoder.ConvertorFormatsContract, error)
|
||||||
|
GetRunningProcesses() map[int]*exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type runningProcesses struct {
|
||||||
|
items map[int]*exec.Cmd
|
||||||
|
numberOfStarts int
|
||||||
|
}
|
||||||
|
|
||||||
|
type convertor struct {
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract
|
||||||
|
runningProcesses *runningProcesses
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConvertor(
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract,
|
||||||
|
) ConvertorContract {
|
||||||
|
return &convertor{
|
||||||
|
ffmpegService: ffmpegService,
|
||||||
|
runningProcesses: &runningProcesses{items: map[int]*exec.Cmd{}, numberOfStarts: 0},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *convertor) RunConvert(setting ffmpeg.ConvertSetting, progress ffmpeg.ProgressContract) error {
|
||||||
|
ffmpegService, err := c.ffmpegService.GetFFmpeg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
index := c.runningProcesses.numberOfStarts
|
||||||
|
beforeWait := func(cmd *exec.Cmd) {
|
||||||
|
c.runningProcesses.numberOfStarts++
|
||||||
|
c.runningProcesses.items[index] = cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
afterWait := func(cmd *exec.Cmd) {
|
||||||
|
delete(c.runningProcesses.items, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ffmpegService.RunConvert(setting, progress, beforeWait, afterWait)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *convertor) GetSupportFormats() (encoder.ConvertorFormatsContract, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
formats := encoder.NewConvertorFormats()
|
||||||
|
ffmpeg, err := c.ffmpegService.GetFFmpeg()
|
||||||
|
if err != nil {
|
||||||
|
return formats, err
|
||||||
|
}
|
||||||
|
err = ffmpeg.GetEncoders(func(scanner *bufio.Reader) {
|
||||||
|
for {
|
||||||
|
line, _, err := scanner.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
text := strings.Split(strings.TrimSpace(string(line)), " ")
|
||||||
|
encoderType := string(text[0][0])
|
||||||
|
if len(text) < 2 || (encoderType != "V" && encoderType != "A") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formats.NewEncoder(text[1])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return formats, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *convertor) GetRunningProcesses() map[int]*exec.Cmd {
|
||||||
|
return c.runningProcesses.items
|
||||||
|
}
|
84
internal/application/convertor/encoder/encoder.go
Normal file
84
internal/application/convertor/encoder/encoder.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConvertorFormatContract interface {
|
||||||
|
GetTitle() string
|
||||||
|
AddEncoder(encoder encoder.EncoderDataContract)
|
||||||
|
GetFileType() encoder.FileTypeContract
|
||||||
|
GetEncoders() map[int]encoder.EncoderDataContract
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConvertorFormat struct {
|
||||||
|
title string
|
||||||
|
fileType encoder.FileTypeContract
|
||||||
|
encoders map[int]encoder.EncoderDataContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConvertorFormat(title string, fileType encoder.FileTypeContract) ConvertorFormatContract {
|
||||||
|
return &ConvertorFormat{
|
||||||
|
title: title,
|
||||||
|
fileType: fileType,
|
||||||
|
encoders: map[int]encoder.EncoderDataContract{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormat) GetTitle() string {
|
||||||
|
return f.title
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormat) AddEncoder(encoder encoder.EncoderDataContract) {
|
||||||
|
f.encoders[len(f.encoders)] = encoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormat) GetEncoders() map[int]encoder.EncoderDataContract {
|
||||||
|
return f.encoders
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormat) GetFileType() encoder.FileTypeContract {
|
||||||
|
return f.fileType
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConvertorFormatsContract interface {
|
||||||
|
NewEncoder(encoderName string) bool
|
||||||
|
GetFormats() map[string]ConvertorFormatContract
|
||||||
|
GetFormat(format string) (ConvertorFormatContract, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConvertorFormats struct {
|
||||||
|
formats map[string]ConvertorFormatContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConvertorFormats() ConvertorFormatsContract {
|
||||||
|
return &ConvertorFormats{
|
||||||
|
formats: map[string]ConvertorFormatContract{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormats) NewEncoder(encoderName string) bool {
|
||||||
|
if supportEncoders[encoderName] == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
data := supportEncoders[encoderName]()
|
||||||
|
for _, format := range data.GetFormats() {
|
||||||
|
if f.formats[format] == nil {
|
||||||
|
f.formats[format] = NewConvertorFormat(format, data.GetFileType())
|
||||||
|
}
|
||||||
|
f.formats[format].AddEncoder(data)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormats) GetFormats() map[string]ConvertorFormatContract {
|
||||||
|
return f.formats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ConvertorFormats) GetFormat(format string) (ConvertorFormatContract, error) {
|
||||||
|
if f.formats[format] == nil {
|
||||||
|
return &ConvertorFormat{}, errors.New("not found ConvertorFormat")
|
||||||
|
}
|
||||||
|
return f.formats[format], nil
|
||||||
|
}
|
74
internal/application/convertor/encoder/encoders.go
Normal file
74
internal/application/convertor/encoder/encoders.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import (
|
||||||
|
encoder2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/apng"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/bmp"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/flv"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/gif"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/h264_nvenc"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libmp3lame"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libshine"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libtwolame"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libvpx"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libvpx_vp9"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libwebp"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libwebp_anim"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx264"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx265"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libxvid"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mjpeg"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mp2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mp2fixed"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mpeg1video"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mpeg2video"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/mpeg4"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/msmpeg4"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/msmpeg4v2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/msvideo1"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/png"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/qtrle"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/sgi"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/tiff"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/wmav1"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/wmav2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/wmv1"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/wmv2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/xbm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportEncoders = map[string]func() encoder2.EncoderDataContract{
|
||||||
|
"libx264": libx264.NewData,
|
||||||
|
"h264_nvenc": h264_nvenc.NewData,
|
||||||
|
"libx265": libx265.NewData,
|
||||||
|
"png": png.NewData,
|
||||||
|
"gif": gif.NewData,
|
||||||
|
"flv": flv.NewData,
|
||||||
|
"apng": apng.NewData,
|
||||||
|
"bmp": bmp.NewData,
|
||||||
|
"mjpeg": mjpeg.NewData,
|
||||||
|
"mpeg1video": mpeg1video.NewData,
|
||||||
|
"mpeg2video": mpeg2video.NewData,
|
||||||
|
"mpeg4": mpeg4.NewData,
|
||||||
|
"libxvid": libxvid.NewData,
|
||||||
|
"msmpeg4v2": msmpeg4v2.NewData,
|
||||||
|
"msmpeg4": msmpeg4.NewData,
|
||||||
|
"msvideo1": msvideo1.NewData,
|
||||||
|
"qtrle": qtrle.NewData,
|
||||||
|
"tiff": tiff.NewData,
|
||||||
|
"sgi": sgi.NewData,
|
||||||
|
"libvpx": libvpx.NewData,
|
||||||
|
"libvpx-vp9": libvpx_vp9.NewData,
|
||||||
|
"libwebp_anim": libwebp_anim.NewData,
|
||||||
|
"libwebp": libwebp.NewData,
|
||||||
|
"wmv1": wmv1.NewData,
|
||||||
|
"wmv2": wmv2.NewData,
|
||||||
|
"xbm": xbm.NewData,
|
||||||
|
"mp2": mp2.NewData,
|
||||||
|
"mp2fixed": mp2fixed.NewData,
|
||||||
|
"libtwolame": libtwolame.NewData,
|
||||||
|
"libmp3lame": libmp3lame.NewData,
|
||||||
|
"libshine": libshine.NewData,
|
||||||
|
"wmav1": wmav1.NewData,
|
||||||
|
"wmav2": wmav2.NewData,
|
||||||
|
}
|
139
internal/application/convertor/items_to_convert.go
Normal file
139
internal/application/convertor/items_to_convert.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package convertor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ItemsToConvertContract interface {
|
||||||
|
Add(file *ffmpeg.File)
|
||||||
|
Clear()
|
||||||
|
GetItems() map[int]ItemToConvertContract
|
||||||
|
GetItemsContainer() *fyne.Container
|
||||||
|
AfterAddingQueue()
|
||||||
|
GetIsAutoRemove() bool
|
||||||
|
SetIsAutoRemove(isAutoRemove bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
type itemsToConvert struct {
|
||||||
|
ffmpeg ffmpeg.UtilitiesContract
|
||||||
|
nextId int
|
||||||
|
items map[int]ItemToConvertContract
|
||||||
|
itemsContainer *fyne.Container
|
||||||
|
isAutoRemove bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewItemsToConvert(ffmpeg ffmpeg.UtilitiesContract) ItemsToConvertContract {
|
||||||
|
return &itemsToConvert{
|
||||||
|
ffmpeg: ffmpeg,
|
||||||
|
nextId: 0,
|
||||||
|
items: map[int]ItemToConvertContract{},
|
||||||
|
itemsContainer: container.NewVBox(),
|
||||||
|
isAutoRemove: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) GetItemsContainer() *fyne.Container {
|
||||||
|
return items.itemsContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) Add(file *ffmpeg.File) {
|
||||||
|
nextId := items.nextId
|
||||||
|
var content *fyne.Container
|
||||||
|
var buttonPlay *widget.Button
|
||||||
|
|
||||||
|
buttonPlay = widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||||
|
buttonPlay.Disable()
|
||||||
|
go func() {
|
||||||
|
ffplay, err := items.ffmpeg.GetFFplay()
|
||||||
|
if err != nil {
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonPlay.Enable()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = ffplay.Play(file)
|
||||||
|
fyne.Do(func() {
|
||||||
|
buttonPlay.Enable()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
})
|
||||||
|
|
||||||
|
buttonRemove := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameDelete), func() {
|
||||||
|
items.itemsContainer.Remove(content)
|
||||||
|
items.itemsContainer.Refresh()
|
||||||
|
delete(items.items, nextId)
|
||||||
|
})
|
||||||
|
buttonRemove.Importance = widget.DangerImportance
|
||||||
|
|
||||||
|
content = container.NewVBox(
|
||||||
|
container.NewBorder(
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
buttonPlay,
|
||||||
|
buttonRemove,
|
||||||
|
container.NewHScroll(widget.NewLabel(file.Name)),
|
||||||
|
),
|
||||||
|
container.NewHScroll(widget.NewLabel(file.Path)),
|
||||||
|
container.NewPadded(),
|
||||||
|
canvas.NewLine(theme.Color(theme.ColorNameFocus)),
|
||||||
|
container.NewPadded(),
|
||||||
|
)
|
||||||
|
|
||||||
|
items.itemsContainer.Add(content)
|
||||||
|
items.items[nextId] = newItemToConvert(file, content)
|
||||||
|
items.nextId++
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) GetIsAutoRemove() bool {
|
||||||
|
return items.isAutoRemove
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) SetIsAutoRemove(isAutoRemove bool) {
|
||||||
|
items.isAutoRemove = isAutoRemove
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) GetItems() map[int]ItemToConvertContract {
|
||||||
|
return items.items
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) AfterAddingQueue() {
|
||||||
|
if items.isAutoRemove {
|
||||||
|
items.Clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (items *itemsToConvert) Clear() {
|
||||||
|
items.itemsContainer.RemoveAll()
|
||||||
|
items.items = map[int]ItemToConvertContract{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ItemToConvertContract interface {
|
||||||
|
GetFile() *ffmpeg.File
|
||||||
|
GetContent() *fyne.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
type itemToConvert struct {
|
||||||
|
file *ffmpeg.File
|
||||||
|
content *fyne.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func newItemToConvert(file *ffmpeg.File, content *fyne.Container) ItemToConvertContract {
|
||||||
|
return &itemToConvert{
|
||||||
|
file: file,
|
||||||
|
content: content,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (item *itemToConvert) GetFile() *ffmpeg.File {
|
||||||
|
return item.file
|
||||||
|
}
|
||||||
|
|
||||||
|
func (item *itemToConvert) GetContent() *fyne.Container {
|
||||||
|
return item.content
|
||||||
|
}
|
217
internal/application/convertor/progressbar.go
Normal file
217
internal/application/convertor/progressbar.go
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
package convertor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProgressBarContract interface {
|
||||||
|
GetContainer() *fyne.Container
|
||||||
|
GetProgressbar(totalDuration float64, filePath string) ffmpeg.ProgressContract
|
||||||
|
ProcessEndedWithError(errorText string)
|
||||||
|
ProcessEndedWithSuccess(file *ffmpeg.File)
|
||||||
|
}
|
||||||
|
|
||||||
|
type progressBar struct {
|
||||||
|
container *fyne.Container
|
||||||
|
label *widget.Label
|
||||||
|
progressbar *widget.ProgressBar
|
||||||
|
errorBlock *container.Scroll
|
||||||
|
messageError *canvas.Text
|
||||||
|
statusMessage *canvas.Text
|
||||||
|
buttonPlay *widget.Button
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProgressBar(ffmpegService ffmpeg.UtilitiesContract) ProgressBarContract {
|
||||||
|
label := widget.NewLabel("")
|
||||||
|
progressbar := widget.NewProgressBar()
|
||||||
|
|
||||||
|
statusMessage := canvas.NewText("", theme.Color(theme.ColorNamePrimary))
|
||||||
|
messageError := canvas.NewText("", theme.Color(theme.ColorNameError))
|
||||||
|
buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||||
|
|
||||||
|
})
|
||||||
|
buttonPlay.Hide()
|
||||||
|
|
||||||
|
errorBlock := container.NewHScroll(messageError)
|
||||||
|
errorBlock.Hide()
|
||||||
|
|
||||||
|
content := container.NewVBox(
|
||||||
|
container.NewHScroll(label),
|
||||||
|
progressbar,
|
||||||
|
container.NewHScroll(container.NewHBox(
|
||||||
|
buttonPlay,
|
||||||
|
statusMessage,
|
||||||
|
)),
|
||||||
|
errorBlock,
|
||||||
|
)
|
||||||
|
content.Hide()
|
||||||
|
|
||||||
|
return &progressBar{
|
||||||
|
container: content,
|
||||||
|
label: label,
|
||||||
|
progressbar: progressbar,
|
||||||
|
errorBlock: errorBlock,
|
||||||
|
messageError: messageError,
|
||||||
|
statusMessage: statusMessage,
|
||||||
|
buttonPlay: buttonPlay,
|
||||||
|
ffmpegService: ffmpegService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *progressBar) GetContainer() *fyne.Container {
|
||||||
|
return p.container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *progressBar) GetProgressbar(totalDuration float64, filePath string) ffmpeg.ProgressContract {
|
||||||
|
p.label.Text = filePath
|
||||||
|
p.statusMessage.Color = theme.Color(theme.ColorNamePrimary)
|
||||||
|
p.statusMessage.Text = lang.L("inProgressQueue")
|
||||||
|
p.messageError.Text = ""
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.buttonPlay.Hide()
|
||||||
|
if p.errorBlock.Visible() {
|
||||||
|
p.errorBlock.Hide()
|
||||||
|
}
|
||||||
|
p.statusMessage.Refresh()
|
||||||
|
p.container.Refresh()
|
||||||
|
p.errorBlock.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
p.progressbar.Value = 0
|
||||||
|
return NewProgress(totalDuration, p.progressbar)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *progressBar) ProcessEndedWithError(errorText string) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.statusMessage.Color = theme.Color(theme.ColorNameError)
|
||||||
|
p.statusMessage.Text = lang.L("errorQueue")
|
||||||
|
p.messageError.Text = errorText
|
||||||
|
p.errorBlock.Show()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *progressBar) ProcessEndedWithSuccess(file *ffmpeg.File) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.statusMessage.Color = color.RGBA{R: 49, G: 127, B: 114, A: 255}
|
||||||
|
p.statusMessage.Text = lang.L("completedQueue")
|
||||||
|
p.buttonPlay.Show()
|
||||||
|
p.buttonPlay.OnTapped = func() {
|
||||||
|
p.buttonPlay.Disable()
|
||||||
|
go func() {
|
||||||
|
ffplay, err := p.ffmpegService.GetFFplay()
|
||||||
|
if err == nil {
|
||||||
|
_ = ffplay.Play(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.buttonPlay.Enable()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Progress struct {
|
||||||
|
totalDuration float64
|
||||||
|
progressbar *widget.ProgressBar
|
||||||
|
protocol string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProgress(totalDuration float64, progressbar *widget.ProgressBar) ffmpeg.ProgressContract {
|
||||||
|
return &Progress{
|
||||||
|
totalDuration: totalDuration,
|
||||||
|
progressbar: progressbar,
|
||||||
|
protocol: "pipe:",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Progress) GetProtocole() string {
|
||||||
|
return p.protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Progress) Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error {
|
||||||
|
isProcessCompleted := false
|
||||||
|
var errorText string
|
||||||
|
|
||||||
|
p.progressbar.Value = 0
|
||||||
|
p.progressbar.Max = p.totalDuration
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.progressbar.Refresh()
|
||||||
|
})
|
||||||
|
progress := 0.0
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
scannerErr := bufio.NewReader(stdErr)
|
||||||
|
for {
|
||||||
|
line, _, err := scannerErr.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data := strings.TrimSpace(string(line))
|
||||||
|
errorText = data
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
scannerOut := bufio.NewReader(stdOut)
|
||||||
|
for {
|
||||||
|
line, _, err := scannerOut.ReadLine()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
data := strings.TrimSpace(string(line))
|
||||||
|
if strings.Contains(data, "progress=end") {
|
||||||
|
p.progressbar.Value = p.totalDuration
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.progressbar.Refresh()
|
||||||
|
})
|
||||||
|
isProcessCompleted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`frame=(\d+)`)
|
||||||
|
a := re.FindAllStringSubmatch(data, -1)
|
||||||
|
|
||||||
|
if len(a) > 0 && len(a[len(a)-1]) > 0 {
|
||||||
|
c, err := strconv.Atoi(a[len(a)-1][len(a[len(a)-1])-1])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
progress = float64(c)
|
||||||
|
}
|
||||||
|
if p.progressbar.Value != progress {
|
||||||
|
p.progressbar.Value = progress
|
||||||
|
fyne.Do(func() {
|
||||||
|
p.progressbar.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isProcessCompleted == false {
|
||||||
|
if len(errorText) == 0 {
|
||||||
|
errorText = lang.L("errorConverter")
|
||||||
|
}
|
||||||
|
return errors.New(errorText)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
152
internal/application/convertor/queue.go
Normal file
152
internal/application/convertor/queue.go
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package convertor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Queue struct {
|
||||||
|
Setting *ffmpeg.ConvertSetting
|
||||||
|
Status StatusContract
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
AddQueue(key int, queue *Queue)
|
||||||
|
ChangeQueue(key int, queue *Queue)
|
||||||
|
RemoveQueue(key int, status StatusContract)
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueueListContract interface {
|
||||||
|
AddListener(queueListener QueueListenerContract)
|
||||||
|
GetItems() map[int]*Queue
|
||||||
|
Add(setting *ffmpeg.ConvertSetting)
|
||||||
|
EventChangeQueue(key int, queue *Queue)
|
||||||
|
Remove(key int)
|
||||||
|
GetItem(key int) (*Queue, error)
|
||||||
|
Next() (key int, queue *Queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
type queueList struct {
|
||||||
|
currentKey int
|
||||||
|
items map[int]*Queue
|
||||||
|
queue map[int]int
|
||||||
|
queueListener map[int]QueueListenerContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQueueList() QueueListContract {
|
||||||
|
return &queueList{
|
||||||
|
currentKey: 0,
|
||||||
|
items: map[int]*Queue{},
|
||||||
|
queue: map[int]int{},
|
||||||
|
queueListener: map[int]QueueListenerContract{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) GetItems() map[int]*Queue {
|
||||||
|
return l.items
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) Add(setting *ffmpeg.ConvertSetting) {
|
||||||
|
queue := Queue{
|
||||||
|
Setting: setting,
|
||||||
|
Status: StatusType(Waiting),
|
||||||
|
}
|
||||||
|
|
||||||
|
l.currentKey += 1
|
||||||
|
l.items[l.currentKey] = &queue
|
||||||
|
l.queue[l.currentKey] = l.currentKey
|
||||||
|
|
||||||
|
l.eventAdd(l.currentKey, &queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) EventChangeQueue(key int, queue *Queue) {
|
||||||
|
l.eventChange(key, queue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) Remove(key int) {
|
||||||
|
if _, ok := l.queue[key]; ok {
|
||||||
|
delete(l.queue, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := l.items[key]; ok {
|
||||||
|
status := l.items[key].Status
|
||||||
|
l.eventRemove(key, status)
|
||||||
|
delete(l.items, 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) Next() (key int, queue *Queue) {
|
||||||
|
statusWaiting := StatusType(Waiting)
|
||||||
|
for key, queueId := range l.queue {
|
||||||
|
if queue, ok := l.items[queueId]; ok {
|
||||||
|
if queue.Status == statusWaiting {
|
||||||
|
return queueId, queue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := l.queue[key]; ok {
|
||||||
|
delete(l.queue, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) eventAdd(key int, queue *Queue) {
|
||||||
|
for _, listener := range l.queueListener {
|
||||||
|
listener.AddQueue(key, queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) eventChange(key int, queue *Queue) {
|
||||||
|
for _, listener := range l.queueListener {
|
||||||
|
listener.ChangeQueue(key, queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueList) eventRemove(key int, status StatusContract) {
|
||||||
|
for _, listener := range l.queueListener {
|
||||||
|
listener.RemoveQueue(key, status)
|
||||||
|
}
|
||||||
|
}
|
40
internal/application/setting/ffmpeg.go
Normal file
40
internal/application/setting/ffmpeg.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package setting
|
||||||
|
|
||||||
|
func (s *setting) GetFFmpegPath() string {
|
||||||
|
path := s.fyneApp.Preferences().String("ffmpegPath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffmpeg"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetFFmpegPath(path string) {
|
||||||
|
s.fyneApp.Preferences().SetString("ffmpegPath", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetFFprobePath() string {
|
||||||
|
path := s.fyneApp.Preferences().String("ffprobePath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffprobe"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetFFprobePath(path string) {
|
||||||
|
s.fyneApp.Preferences().SetString("ffprobePath", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetFFplayPath() string {
|
||||||
|
path := s.fyneApp.Preferences().String("ffplayPath")
|
||||||
|
if path == "" {
|
||||||
|
return "ffplay"
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetFFplayPath(path string) {
|
||||||
|
s.fyneApp.Preferences().SetString("ffplayPath", path)
|
||||||
|
}
|
66
internal/application/setting/lang.go
Normal file
66
internal/application/setting/lang.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package setting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
fyneLang "fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/resources"
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportedLanguages = map[string]Lang{
|
||||||
|
"ru": {Code: "ru", Title: "Русский"},
|
||||||
|
"kk": {Code: "kk", Title: "Қазақ Тілі"},
|
||||||
|
"en": {Code: "en", Title: "English"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type Lang struct {
|
||||||
|
Code string
|
||||||
|
Title string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChangeLang(lang Lang) error {
|
||||||
|
translationsData, err := getTranslations(lang)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
name := fyneLang.SystemLocale().LanguageString()
|
||||||
|
return fyneLang.AddTranslations(fyne.NewStaticResource(name+".json", translationsData))
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultLang() Lang {
|
||||||
|
return supportedLanguages["ru"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTranslations(language Lang) ([]byte, error) {
|
||||||
|
translations := resources.GetTranslations()
|
||||||
|
|
||||||
|
baseJson, err := translations.ReadFile("translations/base." + language.Code + ".json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
appJson, err := translations.ReadFile("translations/app." + language.Code + ".json")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mergeTranslations(baseJson, appJson)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeTranslations(baseJson []byte, appJson []byte) ([]byte, error) {
|
||||||
|
base := map[string]interface{}{}
|
||||||
|
custom := map[string]interface{}{}
|
||||||
|
err := json.Unmarshal(baseJson, &base)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(appJson, &custom)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range custom {
|
||||||
|
base[k] = v
|
||||||
|
}
|
||||||
|
return json.Marshal(base)
|
||||||
|
}
|
84
internal/application/setting/setting.go
Normal file
84
internal/application/setting/setting.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package setting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SettingContract interface {
|
||||||
|
GetLanguages() []Lang
|
||||||
|
GetCurrentLangOrDefaultLang() (currentLang Lang, isDefault bool)
|
||||||
|
SetLang(language Lang) error
|
||||||
|
|
||||||
|
GetDirectoryForSaving() string
|
||||||
|
SetDirectoryForSaving(path string)
|
||||||
|
|
||||||
|
GetFFmpegPath() string
|
||||||
|
SetFFmpegPath(path string)
|
||||||
|
|
||||||
|
GetFFprobePath() string
|
||||||
|
SetFFprobePath(path string)
|
||||||
|
|
||||||
|
GetFFplayPath() string
|
||||||
|
SetFFplayPath(path string)
|
||||||
|
|
||||||
|
ThemeInit()
|
||||||
|
GetThemes() map[string]ThemeInfoContract
|
||||||
|
GetTheme() ThemeInfoContract
|
||||||
|
SetTheme(themeInfo ThemeInfoContract)
|
||||||
|
}
|
||||||
|
|
||||||
|
type setting struct {
|
||||||
|
fyneApp fyne.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSetting(fyneApp fyne.App) SettingContract {
|
||||||
|
return &setting{
|
||||||
|
fyneApp: fyneApp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetLanguages() []Lang {
|
||||||
|
items := []Lang{}
|
||||||
|
for _, item := range supportedLanguages {
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetCurrentLangOrDefaultLang() (currentLang Lang, isDefault bool) {
|
||||||
|
languageCode := s.fyneApp.Preferences().String("language")
|
||||||
|
|
||||||
|
if languageCode == "" {
|
||||||
|
languageTag, err := language.Parse(lang.SystemLocale().LanguageString())
|
||||||
|
if err != nil {
|
||||||
|
return currentLang, true
|
||||||
|
}
|
||||||
|
base, _ := languageTag.Base()
|
||||||
|
languageCode = base.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentLang, ok := supportedLanguages[languageCode]; ok {
|
||||||
|
return currentLang, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultLang(), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetLang(language Lang) error {
|
||||||
|
err := ChangeLang(language)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.fyneApp.Preferences().SetString("language", language.Code)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetDirectoryForSaving() string {
|
||||||
|
return s.fyneApp.Preferences().String("directoryForSaving")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetDirectoryForSaving(path string) {
|
||||||
|
s.fyneApp.Preferences().SetString("directoryForSaving", path)
|
||||||
|
}
|
112
internal/application/setting/theme.go
Normal file
112
internal/application/setting/theme.go
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package setting
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *setting) GetTheme() ThemeInfoContract {
|
||||||
|
name := s.fyneApp.Preferences().String("theme")
|
||||||
|
if name != "" {
|
||||||
|
if _, ok := s.GetThemes()[name]; ok {
|
||||||
|
return s.GetThemes()[name]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.GetThemes()["default"]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) SetTheme(themeInfo ThemeInfoContract) {
|
||||||
|
s.fyneApp.Preferences().SetString("theme", themeInfo.GetName())
|
||||||
|
|
||||||
|
if themeInfo.GetName() == "default" {
|
||||||
|
s.fyneApp.Settings().SetTheme(theme.DefaultTheme())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.fyneApp.Settings().SetTheme(&forcedVariant{theme: theme.DefaultTheme(), variant: themeInfo.GetVariant()})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) ThemeInit() {
|
||||||
|
themeInfo := s.GetTheme()
|
||||||
|
if themeInfo.GetName() == "default" {
|
||||||
|
// In the new version of Fyne the theme color changes incorrectly if it is set to default.
|
||||||
|
// s.fyneApp.Settings().SetTheme(theme.DefaultTheme())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.fyneApp.Settings().SetTheme(&forcedVariant{theme: theme.DefaultTheme(), variant: themeInfo.GetVariant()})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *setting) GetThemes() map[string]ThemeInfoContract {
|
||||||
|
themesNameDefault := &themeInfo{
|
||||||
|
name: "default",
|
||||||
|
title: lang.L("themesNameDefault"),
|
||||||
|
}
|
||||||
|
|
||||||
|
themesNameLight := &themeInfo{
|
||||||
|
name: "light",
|
||||||
|
title: lang.L("themesNameLight"),
|
||||||
|
variant: theme.VariantLight,
|
||||||
|
}
|
||||||
|
|
||||||
|
themesNameDark := &themeInfo{
|
||||||
|
name: "dark",
|
||||||
|
title: lang.L("themesNameDark"),
|
||||||
|
variant: theme.VariantDark,
|
||||||
|
}
|
||||||
|
|
||||||
|
list := map[string]ThemeInfoContract{
|
||||||
|
"default": themesNameDefault,
|
||||||
|
"light": themesNameLight,
|
||||||
|
"dark": themesNameDark,
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
type ThemeInfoContract interface {
|
||||||
|
GetName() string
|
||||||
|
GetTitle() string
|
||||||
|
GetVariant() fyne.ThemeVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
type themeInfo struct {
|
||||||
|
name string
|
||||||
|
title string
|
||||||
|
variant fyne.ThemeVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (inf *themeInfo) GetName() string {
|
||||||
|
return inf.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (inf *themeInfo) GetTitle() string {
|
||||||
|
return inf.title
|
||||||
|
}
|
||||||
|
|
||||||
|
func (inf *themeInfo) GetVariant() fyne.ThemeVariant {
|
||||||
|
return inf.variant
|
||||||
|
}
|
||||||
|
|
||||||
|
type forcedVariant struct {
|
||||||
|
theme fyne.Theme
|
||||||
|
variant fyne.ThemeVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forcedVariant) Color(name fyne.ThemeColorName, _ fyne.ThemeVariant) color.Color {
|
||||||
|
return f.theme.Color(name, f.variant)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forcedVariant) Font(style fyne.TextStyle) fyne.Resource {
|
||||||
|
return theme.DefaultTheme().Font(style)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forcedVariant) Icon(name fyne.ThemeIconName) fyne.Resource {
|
||||||
|
return theme.DefaultTheme().Icon(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forcedVariant) Size(name fyne.ThemeSizeName) float32 {
|
||||||
|
return theme.DefaultTheme().Size(name)
|
||||||
|
}
|
111
internal/controller/convertor.go
Normal file
111
internal/controller/convertor.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
"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"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *controller) convertor() {
|
||||||
|
formats, err := c.app.GetConvertorService().GetSupportFormats()
|
||||||
|
if err != nil {
|
||||||
|
c.startWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
content := view.Convertor(
|
||||||
|
c.window,
|
||||||
|
c.addFileForConversion,
|
||||||
|
c.app.GetSetting().GetDirectoryForSaving(),
|
||||||
|
c.setDirectoryForSaving,
|
||||||
|
formats,
|
||||||
|
c.addToConversion,
|
||||||
|
)
|
||||||
|
c.window.SetContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) addFileForConversion(file ffmpeg.File) {
|
||||||
|
c.app.GetItemsToConvert().Add(&file)
|
||||||
|
c.window.GetLayout().GetRContainer().SelectAddedFilesTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) setDirectoryForSaving(path string) {
|
||||||
|
c.app.GetSetting().SetDirectoryForSaving(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) addToConversion(convertSetting view.ConvertSetting) error {
|
||||||
|
if len(c.app.GetItemsToConvert().GetItems()) == 0 {
|
||||||
|
return errors.New(lang.L("errorNoFilesAddedForConversion"))
|
||||||
|
}
|
||||||
|
c.window.GetLayout().GetRContainer().SelectFileQueueTab()
|
||||||
|
for _, item := range c.app.GetItemsToConvert().GetItems() {
|
||||||
|
file := item.GetFile()
|
||||||
|
if file == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
c.app.GetQueueService().Add(&ffmpeg.ConvertSetting{
|
||||||
|
FileInput: *file,
|
||||||
|
FileOut: ffmpeg.File{
|
||||||
|
Path: convertSetting.DirectoryForSave + utils.PathSeparator() + file.Name + "." + convertSetting.Format,
|
||||||
|
Name: file.Name,
|
||||||
|
Ext: "." + convertSetting.Format,
|
||||||
|
},
|
||||||
|
OverwriteOutputFiles: convertSetting.OverwriteOutputFiles,
|
||||||
|
Encoder: convertSetting.Encoder,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
c.app.GetItemsToConvert().AfterAddingQueue()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
16
internal/controller/error.go
Normal file
16
internal/controller/error.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *controller) startWithError(err error) {
|
||||||
|
languages := c.app.GetSetting().GetLanguages()
|
||||||
|
|
||||||
|
content := view.StartWithError(err, languages, func(lang setting.Lang) {
|
||||||
|
_ = setting.ChangeLang(lang)
|
||||||
|
c.startWithError(err)
|
||||||
|
})
|
||||||
|
c.window.SetContent(content)
|
||||||
|
}
|
96
internal/controller/main.go
Normal file
96
internal/controller/main.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/menu"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/window"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ControllerContract interface {
|
||||||
|
Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
type controller struct {
|
||||||
|
app application.AppContract
|
||||||
|
window window.WindowContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewController(app application.AppContract) ControllerContract {
|
||||||
|
fyneWindow := app.FyneApp().NewWindow("GUI for FFmpeg")
|
||||||
|
fyneWindow.SetMaster()
|
||||||
|
queueLayout := window.NewQueueLayout(app.GetFFmpegService())
|
||||||
|
app.GetQueueService().AddListener(queueLayout)
|
||||||
|
|
||||||
|
return &controller{
|
||||||
|
app: app,
|
||||||
|
window: window.NewMainWindow(
|
||||||
|
fyneWindow,
|
||||||
|
app.GetProgressBarService(),
|
||||||
|
app.GetItemsToConvert(),
|
||||||
|
queueLayout,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) Start() {
|
||||||
|
isDefault, err := c.initLanguage()
|
||||||
|
if err != nil {
|
||||||
|
c.startWithError(err)
|
||||||
|
c.window.Show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.app.GetSetting().ThemeInit()
|
||||||
|
|
||||||
|
if isDefault {
|
||||||
|
languages := c.app.GetSetting().GetLanguages()
|
||||||
|
content := view.StartWithoutSupportLang(languages, func(lang setting.Lang) {
|
||||||
|
err = c.app.GetSetting().SetLang(lang)
|
||||||
|
if err != nil {
|
||||||
|
c.startWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.initLayout()
|
||||||
|
c.verificareaFFmpeg()
|
||||||
|
})
|
||||||
|
c.window.SetContent(content)
|
||||||
|
c.window.Show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.initLayout()
|
||||||
|
c.verificareaFFmpeg()
|
||||||
|
c.window.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) verificareaFFmpeg() {
|
||||||
|
if !c.app.GetFFmpegService().UtilityCheck() {
|
||||||
|
c.settingConvertor(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.convertor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) initLanguage() (isDefault bool, err error) {
|
||||||
|
lang, isDefault := c.app.GetSetting().GetCurrentLangOrDefaultLang()
|
||||||
|
err = setting.ChangeLang(lang)
|
||||||
|
return isDefault, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) initLayout() {
|
||||||
|
c.window.SetMainMenu(fyne.NewMainMenu(
|
||||||
|
menu.MainMenuSettings(
|
||||||
|
c.actionMainSettings,
|
||||||
|
c.actionSettingConvertor,
|
||||||
|
),
|
||||||
|
menu.MainMenuHelp(
|
||||||
|
c.actionAbout,
|
||||||
|
c.actionHelpFFplay,
|
||||||
|
),
|
||||||
|
))
|
||||||
|
c.window.InitLayout()
|
||||||
|
}
|
67
internal/controller/menu.go
Normal file
67
internal/controller/menu.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
package controller
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *controller) actionSettingConvertor() {
|
||||||
|
c.settingConvertor(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) actionMainSettings() {
|
||||||
|
currentLang, _ := c.app.GetSetting().GetCurrentLangOrDefaultLang()
|
||||||
|
content := view.MainSettings(
|
||||||
|
currentLang,
|
||||||
|
c.app.GetSetting().GetLanguages(),
|
||||||
|
|
||||||
|
c.app.GetSetting().GetTheme(),
|
||||||
|
c.app.GetSetting().GetThemes(),
|
||||||
|
|
||||||
|
c.actionMainSettingsSave,
|
||||||
|
c.convertor,
|
||||||
|
)
|
||||||
|
c.window.SetContent(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) actionMainSettingsSave(setting *view.MainSettingForm) error {
|
||||||
|
err := c.app.GetSetting().SetLang(setting.Language)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.app.GetSetting().SetTheme(setting.ThemeInfo)
|
||||||
|
c.initLayout()
|
||||||
|
|
||||||
|
c.convertor()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) actionAbout() {
|
||||||
|
ffmpegVersion := c.app.GetFFmpegService().GetFFmpegVersion()
|
||||||
|
ffprobeVersion := c.app.GetFFmpegService().GetFFprobeVersion()
|
||||||
|
ffplayVersion := c.app.GetFFmpegService().GetFFplayVersion()
|
||||||
|
appVersion := c.app.FyneApp().Metadata().Version
|
||||||
|
|
||||||
|
window := c.app.FyneApp().NewWindow(lang.L("about"))
|
||||||
|
window.Resize(fyne.Size{Width: 793, Height: 550})
|
||||||
|
window.SetFixedSize(true)
|
||||||
|
|
||||||
|
content := view.About(appVersion, ffmpegVersion, ffprobeVersion, ffplayVersion)
|
||||||
|
|
||||||
|
window.SetContent(content)
|
||||||
|
window.CenterOnScreen()
|
||||||
|
window.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *controller) actionHelpFFplay() {
|
||||||
|
window := c.app.FyneApp().NewWindow(lang.L("helpFFplay"))
|
||||||
|
window.Resize(fyne.Size{Width: 800, Height: 550})
|
||||||
|
window.SetFixedSize(true)
|
||||||
|
|
||||||
|
content := view.HelpFFplay()
|
||||||
|
|
||||||
|
window.SetContent(content)
|
||||||
|
window.CenterOnScreen()
|
||||||
|
window.Show()
|
||||||
|
}
|
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
|
||||||
|
}
|
21
internal/ffmpeg/encoder/apng/encoder.go
Normal file
21
internal/ffmpeg/encoder/apng/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package apng
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "apng"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("apng", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "apng"
|
||||||
|
formats := []string{"apng"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/bmp/encoder.go
Normal file
21
internal/ffmpeg/encoder/bmp/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package bmp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "bmp"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("bmp", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "bmp"
|
||||||
|
formats := []string{"bmp"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
169
internal/ffmpeg/encoder/encoder.go
Normal file
169
internal/ffmpeg/encoder/encoder.go
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package encoder
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
type EncoderContract interface {
|
||||||
|
GetName() string
|
||||||
|
GetParams() []string
|
||||||
|
GetParameter(name string) (ParameterContract, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParameterContract interface {
|
||||||
|
GetName() string
|
||||||
|
Set(string) error
|
||||||
|
Get() string
|
||||||
|
IsEnabled() bool
|
||||||
|
SetEnable()
|
||||||
|
SetDisable()
|
||||||
|
}
|
||||||
|
|
||||||
|
type EncoderDataContract interface {
|
||||||
|
GetTitle() string
|
||||||
|
GetFormats() []string
|
||||||
|
GetFileType() FileTypeContract
|
||||||
|
NewEncoder() EncoderContract
|
||||||
|
}
|
||||||
|
|
||||||
|
type data struct {
|
||||||
|
title string
|
||||||
|
formats []string
|
||||||
|
fileType FileTypeContract
|
||||||
|
encoder func() EncoderContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData(title string, formats []string, fileType FileTypeContract, encoder func() EncoderContract) EncoderDataContract {
|
||||||
|
return &data{
|
||||||
|
title: title,
|
||||||
|
formats: formats,
|
||||||
|
fileType: fileType,
|
||||||
|
encoder: encoder,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *data) GetTitle() string {
|
||||||
|
return data.title
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *data) GetFormats() []string {
|
||||||
|
return data.formats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *data) NewEncoder() EncoderContract {
|
||||||
|
return data.encoder()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (data *data) GetFileType() FileTypeContract {
|
||||||
|
return data.fileType
|
||||||
|
}
|
||||||
|
|
||||||
|
type FileTypeContract interface {
|
||||||
|
Name() string
|
||||||
|
Ordinal() int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
Video = iota
|
||||||
|
Audio
|
||||||
|
Image
|
||||||
|
)
|
||||||
|
|
||||||
|
type FileType uint
|
||||||
|
|
||||||
|
var fileTypeStrings = []string{
|
||||||
|
"video",
|
||||||
|
"audio",
|
||||||
|
"image",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fileType FileType) Name() string {
|
||||||
|
return fileTypeStrings[fileType]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fileType FileType) Ordinal() int {
|
||||||
|
return int(fileType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetListFileType() []FileTypeContract {
|
||||||
|
return []FileTypeContract{
|
||||||
|
FileType(Video),
|
||||||
|
FileType(Audio),
|
||||||
|
FileType(Image),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type encoder struct {
|
||||||
|
name string
|
||||||
|
parameters map[string]ParameterContract
|
||||||
|
getParams func(parameters map[string]ParameterContract) []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder(name string, parameters map[string]ParameterContract, getParams func(parameters map[string]ParameterContract) []string) EncoderContract {
|
||||||
|
return &encoder{
|
||||||
|
name: name,
|
||||||
|
parameters: parameters,
|
||||||
|
getParams: getParams,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) GetName() string {
|
||||||
|
return e.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) GetParams() []string {
|
||||||
|
return e.getParams(e.parameters)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *encoder) GetParameter(name string) (ParameterContract, error) {
|
||||||
|
if e.parameters[name] == nil {
|
||||||
|
return nil, errors.New("parameter not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.parameters[name], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type parameter struct {
|
||||||
|
name string
|
||||||
|
isEnabled bool
|
||||||
|
parameter string
|
||||||
|
setParameter func(string) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParameter(name string, isEnabled bool, defaultParameter string, setParameter func(string) (string, error)) ParameterContract {
|
||||||
|
return ¶meter{
|
||||||
|
name: name,
|
||||||
|
isEnabled: isEnabled,
|
||||||
|
parameter: defaultParameter,
|
||||||
|
setParameter: setParameter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) GetName() string {
|
||||||
|
return p.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) Set(s string) (err error) {
|
||||||
|
if p.setParameter != nil {
|
||||||
|
s, err = p.setParameter(s)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.parameter = s
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) Get() string {
|
||||||
|
return p.parameter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) IsEnabled() bool {
|
||||||
|
return p.isEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) SetEnable() {
|
||||||
|
p.isEnabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *parameter) SetDisable() {
|
||||||
|
p.isEnabled = false
|
||||||
|
}
|
21
internal/ffmpeg/encoder/flv/encoder.go
Normal file
21
internal/ffmpeg/encoder/flv/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package flv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "flv"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("flv", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "flv"
|
||||||
|
formats := []string{"flv"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/gif/encoder.go
Normal file
21
internal/ffmpeg/encoder/gif/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package gif
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "gif"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("gif", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "gif"
|
||||||
|
formats := []string{"gif"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
58
internal/ffmpeg/encoder/h264_nvenc/encoder.go
Normal file
58
internal/ffmpeg/encoder/h264_nvenc/encoder.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package h264_nvenc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Presets = []string{
|
||||||
|
"default",
|
||||||
|
"slow",
|
||||||
|
"medium",
|
||||||
|
"fast",
|
||||||
|
"hp",
|
||||||
|
"hq",
|
||||||
|
"bd",
|
||||||
|
"ll",
|
||||||
|
"llhq",
|
||||||
|
"llhp",
|
||||||
|
"lossless",
|
||||||
|
"losslesshp",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{
|
||||||
|
"preset": newParameterPreset(),
|
||||||
|
}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
params := []string{"-c:v", "h264_nvenc"}
|
||||||
|
|
||||||
|
if parameters["preset"] != nil && parameters["preset"].IsEnabled() {
|
||||||
|
params = append(params, "-preset", parameters["preset"].Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("h264_nvenc", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "h264_nvenc"
|
||||||
|
formats := []string{"mp4"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParameterPreset() encoder.ParameterContract {
|
||||||
|
setParameter := func(s string) (string, error) {
|
||||||
|
for _, value := range Presets {
|
||||||
|
if value == s {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("preset not found")
|
||||||
|
}
|
||||||
|
return encoder.NewParameter("preset", false, "default", setParameter)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libmp3lame/encoder.go
Normal file
21
internal/ffmpeg/encoder/libmp3lame/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libmp3lame
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "libmp3lame"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libmp3lame", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libmp3lame"
|
||||||
|
formats := []string{"mp3"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libshine/encoder.go
Normal file
21
internal/ffmpeg/encoder/libshine/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libshine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "libshine"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libshine", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libshine"
|
||||||
|
formats := []string{"mp3"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libtwolame/encoder.go
Normal file
21
internal/ffmpeg/encoder/libtwolame/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libtwolame
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "libtwolame"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libtwolame", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libtwolame"
|
||||||
|
formats := []string{"mp2"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libvpx/encoder.go
Normal file
21
internal/ffmpeg/encoder/libvpx/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libvpx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "libvpx"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libvpx", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libvpx"
|
||||||
|
formats := []string{"webm", "mkv"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libvpx_vp9/encoder.go
Normal file
21
internal/ffmpeg/encoder/libvpx_vp9/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libvpx_vp9
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "libvpx-vp9"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libvpx_vp9", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libvpx-vp9"
|
||||||
|
formats := []string{"webm", "mkv"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libwebp/encoder.go
Normal file
21
internal/ffmpeg/encoder/libwebp/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libwebp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "libwebp"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libwebp", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libwebp"
|
||||||
|
formats := []string{"webp"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libwebp_anim/encoder.go
Normal file
21
internal/ffmpeg/encoder/libwebp_anim/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libwebp_anim
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "libwebp_anim"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libwebp_anim", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libwebp_anim"
|
||||||
|
formats := []string{"webp"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
56
internal/ffmpeg/encoder/libx264/encoder.go
Normal file
56
internal/ffmpeg/encoder/libx264/encoder.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package libx264
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Presets = []string{
|
||||||
|
"ultrafast",
|
||||||
|
"superfast",
|
||||||
|
"veryfast",
|
||||||
|
"faster",
|
||||||
|
"fast",
|
||||||
|
"medium",
|
||||||
|
"slow",
|
||||||
|
"slower",
|
||||||
|
"veryslow",
|
||||||
|
"placebo",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{
|
||||||
|
"preset": newParameterPreset(),
|
||||||
|
}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
params := []string{"-c:v", "libx264"}
|
||||||
|
|
||||||
|
if parameters["preset"] != nil && parameters["preset"].IsEnabled() {
|
||||||
|
params = append(params, "-preset", parameters["preset"].Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libx264", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libx264"
|
||||||
|
formats := []string{"mp4"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParameterPreset() encoder.ParameterContract {
|
||||||
|
setParameter := func(s string) (string, error) {
|
||||||
|
for _, value := range Presets {
|
||||||
|
if value == s {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("preset not found")
|
||||||
|
}
|
||||||
|
return encoder.NewParameter("preset", false, "medium", setParameter)
|
||||||
|
}
|
56
internal/ffmpeg/encoder/libx265/encoder.go
Normal file
56
internal/ffmpeg/encoder/libx265/encoder.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package libx265
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Presets = []string{
|
||||||
|
"ultrafast",
|
||||||
|
"superfast",
|
||||||
|
"veryfast",
|
||||||
|
"faster",
|
||||||
|
"fast",
|
||||||
|
"medium",
|
||||||
|
"slow",
|
||||||
|
"slower",
|
||||||
|
"veryslow",
|
||||||
|
"placebo",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{
|
||||||
|
"preset": newParameterPreset(),
|
||||||
|
}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
params := []string{"-c:v", "libx265"}
|
||||||
|
|
||||||
|
if parameters["preset"] != nil && parameters["preset"].IsEnabled() {
|
||||||
|
params = append(params, "-preset", parameters["preset"].Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libx265", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libx265"
|
||||||
|
formats := []string{"mp4"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newParameterPreset() encoder.ParameterContract {
|
||||||
|
setParameter := func(s string) (string, error) {
|
||||||
|
for _, value := range Presets {
|
||||||
|
if value == s {
|
||||||
|
return value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("preset not found")
|
||||||
|
}
|
||||||
|
return encoder.NewParameter("preset", false, "medium", setParameter)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/libxvid/encoder.go
Normal file
21
internal/ffmpeg/encoder/libxvid/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package libxvid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "libxvid"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("libxvid", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "libxvid"
|
||||||
|
formats := []string{"avi"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mjpeg/encoder.go
Normal file
21
internal/ffmpeg/encoder/mjpeg/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mjpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "mjpeg"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mjpeg", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mjpeg"
|
||||||
|
formats := []string{"jpg"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mp2/encoder.go
Normal file
21
internal/ffmpeg/encoder/mp2/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mp2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "mp2"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mp2", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mp2"
|
||||||
|
formats := []string{"mp2"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mp2fixed/encoder.go
Normal file
21
internal/ffmpeg/encoder/mp2fixed/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mp2fixed
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "mp2fixed"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mp2fixed", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mp2fixed"
|
||||||
|
formats := []string{"mp2"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mpeg1video/encoder.go
Normal file
21
internal/ffmpeg/encoder/mpeg1video/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mpeg1video
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "mpeg1video"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mpeg1video", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mpeg1video"
|
||||||
|
formats := []string{"mpg", "mpeg"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mpeg2video/encoder.go
Normal file
21
internal/ffmpeg/encoder/mpeg2video/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mpeg2video
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "mpeg2video"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mpeg2video", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mpeg2video"
|
||||||
|
formats := []string{"mpg", "mpeg"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/mpeg4/encoder.go
Normal file
21
internal/ffmpeg/encoder/mpeg4/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package mpeg4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "mpeg4"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("mpeg4", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "mpeg4"
|
||||||
|
formats := []string{"avi"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/msmpeg4/encoder.go
Normal file
21
internal/ffmpeg/encoder/msmpeg4/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package msmpeg4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "msmpeg4"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("msmpeg4", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "msmpeg4"
|
||||||
|
formats := []string{"avi"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/msmpeg4v2/encoder.go
Normal file
21
internal/ffmpeg/encoder/msmpeg4v2/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package msmpeg4v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "msmpeg4v2"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("msmpeg4v2", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "msmpeg4v2"
|
||||||
|
formats := []string{"avi"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/msvideo1/encoder.go
Normal file
21
internal/ffmpeg/encoder/msvideo1/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package msvideo1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "msvideo1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("msvideo1", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "msvideo1"
|
||||||
|
formats := []string{"avi"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/png/encoder.go
Normal file
21
internal/ffmpeg/encoder/png/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package png
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "png"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("png", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "png"
|
||||||
|
formats := []string{"png"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/qtrle/encoder.go
Normal file
21
internal/ffmpeg/encoder/qtrle/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package qtrle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "qtrle"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("qtrle", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "qtrle"
|
||||||
|
formats := []string{"mov"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/sgi/encoder.go
Normal file
21
internal/ffmpeg/encoder/sgi/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package sgi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "sgi"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("sgi", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "sgi"
|
||||||
|
formats := []string{"sgi"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/tiff/encoder.go
Normal file
21
internal/ffmpeg/encoder/tiff/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package tiff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "tiff"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("tiff", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "tiff"
|
||||||
|
formats := []string{"tiff"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/wmav1/encoder.go
Normal file
21
internal/ffmpeg/encoder/wmav1/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package wmav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "wmav1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("wmav1", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "wmav1"
|
||||||
|
formats := []string{"wma"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/wmav2/encoder.go
Normal file
21
internal/ffmpeg/encoder/wmav2/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package wmav2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:a", "wmav2"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("wmav2", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "wmav2"
|
||||||
|
formats := []string{"wma"}
|
||||||
|
fileType := encoder.FileType(encoder.Audio)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/wmv1/encoder.go
Normal file
21
internal/ffmpeg/encoder/wmv1/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package wmv1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "wmv1"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("wmv1", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "wmv1"
|
||||||
|
formats := []string{"wmv"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/wmv2/encoder.go
Normal file
21
internal/ffmpeg/encoder/wmv2/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package wmv2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "wmv2"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("wmv2", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "wmv2"
|
||||||
|
formats := []string{"wmv"}
|
||||||
|
fileType := encoder.FileType(encoder.Video)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
21
internal/ffmpeg/encoder/xbm/encoder.go
Normal file
21
internal/ffmpeg/encoder/xbm/encoder.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package xbm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewEncoder() encoder.EncoderContract {
|
||||||
|
parameters := map[string]encoder.ParameterContract{}
|
||||||
|
getParams := func(parameters map[string]encoder.ParameterContract) []string {
|
||||||
|
return []string{"-c:v", "xbm"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return encoder.NewEncoder("xbm", parameters, getParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewData() encoder.EncoderDataContract {
|
||||||
|
title := "xbm"
|
||||||
|
formats := []string{"xbm"}
|
||||||
|
fileType := encoder.FileType(encoder.Image)
|
||||||
|
return encoder.NewData(title, formats, fileType, NewEncoder)
|
||||||
|
}
|
139
internal/ffmpeg/ffmpeg.go
Normal file
139
internal/ffmpeg/ffmpeg.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"io"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProgressContract interface {
|
||||||
|
GetProtocole() string
|
||||||
|
Run(stdOut io.ReadCloser, stdErr io.ReadCloser) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type FFmpegContract interface {
|
||||||
|
GetPath() string
|
||||||
|
GetVersion() (string, error)
|
||||||
|
GetEncoders(scanner func(scanner *bufio.Reader)) error
|
||||||
|
RunConvert(setting ConvertSetting, progress ProgressContract, beforeWait func(cmd *exec.Cmd), afterWait func(cmd *exec.Cmd)) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ffmpeg struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFFmpeg(path string) (FFmpegContract, error) {
|
||||||
|
if path == "" {
|
||||||
|
return nil, errors.New(lang.L("errorFFmpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
isCheck, err := checkFFmpegPath(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 (f *ffmpeg) GetVersion() (string, error) {
|
||||||
|
cmd := exec.Command(f.path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
text := regexp.MustCompile("\r?\n").Split(strings.TrimSpace(string(out)), -1)
|
||||||
|
return text[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffmpeg) RunConvert(setting ConvertSetting, progress ProgressContract, beforeWait func(cmd *exec.Cmd), afterWait func(cmd *exec.Cmd)) error {
|
||||||
|
overwriteOutputFiles := "-n"
|
||||||
|
if setting.OverwriteOutputFiles == true {
|
||||||
|
overwriteOutputFiles = "-y"
|
||||||
|
}
|
||||||
|
args := []string{overwriteOutputFiles, "-i", setting.FileInput.Path}
|
||||||
|
args = append(args, setting.Encoder.GetParams()...)
|
||||||
|
args = append(args, "-progress", progress.GetProtocole(), setting.FileOut.Path)
|
||||||
|
cmd := exec.Command(f.path, args...)
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
|
||||||
|
stdOut, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stdErr, err := cmd.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if beforeWait != nil {
|
||||||
|
beforeWait(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
errProgress := progress.Run(stdOut, stdErr)
|
||||||
|
|
||||||
|
err = cmd.Wait()
|
||||||
|
if afterWait != nil {
|
||||||
|
afterWait(cmd)
|
||||||
|
}
|
||||||
|
if errProgress != nil {
|
||||||
|
return errProgress
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffmpeg) GetEncoders(scanner func(scanner *bufio.Reader)) error {
|
||||||
|
cmd := exec.Command(f.path, "-encoders")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
|
||||||
|
stdOut, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
scannerErr := bufio.NewReader(stdOut)
|
||||||
|
scanner(scannerErr)
|
||||||
|
|
||||||
|
return cmd.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
73
internal/ffmpeg/ffplay.go
Normal file
73
internal/ffmpeg/ffplay.go
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FFplayContract interface {
|
||||||
|
GetPath() string
|
||||||
|
GetVersion() (string, error)
|
||||||
|
Play(file *File) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ffplay struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFFplay(path string) (FFplayContract, error) {
|
||||||
|
if path == "" {
|
||||||
|
return nil, errors.New(lang.L("errorFFplay"))
|
||||||
|
}
|
||||||
|
|
||||||
|
isCheck, err := checkFFplayPath(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 (f *ffplay) GetVersion() (string, error) {
|
||||||
|
cmd := exec.Command(f.path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
text := regexp.MustCompile("\r?\n").Split(strings.TrimSpace(string(out)), -1)
|
||||||
|
return text[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffplay) Play(file *File) error {
|
||||||
|
args := []string{file.Path}
|
||||||
|
cmd := exec.Command(f.GetPath(), args...)
|
||||||
|
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
124
internal/ffmpeg/ffprobe.go
Normal file
124
internal/ffmpeg/ffprobe.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package ffmpeg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FFprobeContract interface {
|
||||||
|
GetPath() string
|
||||||
|
GetVersion() (string, error)
|
||||||
|
GetTotalDuration(file *File) (float64, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ffprobe struct {
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFFprobe(path string) (FFprobeContract, error) {
|
||||||
|
if path == "" {
|
||||||
|
return nil, errors.New(lang.L("errorFFprobe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
isCheck, err := checkFFprobePath(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 (f *ffprobe) GetVersion() (string, error) {
|
||||||
|
cmd := exec.Command(f.path, "-version")
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
text := regexp.MustCompile("\r?\n").Split(strings.TrimSpace(string(out)), -1)
|
||||||
|
return text[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffprobe) 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(f.path, args...)
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
errString := strings.TrimSpace(string(out))
|
||||||
|
if len(errString) > 1 {
|
||||||
|
return 0, errors.New(errString)
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
frames := strings.TrimSpace(string(out))
|
||||||
|
if len(frames) == 0 {
|
||||||
|
return f.getAlternativeTotalDuration(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
duration, err = strconv.ParseFloat(frames, 64)
|
||||||
|
if err != nil {
|
||||||
|
// fix .mts duration
|
||||||
|
return strconv.ParseFloat(getFirstDigits(frames), 64)
|
||||||
|
}
|
||||||
|
return duration, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ffprobe) getAlternativeTotalDuration(file *File) (duration float64, err error) {
|
||||||
|
args := []string{"-v", "error", "-select_streams", "a:0", "-count_packets", "-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", file.Path}
|
||||||
|
cmd := exec.Command(f.path, args...)
|
||||||
|
utils.PrepareBackgroundCommand(cmd)
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
errString := strings.TrimSpace(string(out))
|
||||||
|
if len(errString) > 1 {
|
||||||
|
return 0, errors.New(errString)
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
frames := strings.TrimSpace(string(out))
|
||||||
|
if len(frames) == 0 {
|
||||||
|
return 0, errors.New("error getting number of frames")
|
||||||
|
}
|
||||||
|
return strconv.ParseFloat(frames, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFirstDigits(s string) string {
|
||||||
|
result := ""
|
||||||
|
for _, r := range s {
|
||||||
|
if unicode.IsDigit(r) {
|
||||||
|
result += string(r)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
221
internal/ffmpeg/utilities.go
Normal file
221
internal/ffmpeg/utilities.go
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
package ffmpeg
|
||||||
|
|
||||||
|
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/ffmpeg/encoder"
|
||||||
|
)
|
||||||
|
|
||||||
|
type File struct {
|
||||||
|
Path string
|
||||||
|
Name string
|
||||||
|
Ext string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConvertSetting struct {
|
||||||
|
FileInput File
|
||||||
|
FileOut File
|
||||||
|
OverwriteOutputFiles bool
|
||||||
|
Encoder encoder.EncoderContract
|
||||||
|
}
|
||||||
|
|
||||||
|
type UtilitiesContract interface {
|
||||||
|
UtilityCheck() bool
|
||||||
|
|
||||||
|
GetFFmpeg() (FFmpegContract, error)
|
||||||
|
GetFFmpegVersion() string
|
||||||
|
GetFFmpegPath() string
|
||||||
|
ChangeFFmpeg(path string) error
|
||||||
|
|
||||||
|
GetFFprobe() (FFprobeContract, error)
|
||||||
|
GetFFprobeVersion() string
|
||||||
|
GetFFprobePath() string
|
||||||
|
ChangeFFprobe(path string) error
|
||||||
|
|
||||||
|
GetFFplay() (FFplayContract, error)
|
||||||
|
GetFFplayVersion() string
|
||||||
|
GetFFplayPath() string
|
||||||
|
ChangeFFplay(path string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type utilities struct {
|
||||||
|
setting setting.SettingContract
|
||||||
|
ffmpeg FFmpegContract
|
||||||
|
ffprobe FFprobeContract
|
||||||
|
ffplay FFplayContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUtilities(setting setting.SettingContract) UtilitiesContract {
|
||||||
|
return &utilities{
|
||||||
|
setting: setting,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
createFFmpeg, err := newFFmpeg(u.setting.GetFFmpegPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.ffmpeg = createFFmpeg
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.ffmpeg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFmpegVersion() string {
|
||||||
|
ffmpegService, err := u.GetFFmpeg()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFmpegVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := ffmpegService.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFmpegVersion")
|
||||||
|
}
|
||||||
|
return version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFmpegPath() string {
|
||||||
|
ffmpegService, err := u.GetFFmpeg()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return ffmpegService.GetPath()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) ChangeFFmpeg(path string) error {
|
||||||
|
if path == "" {
|
||||||
|
return errors.New(lang.L("errorFFmpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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) GetFFprobeVersion() string {
|
||||||
|
ffprobeService, err := u.GetFFprobe()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFprobeVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
ffprobeVersion, err := ffprobeService.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFprobeVersion")
|
||||||
|
}
|
||||||
|
return ffprobeVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
createFFplay, err := newFFplay(u.setting.GetFFplayPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u.ffplay = createFFplay
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.ffplay, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *utilities) GetFFplayVersion() string {
|
||||||
|
ffplayService, err := u.GetFFplay()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFplayVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
ffplayVersion, err := ffplayService.GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
return lang.L("errorFFplayVersion")
|
||||||
|
}
|
||||||
|
return ffplayVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
29
internal/gui/menu/main.go
Normal file
29
internal/gui/menu/main.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package menu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MainMenuSettings(
|
||||||
|
actionMainSettings func(),
|
||||||
|
actionFFPathSelection func(),
|
||||||
|
) *fyne.Menu {
|
||||||
|
quit := fyne.NewMenuItem(lang.L("exit"), nil)
|
||||||
|
quit.IsQuit = true
|
||||||
|
|
||||||
|
settingsSelection := fyne.NewMenuItem(lang.L("settings"), actionMainSettings)
|
||||||
|
ffPathSelection := fyne.NewMenuItem(lang.L("changeFFPath"), actionFFPathSelection)
|
||||||
|
|
||||||
|
return fyne.NewMenu(lang.L("settings"), settingsSelection, ffPathSelection, quit)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MainMenuHelp(
|
||||||
|
actionAbout func(),
|
||||||
|
actionHelpFFplay func(),
|
||||||
|
) *fyne.Menu {
|
||||||
|
about := fyne.NewMenuItem(lang.L("about"), actionAbout)
|
||||||
|
helpFFplay := fyne.NewMenuItem(lang.L("helpFFplay"), actionHelpFFplay)
|
||||||
|
|
||||||
|
return fyne.NewMenu(lang.L("help"), helpFFplay, about)
|
||||||
|
}
|
607
internal/gui/view/about.go
Normal file
607
internal/gui/view/about.go
Normal file
@@ -0,0 +1,607 @@
|
|||||||
|
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/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/resources"
|
||||||
|
"golang.org/x/image/colornames"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
func About(appVersion string, ffmpegVersion string, ffprobeVersion string, ffplayVersion string) fyne.CanvasObject {
|
||||||
|
programmName := canvas.NewText(" GUI for FFmpeg", colornames.Darkgreen)
|
||||||
|
programmName.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
programmName.TextSize = 20
|
||||||
|
|
||||||
|
programmLink := widget.NewHyperlink(
|
||||||
|
lang.L("programmLink"),
|
||||||
|
&url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "gui-for-ffmpeg.projects.kor-elf.net",
|
||||||
|
Path: "/",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
licenseLink := widget.NewHyperlink(
|
||||||
|
lang.L("licenseLink"),
|
||||||
|
&url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "git.kor-elf.net",
|
||||||
|
Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
licenseLinkOther := widget.NewHyperlink(
|
||||||
|
lang.L("licenseLinkOther"),
|
||||||
|
&url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "git.kor-elf.net",
|
||||||
|
Path: "kor-elf/gui-for-ffmpeg/src/branch/main/LICENSE-3RD-PARTY.txt",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
programmVersion := widget.NewRichTextFromMarkdown(
|
||||||
|
lang.L(
|
||||||
|
"programmVersion",
|
||||||
|
map[string]any{"Version": appVersion},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
aboutText := widget.NewRichText(
|
||||||
|
&widget.TextSegment{
|
||||||
|
Text: lang.L("aboutText"),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
image := canvas.NewImageFromResource(resources.IconAppLogoResource())
|
||||||
|
image.SetMinSize(fyne.Size{Width: 100, Height: 100})
|
||||||
|
image.FillMode = canvas.ImageFillContain
|
||||||
|
|
||||||
|
ffmpegTrademark := widget.NewRichTextFromMarkdown(lang.L("ffmpegTrademark"))
|
||||||
|
ffmpegLGPL := widget.NewRichTextFromMarkdown(lang.L("ffmpegLGPL"))
|
||||||
|
|
||||||
|
return container.NewScroll(container.NewVBox(
|
||||||
|
container.NewBorder(nil, nil, container.NewVBox(image), nil, container.NewVBox(
|
||||||
|
programmName,
|
||||||
|
programmVersion,
|
||||||
|
aboutText,
|
||||||
|
ffmpegTrademark,
|
||||||
|
ffmpegLGPL,
|
||||||
|
widget.NewRichTextFromMarkdown("Copyright (c) 2024 **[Leonid Nikitin (kor-elf)](https://git.kor-elf.net/kor-elf/)**."),
|
||||||
|
container.NewHBox(programmLink, licenseLink),
|
||||||
|
container.NewHBox(licenseLinkOther),
|
||||||
|
)),
|
||||||
|
aboutFFmpeg(ffmpegVersion),
|
||||||
|
aboutFFprobe(ffprobeVersion),
|
||||||
|
aboutFFplay(ffplayVersion),
|
||||||
|
widget.NewCard(lang.L("AlsoUsedProgram"), "", license3RDParty()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
func aboutFFmpeg(version string) *fyne.Container {
|
||||||
|
programmName := canvas.NewText(" FFmpeg", colornames.Darkgreen)
|
||||||
|
programmName.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
programmName.TextSize = 20
|
||||||
|
|
||||||
|
programmLink := widget.NewHyperlink(lang.L("programmLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "",
|
||||||
|
})
|
||||||
|
|
||||||
|
licenseLink := widget.NewHyperlink(lang.L("licenseLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "legal.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
return container.NewVBox(
|
||||||
|
programmName,
|
||||||
|
widget.NewLabel(version),
|
||||||
|
widget.NewRichTextFromMarkdown("**FFmpeg** is a trademark of **[Fabrice Bellard](https://bellard.org/)**, originator of the **[FFmpeg](https://ffmpeg.org/about.html)** project."),
|
||||||
|
widget.NewRichTextFromMarkdown("This software uses libraries from the **FFmpeg** project under the **[LGPLv2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**."),
|
||||||
|
container.NewHBox(programmLink, licenseLink),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func aboutFFprobe(version string) *fyne.Container {
|
||||||
|
programmName := canvas.NewText(" FFprobe", colornames.Darkgreen)
|
||||||
|
programmName.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
programmName.TextSize = 20
|
||||||
|
|
||||||
|
programmLink := widget.NewHyperlink(lang.L("programmLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "ffprobe.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
licenseLink := widget.NewHyperlink(lang.L("licenseLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "legal.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
return container.NewVBox(
|
||||||
|
programmName,
|
||||||
|
widget.NewLabel(version),
|
||||||
|
widget.NewRichTextFromMarkdown("**FFmpeg** is a trademark of **[Fabrice Bellard](https://bellard.org/)**, originator of the **[FFmpeg](https://ffmpeg.org/about.html)** project."),
|
||||||
|
widget.NewRichTextFromMarkdown("This software uses libraries from the **FFmpeg** project under the **[LGPLv2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**."),
|
||||||
|
container.NewHBox(programmLink, licenseLink),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func aboutFFplay(version string) *fyne.Container {
|
||||||
|
programmName := canvas.NewText(" FFplay", colornames.Darkgreen)
|
||||||
|
programmName.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
programmName.TextSize = 20
|
||||||
|
|
||||||
|
programmLink := widget.NewHyperlink(lang.L("programmLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "ffplay.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
licenseLink := widget.NewHyperlink(lang.L("licenseLink"), &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "ffmpeg.org",
|
||||||
|
Path: "legal.html",
|
||||||
|
})
|
||||||
|
|
||||||
|
return container.NewVBox(
|
||||||
|
programmName,
|
||||||
|
widget.NewLabel(version),
|
||||||
|
widget.NewRichTextFromMarkdown("**FFmpeg** is a trademark of **[Fabrice Bellard](https://bellard.org/)**, originator of the **[FFmpeg](https://ffmpeg.org/about.html)** project."),
|
||||||
|
widget.NewRichTextFromMarkdown("This software uses libraries from the **FFmpeg** project under the **[LGPLv2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**."),
|
||||||
|
container.NewHBox(programmLink, licenseLink),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func license3RDParty() *fyne.Container {
|
||||||
|
return container.NewVBox(
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("fyne.io/fyne/v2", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/fyne",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/fyne/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewRichTextFromMarkdown("Copyright (C) 2018 Fyne.io developers (see [AUTHORS](https://github.com/fyne-io/fyne/blob/master/AUTHORS))"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("fyne.io/systray", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/systray",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Apache License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/systray/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/BurntSushi/toml", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "BurntSushi/toml",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("The MIT License (MIT)", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "BurntSushi/toml/blob/master/COPYING",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2013 TOML authors"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/davecgh/go-spew", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "davecgh/go-spew",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("ISC License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "davecgh/go-spew/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2012-2016 Dave Collins <dave@davec.name>"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fredbi/uri", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fredbi/uri",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("The MIT License (MIT)", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fredbi/uri/blob/master/LICENSE.md",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2018 Frederic Bidon"),
|
||||||
|
widget.NewLabel("Copyright (c) 2015 Trey Tacon"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fsnotify/fsnotify", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fsnotify/fsnotify",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD-3-Clause license", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fsnotify/fsnotify/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright © 2012 The Go Authors. All rights reserved."),
|
||||||
|
widget.NewLabel("Copyright © fsnotify Authors. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fyne-io/gl-js", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/gl-js",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD-3-Clause license", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/gl-js/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2009 The Go Authors. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fyne-io/glfw-js", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/glfw-js",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("MIT License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/glfw-js/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2014 Dmitri Shuralyov"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fyne-io/image", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/image",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/image/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2022, Fyne.io"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/fyne-io/oksvg", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/oksvg",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "fyne-io/oksvg/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2018, Steven R Wiley. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/go-gl/gl", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-gl/gl",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("The MIT License (MIT)", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-gl/gl/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2014 Eric Woroshow"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/go-gl/glfw/v3.3/glfw", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-gl/glfw/",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD-3-Clause license", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-gl/glfw/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2012 The glfw3-go Authors. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/go-text/render", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-text/render",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Unlicense OR BSD-3-Clause", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-text/render/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2021 The go-text authors"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/go-text/typesetting", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-text/typesetting",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Unlicense OR BSD-3-Clause", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-text/typesetting/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2021 The go-text authors"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/godbus/dbus/v5", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "godbus/dbus",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 2-Clause \"Simplified\" License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "godbus/dbus/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2013, Georg Reinke (<guelfey at gmail dot com>), Google. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/hack-pad/go-indexeddb", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "hack-pad/go-indexeddb",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Apache License 2.0", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "hack-pad/go-indexeddb/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/hack-pad/safejs", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "hack-pad/safejs",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Apache License 2.0", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "hack-pad/safejs/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/jeandeaual/go-locale", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "jeandeaual/go-locale",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("MIT License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "jeandeaual/go-locale/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2020 Alexis Jeandeau"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/jsummers/gobmp", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "jsummers/gobmp",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("The MIT License (MIT)", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "jsummers/gobmp/blob/master/COPYING.txt",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2012-2015 Jason Summers"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/nfnt/resize", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "nfnt/resize",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("ISC License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "nfnt/resize/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2012, Jan Schlicht <jan.schlicht@gmail.com>"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/nicksnyder/go-i18n/v2", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "nicksnyder/go-i18n",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("The MIT License (MIT)", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "nicksnyder/go-i18n/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewRichTextFromMarkdown("Copyright (c) 2014 Nick Snyder [https://github.com/nicksnyder](https://github.com/nicksnyder)"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/pmezard/go-difflib", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "pmezard/go-difflib",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "pmezard/go-difflib/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2013, Patrick Mezard. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/rymdport/portal", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "rymdport/portal",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("Apache License 2.0", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "rymdport/portal/blob/main/LICENSE",
|
||||||
|
})),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/srwiley/oksvg", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "srwiley/oksvg",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "srwiley/oksvg/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2018, Steven R Wiley. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/srwiley/rasterx", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "srwiley/rasterx",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "srwiley/rasterx/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2018, Steven R Wiley. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/stretchr/testify", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "stretchr/testify",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("MIT License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "stretchr/testify/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/ulikunitz/xz", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "ulikunitz/xz",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "ulikunitz/xz/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2014-2022 Ulrich Kunitz. All rights reserved."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/yuin/goldmark", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "yuin/goldmark",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("MIT License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "yuin/goldmark/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2019 Yusuke Inuzuka"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("golang.org/x/image", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "pkg.go.dev",
|
||||||
|
Path: "golang.org/x/image",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "cs.opensource.google",
|
||||||
|
Path: "go/x/image/+/master:LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2009 The Go Authors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("golang.org/x/net", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "pkg.go.dev",
|
||||||
|
Path: "golang.org/x/net",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "cs.opensource.google",
|
||||||
|
Path: "go/x/net/+/master:LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2009 The Go Authors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("golang.org/x/sys", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "pkg.go.dev",
|
||||||
|
Path: "golang.org/x/sys",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "cs.opensource.google",
|
||||||
|
Path: "go/x/sys/+/master:LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2009 The Go Authors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("golang.org/x/text", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "pkg.go.dev",
|
||||||
|
Path: "golang.org/x/text",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "cs.opensource.google",
|
||||||
|
Path: "go/x/text/+/master:LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2009 The Go Authors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("gopkg.in/yaml.v3", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-yaml/yaml/tree/v3.0.1",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("MIT License and Apache License 2.0", &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "go-yaml/yaml/blob/v3.0.1/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright (c) 2006-2010 Kirill Simonov"),
|
||||||
|
widget.NewLabel("Copyright (c) 2006-2011 Kirill Simonov"),
|
||||||
|
widget.NewLabel("Copyright (c) 2011-2019 Canonical Ltd"),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
|
||||||
|
container.NewHBox(widget.NewHyperlink("github.com/golang/go", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "golang/go",
|
||||||
|
})),
|
||||||
|
container.NewHBox(widget.NewHyperlink("BSD 3-Clause \"New\" or \"Revised\" License", &url.URL{
|
||||||
|
Scheme: "https",
|
||||||
|
Host: "github.com",
|
||||||
|
Path: "golang/go/blob/master/LICENSE",
|
||||||
|
})),
|
||||||
|
widget.NewLabel("Copyright 2009 The Go Authors."),
|
||||||
|
canvas.NewLine(colornames.Darkgreen),
|
||||||
|
)
|
||||||
|
}
|
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
|
||||||
|
}
|
414
internal/gui/view/convertor.go
Normal file
414
internal/gui/view/convertor.go
Normal file
@@ -0,0 +1,414 @@
|
|||||||
|
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/application/convertor/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
encoder2 "git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view/convertor/encoders"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/window"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
"image/color"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConvertSetting struct {
|
||||||
|
DirectoryForSave string
|
||||||
|
OverwriteOutputFiles bool
|
||||||
|
Format string
|
||||||
|
Encoder encoder2.EncoderContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func Convertor(
|
||||||
|
window window.WindowContract,
|
||||||
|
addFileForConversion func(file ffmpeg.File),
|
||||||
|
directoryForSavingPath string,
|
||||||
|
directoryForSaving func(path string),
|
||||||
|
formats encoder.ConvertorFormatsContract,
|
||||||
|
addToConversion func(convertSetting ConvertSetting) error,
|
||||||
|
) fyne.CanvasObject {
|
||||||
|
conversionMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
conversionMessage.TextSize = 16
|
||||||
|
conversionMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
form := newFormConvertor(
|
||||||
|
window,
|
||||||
|
addFileForConversion,
|
||||||
|
directoryForSavingPath,
|
||||||
|
directoryForSaving,
|
||||||
|
formats,
|
||||||
|
addToConversion,
|
||||||
|
conversionMessage,
|
||||||
|
)
|
||||||
|
|
||||||
|
converterVideoFilesTitle := lang.L("converterVideoFilesTitle")
|
||||||
|
return widget.NewCard(converterVideoFilesTitle, "", container.NewVScroll(form.getForm()))
|
||||||
|
}
|
||||||
|
|
||||||
|
type formConvertor struct {
|
||||||
|
form *widget.Form
|
||||||
|
items []*widget.FormItem
|
||||||
|
conversionMessage *canvas.Text
|
||||||
|
|
||||||
|
window window.WindowContract
|
||||||
|
addFileForConversion func(file ffmpeg.File)
|
||||||
|
directoryForSaving func(path string)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFormConvertor(
|
||||||
|
window window.WindowContract,
|
||||||
|
addFileForConversion func(file ffmpeg.File),
|
||||||
|
directoryForSavingPath string,
|
||||||
|
directoryForSaving func(path string),
|
||||||
|
formats encoder.ConvertorFormatsContract,
|
||||||
|
addToConversion func(convertSetting ConvertSetting) error,
|
||||||
|
conversionMessage *canvas.Text,
|
||||||
|
) *formConvertor {
|
||||||
|
f := widget.NewForm()
|
||||||
|
f.SubmitText = lang.L("converterVideoFilesSubmitTitle")
|
||||||
|
|
||||||
|
formConvertor := &formConvertor{
|
||||||
|
form: f,
|
||||||
|
window: window,
|
||||||
|
addFileForConversion: addFileForConversion,
|
||||||
|
directoryForSaving: directoryForSaving,
|
||||||
|
conversionMessage: conversionMessage,
|
||||||
|
}
|
||||||
|
|
||||||
|
fileForConversion := formConvertor.newFileForConversion()
|
||||||
|
directoryForSavingButton := formConvertor.newDirectoryForSaving(directoryForSavingPath)
|
||||||
|
isOverwriteOutputFiles := false
|
||||||
|
checkboxOverwriteOutputFiles := widget.NewCheck(lang.L("checkboxOverwriteOutputFilesTitle"), func(b bool) {
|
||||||
|
isOverwriteOutputFiles = b
|
||||||
|
})
|
||||||
|
checkboxOverwriteOutputFiles.SetChecked(isOverwriteOutputFiles)
|
||||||
|
selectEncoder := formConvertor.newSelectEncoder(formats)
|
||||||
|
|
||||||
|
items := []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("fileForConversionTitle"),
|
||||||
|
Widget: fileForConversion.button,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(fileForConversion.message),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Text: lang.L("buttonForSelectedDirTitle"),
|
||||||
|
Widget: directoryForSavingButton.button,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: container.NewHScroll(directoryForSavingButton.message),
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
Widget: checkboxOverwriteOutputFiles,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: selectEncoder.SelectFileType,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("selectFormat"),
|
||||||
|
Widget: selectEncoder.SelectFormat,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("selectEncoder"),
|
||||||
|
Widget: selectEncoder.SelectEncoder,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
formConvertor.form.Items = items
|
||||||
|
formConvertor.items = items
|
||||||
|
formConvertor.changeEncoder(selectEncoder.Encoder)
|
||||||
|
selectEncoder.ChangeEncoder = formConvertor.changeEncoder
|
||||||
|
|
||||||
|
formConvertor.form.OnSubmit = func() {
|
||||||
|
formConvertor.conversionMessage.Text = ""
|
||||||
|
if len(directoryForSavingButton.path) == 0 {
|
||||||
|
formConvertor.conversionMessage.Text = lang.L("errorSelectedFolderSave")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(selectEncoder.SelectFormat.Selected) == 0 {
|
||||||
|
formConvertor.conversionMessage.Text = lang.L("errorSelectedFormat")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if selectEncoder.Encoder == nil {
|
||||||
|
formConvertor.conversionMessage.Text = lang.L("errorSelectedEncoder")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileForConversion.button.Disable()
|
||||||
|
directoryForSavingButton.button.Disable()
|
||||||
|
formConvertor.form.Disable()
|
||||||
|
|
||||||
|
fyne.Do(func() {
|
||||||
|
err := addToConversion(ConvertSetting{
|
||||||
|
DirectoryForSave: directoryForSavingButton.path,
|
||||||
|
OverwriteOutputFiles: isOverwriteOutputFiles,
|
||||||
|
Format: selectEncoder.SelectFormat.Selected,
|
||||||
|
Encoder: selectEncoder.Encoder,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
formConvertor.conversionMessage.Text = err.Error()
|
||||||
|
}
|
||||||
|
fileForConversion.button.Enable()
|
||||||
|
directoryForSavingButton.button.Enable()
|
||||||
|
formConvertor.form.Enable()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return formConvertor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) getForm() fyne.CanvasObject {
|
||||||
|
return container.NewVBox(
|
||||||
|
f.form,
|
||||||
|
container.NewHScroll(f.conversionMessage),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileForConversion struct {
|
||||||
|
button *widget.Button
|
||||||
|
message *canvas.Text
|
||||||
|
file *ffmpeg.File
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) newFileForConversion() *fileForConversion {
|
||||||
|
message := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
fileForConversion := &fileForConversion{
|
||||||
|
message: message,
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonTitle := lang.L("choose") + "\n" +
|
||||||
|
lang.L("or") + "\n" +
|
||||||
|
lang.L("dragAndDropFiles")
|
||||||
|
|
||||||
|
var locationURI fyne.ListableURI
|
||||||
|
|
||||||
|
fileForConversion.button = widget.NewButton(buttonTitle, func() {
|
||||||
|
f.window.NewFileOpen(func(r fyne.URIReadCloser, err error) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
fileForConversion.message.Text = ""
|
||||||
|
fileForConversion.message.Refresh()
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fyne.Do(func() {
|
||||||
|
fileForConversion.message.Text = err.Error()
|
||||||
|
fileForConversion.message.Refresh()
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.addFileForConversion(ffmpeg.File{
|
||||||
|
Path: r.URI().Path(),
|
||||||
|
Name: r.URI().Name(),
|
||||||
|
Ext: r.URI().Extension(),
|
||||||
|
})
|
||||||
|
|
||||||
|
listableURI := storage.NewFileURI(filepath.Dir(r.URI().Path()))
|
||||||
|
locationURI, _ = storage.ListerForURI(listableURI)
|
||||||
|
}, locationURI)
|
||||||
|
})
|
||||||
|
|
||||||
|
f.window.SetOnDropped(func(position fyne.Position, uris []fyne.URI) {
|
||||||
|
if len(uris) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isError := false
|
||||||
|
for _, uri := range uris {
|
||||||
|
info, err := os.Stat(uri.Path())
|
||||||
|
if err != nil {
|
||||||
|
isError = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
isError = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
f.addFileForConversion(ffmpeg.File{
|
||||||
|
Path: uri.Path(),
|
||||||
|
Name: uri.Name(),
|
||||||
|
Ext: uri.Extension(),
|
||||||
|
})
|
||||||
|
|
||||||
|
listableURI := storage.NewFileURI(filepath.Dir(uri.Path()))
|
||||||
|
locationURI, _ = storage.ListerForURI(listableURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isError {
|
||||||
|
fileForConversion.message.Text = lang.L("errorDragAndDropFile")
|
||||||
|
utils.SetStringErrorStyle(fileForConversion.message)
|
||||||
|
} else {
|
||||||
|
fyne.Do(func() {
|
||||||
|
fileForConversion.message.Text = ""
|
||||||
|
fileForConversion.message.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return fileForConversion
|
||||||
|
}
|
||||||
|
|
||||||
|
type directoryForSaving struct {
|
||||||
|
button *widget.Button
|
||||||
|
message *canvas.Text
|
||||||
|
path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) newDirectoryForSaving(directoryForSavingPath string) *directoryForSaving {
|
||||||
|
directoryForSaving := &directoryForSaving{
|
||||||
|
path: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
directoryForSaving.message = canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
directoryForSaving.message.TextSize = 16
|
||||||
|
directoryForSaving.message.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
buttonTitle := lang.L("choose")
|
||||||
|
|
||||||
|
locationURI, err := utils.PathToListableURI(directoryForSavingPath)
|
||||||
|
if err == nil {
|
||||||
|
directoryForSaving.path = locationURI.Path()
|
||||||
|
directoryForSaving.message.Text = locationURI.Path()
|
||||||
|
utils.SetStringSuccessStyle(directoryForSaving.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
directoryForSaving.button = widget.NewButton(buttonTitle, func() {
|
||||||
|
f.window.NewFolderOpen(func(r fyne.ListableURI, err error) {
|
||||||
|
if err != nil {
|
||||||
|
directoryForSaving.message.Text = err.Error()
|
||||||
|
utils.SetStringErrorStyle(directoryForSaving.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
directoryForSaving.path = r.Path()
|
||||||
|
|
||||||
|
directoryForSaving.message.Text = r.Path()
|
||||||
|
utils.SetStringSuccessStyle(directoryForSaving.message)
|
||||||
|
locationURI, err = storage.ListerForURI(r)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
f.directoryForSaving(locationURI.Path())
|
||||||
|
}
|
||||||
|
|
||||||
|
}, locationURI)
|
||||||
|
})
|
||||||
|
|
||||||
|
return directoryForSaving
|
||||||
|
}
|
||||||
|
|
||||||
|
type selectEncoder struct {
|
||||||
|
SelectFileType *widget.RadioGroup
|
||||||
|
SelectFormat *widget.Select
|
||||||
|
SelectEncoder *widget.Select
|
||||||
|
Encoder encoder2.EncoderContract
|
||||||
|
|
||||||
|
ChangeEncoder func(encoder encoder2.EncoderContract)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) newSelectEncoder(formats encoder.ConvertorFormatsContract) *selectEncoder {
|
||||||
|
selectEncoder := &selectEncoder{}
|
||||||
|
|
||||||
|
encoderMap := map[int]encoder2.EncoderDataContract{}
|
||||||
|
selectEncoder.SelectEncoder = widget.NewSelect([]string{}, func(s string) {
|
||||||
|
if encoderMap[selectEncoder.SelectEncoder.SelectedIndex()] == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectEncoderData := encoderMap[selectEncoder.SelectEncoder.SelectedIndex()]
|
||||||
|
selectEncoder.Encoder = selectEncoderData.NewEncoder()
|
||||||
|
if selectEncoder.ChangeEncoder != nil {
|
||||||
|
selectEncoder.ChangeEncoder(selectEncoder.Encoder)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
formatSelected := ""
|
||||||
|
selectEncoder.SelectFormat = widget.NewSelect([]string{}, func(s string) {
|
||||||
|
if formatSelected == s {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
formatSelected = s
|
||||||
|
format, err := formats.GetFormat(s)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var encoderOptions []string
|
||||||
|
encoderMap = map[int]encoder2.EncoderDataContract{}
|
||||||
|
for _, e := range format.GetEncoders() {
|
||||||
|
encoderMap[len(encoderMap)] = e
|
||||||
|
encoderOptions = append(encoderOptions, lang.L("encoder_"+e.GetTitle()))
|
||||||
|
}
|
||||||
|
selectEncoder.SelectEncoder.SetOptions(encoderOptions)
|
||||||
|
selectEncoder.SelectEncoder.SetSelectedIndex(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
var fileTypeOptions []string
|
||||||
|
for _, fileType := range encoder2.GetListFileType() {
|
||||||
|
fileTypeOptions = append(fileTypeOptions, fileType.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
encoderGroupVideo := lang.L("encoderGroupVideo")
|
||||||
|
encoderGroupAudio := lang.L("encoderGroupAudio")
|
||||||
|
encoderGroupImage := lang.L("encoderGroupImage")
|
||||||
|
encoderGroup := map[string]string{
|
||||||
|
encoderGroupVideo: "video",
|
||||||
|
encoderGroupAudio: "audio",
|
||||||
|
encoderGroupImage: "image",
|
||||||
|
}
|
||||||
|
selectEncoder.SelectFileType = widget.NewRadioGroup([]string{encoderGroupVideo, encoderGroupAudio, encoderGroupImage}, func(s string) {
|
||||||
|
groupCode := encoderGroup[s]
|
||||||
|
|
||||||
|
var formatOptions []string
|
||||||
|
for _, f := range formats.GetFormats() {
|
||||||
|
if groupCode != f.GetFileType().Name() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formatOptions = append(formatOptions, f.GetTitle())
|
||||||
|
}
|
||||||
|
selectEncoder.SelectFormat.SetOptions(formatOptions)
|
||||||
|
if groupCode == encoder2.FileType(encoder2.Video).Name() {
|
||||||
|
selectEncoder.SelectFormat.SetSelected("mp4")
|
||||||
|
} else {
|
||||||
|
selectEncoder.SelectFormat.SetSelectedIndex(0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
selectEncoder.SelectFileType.Horizontal = true
|
||||||
|
selectEncoder.SelectFileType.Required = true
|
||||||
|
selectEncoder.SelectFileType.SetSelected(encoderGroupVideo)
|
||||||
|
|
||||||
|
return selectEncoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) changeEncoder(encoder encoder2.EncoderContract) {
|
||||||
|
var items []*widget.FormItem
|
||||||
|
|
||||||
|
if encoders.Views[encoder.GetName()] != nil {
|
||||||
|
items = encoders.Views[encoder.GetName()](encoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.changeItems(items)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *formConvertor) changeItems(items []*widget.FormItem) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
f.form.Items = f.items
|
||||||
|
f.form.Refresh()
|
||||||
|
f.form.Items = append(f.form.Items, items...)
|
||||||
|
f.form.Refresh()
|
||||||
|
})
|
||||||
|
}
|
15
internal/gui/view/convertor/encoders/encoders.go
Normal file
15
internal/gui/view/convertor/encoders/encoders.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package encoders
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view/convertor/encoders/h264_nvenc"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view/convertor/encoders/libx264"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/gui/view/convertor/encoders/libx265"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Views = map[string]func(encoder encoder.EncoderContract) []*widget.FormItem{
|
||||||
|
"libx264": libx264.View,
|
||||||
|
"h264_nvenc": h264_nvenc.View,
|
||||||
|
"libx265": libx265.View,
|
||||||
|
}
|
64
internal/gui/view/convertor/encoders/h264_nvenc/view.go
Normal file
64
internal/gui/view/convertor/encoders/h264_nvenc/view.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package h264_nvenc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/h264_nvenc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func View(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
items := []*widget.FormItem{}
|
||||||
|
|
||||||
|
items = append(items, presetParameter(encoder)...)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
parameter, err := encoder.GetParameter("preset")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
presets := map[string]string{}
|
||||||
|
presetsForSelect := []string{}
|
||||||
|
presetDefault := ""
|
||||||
|
|
||||||
|
for _, name := range h264_nvenc.Presets {
|
||||||
|
title := name
|
||||||
|
presetsForSelect = append(presetsForSelect, name)
|
||||||
|
presets[title] = name
|
||||||
|
if name == parameter.Get() {
|
||||||
|
presetDefault = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementSelect := widget.NewSelect(presetsForSelect, func(s string) {
|
||||||
|
if presets[s] == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.Set(presets[s])
|
||||||
|
})
|
||||||
|
elementSelect.SetSelected(presetDefault)
|
||||||
|
elementSelect.Hide()
|
||||||
|
|
||||||
|
checkboxTitle := lang.L("parameterCheckbox")
|
||||||
|
elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
parameter.SetEnable()
|
||||||
|
elementSelect.Show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.SetDisable()
|
||||||
|
elementSelect.Hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
return []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("formPreset"),
|
||||||
|
Widget: container.NewVBox(elementCheckbox, elementSelect),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
64
internal/gui/view/convertor/encoders/libx264/view.go
Normal file
64
internal/gui/view/convertor/encoders/libx264/view.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package libx264
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx264"
|
||||||
|
)
|
||||||
|
|
||||||
|
func View(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
items := []*widget.FormItem{}
|
||||||
|
|
||||||
|
items = append(items, presetParameter(encoder)...)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
parameter, err := encoder.GetParameter("preset")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
presets := map[string]string{}
|
||||||
|
presetsForSelect := []string{}
|
||||||
|
presetDefault := ""
|
||||||
|
|
||||||
|
for _, name := range libx264.Presets {
|
||||||
|
title := lang.L("preset_" + name)
|
||||||
|
presetsForSelect = append(presetsForSelect, title)
|
||||||
|
presets[title] = name
|
||||||
|
if name == parameter.Get() {
|
||||||
|
presetDefault = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementSelect := widget.NewSelect(presetsForSelect, func(s string) {
|
||||||
|
if presets[s] == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.Set(presets[s])
|
||||||
|
})
|
||||||
|
elementSelect.SetSelected(presetDefault)
|
||||||
|
elementSelect.Hide()
|
||||||
|
|
||||||
|
checkboxTitle := lang.L("parameterCheckbox")
|
||||||
|
elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
parameter.SetEnable()
|
||||||
|
elementSelect.Show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.SetDisable()
|
||||||
|
elementSelect.Hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
return []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("formPreset"),
|
||||||
|
Widget: container.NewVBox(elementCheckbox, elementSelect),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
64
internal/gui/view/convertor/encoders/libx265/view.go
Normal file
64
internal/gui/view/convertor/encoders/libx265/view.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package libx265
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg/encoder/libx265"
|
||||||
|
)
|
||||||
|
|
||||||
|
func View(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
items := []*widget.FormItem{}
|
||||||
|
|
||||||
|
items = append(items, presetParameter(encoder)...)
|
||||||
|
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
|
func presetParameter(encoder encoder.EncoderContract) []*widget.FormItem {
|
||||||
|
parameter, err := encoder.GetParameter("preset")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
presets := map[string]string{}
|
||||||
|
presetsForSelect := []string{}
|
||||||
|
presetDefault := ""
|
||||||
|
|
||||||
|
for _, name := range libx265.Presets {
|
||||||
|
title := lang.L("preset_" + name)
|
||||||
|
presetsForSelect = append(presetsForSelect, title)
|
||||||
|
presets[title] = name
|
||||||
|
if name == parameter.Get() {
|
||||||
|
presetDefault = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementSelect := widget.NewSelect(presetsForSelect, func(s string) {
|
||||||
|
if presets[s] == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.Set(presets[s])
|
||||||
|
})
|
||||||
|
elementSelect.SetSelected(presetDefault)
|
||||||
|
elementSelect.Hide()
|
||||||
|
|
||||||
|
checkboxTitle := lang.L("parameterCheckbox")
|
||||||
|
elementCheckbox := widget.NewCheck(checkboxTitle, func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
parameter.SetEnable()
|
||||||
|
elementSelect.Show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
parameter.SetDisable()
|
||||||
|
elementSelect.Hide()
|
||||||
|
})
|
||||||
|
|
||||||
|
return []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("formPreset"),
|
||||||
|
Widget: container.NewVBox(elementCheckbox, elementSelect),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
39
internal/gui/view/error.go
Normal file
39
internal/gui/view/error.go
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartWithError(err error, languages []setting.Lang, funcSelected func(lang setting.Lang)) fyne.CanvasObject {
|
||||||
|
messageHead := lang.L("error")
|
||||||
|
|
||||||
|
listView := widget.NewList(
|
||||||
|
func() int {
|
||||||
|
return len(languages)
|
||||||
|
},
|
||||||
|
func() fyne.CanvasObject {
|
||||||
|
return widget.NewLabel("template")
|
||||||
|
},
|
||||||
|
func(i widget.ListItemID, o fyne.CanvasObject) {
|
||||||
|
block := o.(*widget.Label)
|
||||||
|
block.SetText(languages[i].Title)
|
||||||
|
})
|
||||||
|
listView.OnSelected = func(id widget.ListItemID) {
|
||||||
|
funcSelected(languages[id])
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.NewBorder(
|
||||||
|
container.NewVBox(
|
||||||
|
widget.NewLabel(messageHead),
|
||||||
|
widget.NewLabel(err.Error()),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
listView,
|
||||||
|
)
|
||||||
|
}
|
105
internal/gui/view/help_ffplay.go
Normal file
105
internal/gui/view/help_ffplay.go
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HelpFFplay() fyne.CanvasObject {
|
||||||
|
data := [][]string{
|
||||||
|
{
|
||||||
|
lang.L("helpFFplayKeys"),
|
||||||
|
lang.L("helpFFplayDescription"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Q, ESC",
|
||||||
|
lang.L("helpFFplayQuit"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"F, " + lang.L("helpFFplayDoubleClickLeftMouseButton"),
|
||||||
|
lang.L("helpFFplayToggleFullScreen"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"P, " + lang.L("helpFFplayKeySpace"),
|
||||||
|
lang.L("helpFFplayPause"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"M",
|
||||||
|
lang.L("helpFFplayToggleMute"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"9, /",
|
||||||
|
lang.L("helpFFplayDecreaseVolume"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"0, *",
|
||||||
|
lang.L("helpFFplayIncreaseVolume"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang.L("helpFFplayKeyLeft"),
|
||||||
|
lang.L("helpFFplaySeekBackward10Seconds"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang.L("helpFFplayKeyRight"),
|
||||||
|
lang.L("helpFFplaySeekForward10Seconds"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang.L("helpFFplayKeyDown"),
|
||||||
|
lang.L("helpFFplaySeekBackward1Minute"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lang.L("helpFFplayKeyUp"),
|
||||||
|
lang.L("helpFFplaySeekBForward1Minute"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Page Down",
|
||||||
|
lang.L("helpFFplaySeekBackward10Minutes"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Page Up",
|
||||||
|
lang.L("helpFFplaySeekBForward10Minutes"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"S, " + lang.L("helpFFplayKeyHoldS"),
|
||||||
|
lang.L("helpFFplayActivateFrameStepMode"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"W",
|
||||||
|
lang.L("helpFFplayCycleVideoFiltersOrShowModes"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
list := widget.NewTable(
|
||||||
|
func() (int, int) {
|
||||||
|
return len(data), len(data[0])
|
||||||
|
},
|
||||||
|
func() fyne.CanvasObject {
|
||||||
|
return widget.NewLabel("")
|
||||||
|
},
|
||||||
|
func(i widget.TableCellID, o fyne.CanvasObject) {
|
||||||
|
label := o.(*widget.Label)
|
||||||
|
|
||||||
|
label.TextStyle.Bold = false
|
||||||
|
label.SizeName = theme.SizeNameText
|
||||||
|
|
||||||
|
if i.Row == 0 {
|
||||||
|
label.TextStyle.Bold = true
|
||||||
|
label.SizeName = theme.SizeNameSubHeadingText
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.Col == 0 {
|
||||||
|
label.TextStyle.Bold = true
|
||||||
|
}
|
||||||
|
|
||||||
|
label.SetText(data[i.Row][i.Col])
|
||||||
|
})
|
||||||
|
list.SetRowHeight(0, 40)
|
||||||
|
list.SetColumnWidth(0, 200)
|
||||||
|
list.SetColumnWidth(1, 585)
|
||||||
|
list.SetRowHeight(2, 55)
|
||||||
|
|
||||||
|
return container.NewScroll(list)
|
||||||
|
}
|
92
internal/gui/view/mainSettings.go
Normal file
92
internal/gui/view/mainSettings.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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/setting"
|
||||||
|
"image/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MainSettingForm struct {
|
||||||
|
Language setting.Lang
|
||||||
|
ThemeInfo setting.ThemeInfoContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func MainSettings(
|
||||||
|
currentLang setting.Lang,
|
||||||
|
langList []setting.Lang,
|
||||||
|
|
||||||
|
themeInfo setting.ThemeInfoContract,
|
||||||
|
themeList map[string]setting.ThemeInfoContract,
|
||||||
|
|
||||||
|
save func(form *MainSettingForm) error,
|
||||||
|
cancel func(),
|
||||||
|
) fyne.CanvasObject {
|
||||||
|
|
||||||
|
errorMessage := canvas.NewText("", color.RGBA{R: 255, G: 0, B: 0, A: 255})
|
||||||
|
errorMessage.TextSize = 16
|
||||||
|
errorMessage.TextStyle = fyne.TextStyle{Bold: true}
|
||||||
|
|
||||||
|
viewSettingForm := &MainSettingForm{
|
||||||
|
Language: currentLang,
|
||||||
|
ThemeInfo: themeInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
var languageItems []string
|
||||||
|
langByTitle := map[string]setting.Lang{}
|
||||||
|
for _, language := range langList {
|
||||||
|
languageItems = append(languageItems, language.Title)
|
||||||
|
langByTitle[language.Title] = language
|
||||||
|
}
|
||||||
|
selectLanguage := widget.NewSelect(languageItems, func(s string) {
|
||||||
|
if lang, ok := langByTitle[s]; ok {
|
||||||
|
viewSettingForm.Language = lang
|
||||||
|
}
|
||||||
|
})
|
||||||
|
selectLanguage.Selected = currentLang.Title
|
||||||
|
|
||||||
|
var themeItems []string
|
||||||
|
themeByTitle := map[string]setting.ThemeInfoContract{}
|
||||||
|
for _, themeInfo := range themeList {
|
||||||
|
themeItems = append(themeItems, themeInfo.GetTitle())
|
||||||
|
themeByTitle[themeInfo.GetTitle()] = themeInfo
|
||||||
|
}
|
||||||
|
selectTheme := widget.NewSelect(themeItems, func(s string) {
|
||||||
|
if themeInfo, ok := themeByTitle[s]; ok {
|
||||||
|
viewSettingForm.ThemeInfo = themeInfo
|
||||||
|
}
|
||||||
|
})
|
||||||
|
selectTheme.Selected = themeInfo.GetTitle()
|
||||||
|
|
||||||
|
form := &widget.Form{
|
||||||
|
Items: []*widget.FormItem{
|
||||||
|
{
|
||||||
|
Text: lang.L("menuSettingsLanguage"),
|
||||||
|
Widget: selectLanguage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Text: lang.L("menuSettingsTheme"),
|
||||||
|
Widget: selectTheme,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Widget: errorMessage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
SubmitText: lang.L("save"),
|
||||||
|
OnSubmit: func() {
|
||||||
|
err := save(viewSettingForm)
|
||||||
|
if err != nil {
|
||||||
|
errorMessage.Text = err.Error()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if cancel != nil {
|
||||||
|
form.OnCancel = cancel
|
||||||
|
form.CancelText = lang.L("cancel")
|
||||||
|
}
|
||||||
|
|
||||||
|
messageHead := lang.L("settings")
|
||||||
|
return widget.NewCard(messageHead, "", form)
|
||||||
|
}
|
28
internal/gui/view/start_without_support_lang.go
Normal file
28
internal/gui/view/start_without_support_lang.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package view
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/setting"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StartWithoutSupportLang(languages []setting.Lang, funcSelected func(lang setting.Lang)) fyne.CanvasObject {
|
||||||
|
listView := widget.NewList(
|
||||||
|
func() int {
|
||||||
|
return len(languages)
|
||||||
|
},
|
||||||
|
func() fyne.CanvasObject {
|
||||||
|
return widget.NewLabel("template")
|
||||||
|
},
|
||||||
|
func(i widget.ListItemID, o fyne.CanvasObject) {
|
||||||
|
block := o.(*widget.Label)
|
||||||
|
block.SetText(languages[i].Title)
|
||||||
|
})
|
||||||
|
listView.OnSelected = func(id widget.ListItemID) {
|
||||||
|
funcSelected(languages[id])
|
||||||
|
}
|
||||||
|
|
||||||
|
messageHead := lang.L("languageSelectionHead")
|
||||||
|
return widget.NewCard(messageHead, "", listView)
|
||||||
|
}
|
172
internal/gui/window/layout.go
Normal file
172
internal/gui/window/layout.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package window
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LayoutContract interface {
|
||||||
|
SetContent(content fyne.CanvasObject) fyne.CanvasObject
|
||||||
|
GetRContainer() RightMainContainerContract
|
||||||
|
}
|
||||||
|
|
||||||
|
type layout struct {
|
||||||
|
layoutContainer *fyne.Container
|
||||||
|
rContainer RightMainContainerContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLayout(progressBarService convertor.ProgressBarContract, itemsToConvert convertor.ItemsToConvertContract, queueLayout QueueLayoutContract) LayoutContract {
|
||||||
|
rContainer := newRightContainer(progressBarService.GetContainer(), itemsToConvert, queueLayout)
|
||||||
|
layoutContainer := container.NewAdaptiveGrid(2, widget.NewLabel(""), rContainer.GetCanvasObject())
|
||||||
|
|
||||||
|
return &layout{
|
||||||
|
layoutContainer: layoutContainer,
|
||||||
|
rContainer: rContainer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *layout) SetContent(content fyne.CanvasObject) fyne.CanvasObject {
|
||||||
|
l.layoutContainer.Objects[0] = content
|
||||||
|
return l.layoutContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *layout) GetRContainer() RightMainContainerContract {
|
||||||
|
return l.rContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
type RightMainContainerContract interface {
|
||||||
|
GetCanvasObject() fyne.CanvasObject
|
||||||
|
GetTabs() *container.AppTabs
|
||||||
|
SelectFileQueueTab()
|
||||||
|
SelectAddedFilesTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
type rightMainContainer struct {
|
||||||
|
container fyne.CanvasObject
|
||||||
|
tabs *container.AppTabs
|
||||||
|
addedFilesTab *container.TabItem
|
||||||
|
fileQueueTab *container.TabItem
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRightContainer(blockProgressbar *fyne.Container, itemsToConvert convertor.ItemsToConvertContract, queueLayout QueueLayoutContract) RightMainContainerContract {
|
||||||
|
addedFilesTab := container.NewTabItem(lang.L("addedFilesTitle"), addedFilesContainer(itemsToConvert))
|
||||||
|
fileQueueTab := container.NewTabItem(lang.L("fileQueueTitle"), fileQueueContainer(queueLayout))
|
||||||
|
|
||||||
|
tabs := container.NewAppTabs(
|
||||||
|
addedFilesTab,
|
||||||
|
fileQueueTab,
|
||||||
|
)
|
||||||
|
|
||||||
|
rightContainer := container.NewBorder(
|
||||||
|
container.NewVBox(
|
||||||
|
blockProgressbar,
|
||||||
|
widget.NewSeparator(),
|
||||||
|
),
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
tabs,
|
||||||
|
)
|
||||||
|
|
||||||
|
return &rightMainContainer{
|
||||||
|
container: rightContainer,
|
||||||
|
tabs: tabs,
|
||||||
|
addedFilesTab: addedFilesTab,
|
||||||
|
fileQueueTab: fileQueueTab,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rightMainContainer) GetCanvasObject() fyne.CanvasObject {
|
||||||
|
return r.container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rightMainContainer) GetTabs() *container.AppTabs {
|
||||||
|
return r.tabs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rightMainContainer) SelectFileQueueTab() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
r.tabs.Select(r.fileQueueTab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *rightMainContainer) SelectAddedFilesTab() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
r.tabs.Select(r.addedFilesTab)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func addedFilesContainer(itemsToConvert convertor.ItemsToConvertContract) *fyne.Container {
|
||||||
|
line := canvas.NewLine(theme.Color(theme.ColorNameFocus))
|
||||||
|
line.StrokeWidth = 5
|
||||||
|
checkboxAutoRemove := widget.NewCheck(
|
||||||
|
lang.L("autoClearAfterAddingToQueue"),
|
||||||
|
func(checked bool) {
|
||||||
|
itemsToConvert.SetIsAutoRemove(checked)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
checkboxAutoRemove.SetChecked(itemsToConvert.GetIsAutoRemove())
|
||||||
|
|
||||||
|
buttonClear := widget.NewButton(
|
||||||
|
lang.L("clearAll"),
|
||||||
|
func() {
|
||||||
|
itemsToConvert.Clear()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
buttonClear.Importance = widget.DangerImportance
|
||||||
|
return container.NewBorder(
|
||||||
|
container.NewVBox(
|
||||||
|
container.NewPadded(),
|
||||||
|
container.NewBorder(nil, nil, nil, buttonClear, container.NewHScroll(checkboxAutoRemove)),
|
||||||
|
container.NewPadded(),
|
||||||
|
line,
|
||||||
|
), nil, nil, nil,
|
||||||
|
container.NewVScroll(
|
||||||
|
container.NewBorder(
|
||||||
|
nil, nil, nil, container.NewPadded(),
|
||||||
|
container.NewVBox(
|
||||||
|
container.NewPadded(),
|
||||||
|
itemsToConvert.GetItemsContainer(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileQueueContainer(queueLayout QueueLayoutContract) *fyne.Container {
|
||||||
|
title := widget.NewLabel(lang.L("queue"))
|
||||||
|
title.TextStyle.Bold = true
|
||||||
|
|
||||||
|
line := canvas.NewLine(theme.Color(theme.ColorNameFocus))
|
||||||
|
line.StrokeWidth = 5
|
||||||
|
|
||||||
|
queueLayout.GetQueueStatistics().GetWaiting().SetTitle(lang.L("waitingQueue"))
|
||||||
|
queueLayout.GetQueueStatistics().GetInProgress().SetTitle(lang.L("inProgressQueue"))
|
||||||
|
queueLayout.GetQueueStatistics().GetCompleted().SetTitle(lang.L("completedQueue"))
|
||||||
|
queueLayout.GetQueueStatistics().GetError().SetTitle(lang.L("errorQueue"))
|
||||||
|
queueLayout.GetQueueStatistics().GetTotal().SetTitle(lang.L("total"))
|
||||||
|
|
||||||
|
return container.NewBorder(
|
||||||
|
container.NewVBox(
|
||||||
|
container.NewPadded(),
|
||||||
|
container.NewHBox(title, queueLayout.GetQueueStatistics().GetCompleted().GetCheckbox(), queueLayout.GetQueueStatistics().GetError().GetCheckbox()),
|
||||||
|
container.NewHBox(queueLayout.GetQueueStatistics().GetInProgress().GetCheckbox(), queueLayout.GetQueueStatistics().GetWaiting().GetCheckbox(), queueLayout.GetQueueStatistics().GetTotal().GetCheckbox()),
|
||||||
|
container.NewPadded(),
|
||||||
|
line,
|
||||||
|
), nil, nil, nil,
|
||||||
|
container.NewVScroll(
|
||||||
|
container.NewBorder(
|
||||||
|
nil, nil, nil, container.NewPadded(),
|
||||||
|
container.NewVBox(
|
||||||
|
container.NewPadded(),
|
||||||
|
queueLayout.GetItemsContainer(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
101
internal/gui/window/main.go
Normal file
101
internal/gui/window/main.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package window
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/dialog"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WindowContract interface {
|
||||||
|
SetContent(content fyne.CanvasObject)
|
||||||
|
SetMainMenu(menu *fyne.MainMenu)
|
||||||
|
Show()
|
||||||
|
InitLayout()
|
||||||
|
NewFileOpen(callback func(fyne.URIReadCloser, error), location fyne.ListableURI) *dialog.FileDialog
|
||||||
|
NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog
|
||||||
|
SetOnDropped(callback func(position fyne.Position, uris []fyne.URI))
|
||||||
|
GetLayout() LayoutContract
|
||||||
|
}
|
||||||
|
|
||||||
|
type mainWindow struct {
|
||||||
|
fyneWindow fyne.Window
|
||||||
|
layout LayoutContract
|
||||||
|
itemsToConvert convertor.ItemsToConvertContract
|
||||||
|
progressBarService convertor.ProgressBarContract
|
||||||
|
queueLayout QueueLayoutContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMainWindow(
|
||||||
|
fyneWindow fyne.Window,
|
||||||
|
progressBarService convertor.ProgressBarContract,
|
||||||
|
itemsToConvert convertor.ItemsToConvertContract,
|
||||||
|
queueLayout QueueLayoutContract,
|
||||||
|
) WindowContract {
|
||||||
|
fyneWindow.Resize(fyne.Size{Width: 1039, Height: 599})
|
||||||
|
fyneWindow.CenterOnScreen()
|
||||||
|
|
||||||
|
return &mainWindow{
|
||||||
|
fyneWindow: fyneWindow,
|
||||||
|
progressBarService: progressBarService,
|
||||||
|
itemsToConvert: itemsToConvert,
|
||||||
|
queueLayout: queueLayout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) SetMainMenu(menu *fyne.MainMenu) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
w.fyneWindow.SetMainMenu(menu)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) InitLayout() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
w.layout = NewLayout(w.progressBarService, w.itemsToConvert, w.queueLayout)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) GetLayout() LayoutContract {
|
||||||
|
return w.layout
|
||||||
|
}
|
||||||
|
|
||||||
|
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) NewFolderOpen(callback func(fyne.ListableURI, error), location fyne.ListableURI) *dialog.FileDialog {
|
||||||
|
fileDialog := dialog.NewFolderOpen(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) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
if w.layout == nil {
|
||||||
|
w.fyneWindow.SetContent(content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.fyneWindow.SetContent(w.layout.SetContent(content))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) Show() {
|
||||||
|
w.fyneWindow.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *mainWindow) SetOnDropped(callback func(position fyne.Position, uris []fyne.URI)) {
|
||||||
|
fyne.Do(func() {
|
||||||
|
w.fyneWindow.SetOnDropped(callback)
|
||||||
|
})
|
||||||
|
}
|
459
internal/gui/window/queue.go
Normal file
459
internal/gui/window/queue.go
Normal file
@@ -0,0 +1,459 @@
|
|||||||
|
package window
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/canvas"
|
||||||
|
"fyne.io/fyne/v2/container"
|
||||||
|
"fyne.io/fyne/v2/lang"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/application/convertor"
|
||||||
|
"git.kor-elf.net/kor-elf/gui-for-ffmpeg/internal/ffmpeg"
|
||||||
|
"image/color"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type QueueLayoutContract interface {
|
||||||
|
GetItemsContainer() *fyne.Container
|
||||||
|
GetQueueStatistics() QueueStatisticsAllContract
|
||||||
|
|
||||||
|
AddQueue(key int, queue *convertor.Queue)
|
||||||
|
ChangeQueue(key int, queue *convertor.Queue)
|
||||||
|
RemoveQueue(key int, status convertor.StatusContract)
|
||||||
|
}
|
||||||
|
|
||||||
|
type queueLayout struct {
|
||||||
|
itemsContainer *fyne.Container
|
||||||
|
queueAllStatistics QueueStatisticsAllContract
|
||||||
|
items map[int]queueLayoutItem
|
||||||
|
ffmpegService ffmpeg.UtilitiesContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQueueLayout(ffmpegService ffmpeg.UtilitiesContract) QueueLayoutContract {
|
||||||
|
items := map[int]queueLayoutItem{}
|
||||||
|
|
||||||
|
return &queueLayout{
|
||||||
|
itemsContainer: container.NewVBox(),
|
||||||
|
queueAllStatistics: newQueueAllStatistics(&items),
|
||||||
|
items: items,
|
||||||
|
ffmpegService: ffmpegService,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) GetItemsContainer() *fyne.Container {
|
||||||
|
return l.itemsContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) GetQueueStatistics() QueueStatisticsAllContract {
|
||||||
|
return l.queueAllStatistics
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) AddQueue(queueID int, queue *convertor.Queue) {
|
||||||
|
|
||||||
|
statusMessage := canvas.NewText(l.getStatusTitle(queue.Status), theme.Color(theme.ColorNamePrimary))
|
||||||
|
messageError := canvas.NewText("", theme.Color(theme.ColorNameError))
|
||||||
|
buttonPlay := widget.NewButtonWithIcon("", theme.Icon(theme.IconNameMediaPlay), func() {
|
||||||
|
|
||||||
|
})
|
||||||
|
buttonPlay.Hide()
|
||||||
|
blockMessageError := container.NewHScroll(messageError)
|
||||||
|
blockMessageError.Hide()
|
||||||
|
|
||||||
|
content := container.NewVBox(
|
||||||
|
container.NewHScroll(widget.NewLabel(queue.Setting.FileInput.Name)),
|
||||||
|
container.NewHBox(
|
||||||
|
buttonPlay,
|
||||||
|
statusMessage,
|
||||||
|
),
|
||||||
|
blockMessageError,
|
||||||
|
container.NewPadded(),
|
||||||
|
canvas.NewLine(theme.Color(theme.ColorNameFocus)),
|
||||||
|
container.NewPadded(),
|
||||||
|
)
|
||||||
|
|
||||||
|
l.addQueueStatistics()
|
||||||
|
if l.GetQueueStatistics().IsChecked(queue.Status) == false {
|
||||||
|
content.Hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
l.items[queueID] = queueLayoutItem{
|
||||||
|
CanvasObject: content,
|
||||||
|
StatusMessage: statusMessage,
|
||||||
|
BlockMessageError: blockMessageError,
|
||||||
|
MessageError: messageError,
|
||||||
|
buttonPlay: buttonPlay,
|
||||||
|
status: &queue.Status,
|
||||||
|
}
|
||||||
|
l.itemsContainer.Add(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) ChangeQueue(queueID int, queue *convertor.Queue) {
|
||||||
|
if item, ok := l.items[queueID]; ok {
|
||||||
|
statusColor := l.getStatusColor(queue.Status)
|
||||||
|
fyne.Do(func() {
|
||||||
|
item.StatusMessage.Text = l.getStatusTitle(queue.Status)
|
||||||
|
item.StatusMessage.Color = statusColor
|
||||||
|
item.StatusMessage.Refresh()
|
||||||
|
})
|
||||||
|
if queue.Error != nil {
|
||||||
|
fyne.Do(func() {
|
||||||
|
item.MessageError.Text = queue.Error.Error()
|
||||||
|
item.MessageError.Color = statusColor
|
||||||
|
item.BlockMessageError.Show()
|
||||||
|
item.MessageError.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if queue.Status == convertor.StatusType(convertor.Completed) {
|
||||||
|
item.buttonPlay.Show()
|
||||||
|
item.buttonPlay.OnTapped = func() {
|
||||||
|
item.buttonPlay.Disable()
|
||||||
|
go func() {
|
||||||
|
ffplay, err := l.ffmpegService.GetFFplay()
|
||||||
|
if err == nil {
|
||||||
|
_ = ffplay.Play(&queue.Setting.FileOut)
|
||||||
|
}
|
||||||
|
fyne.Do(func() {
|
||||||
|
item.buttonPlay.Enable()
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.GetQueueStatistics().IsChecked(queue.Status) == false && item.CanvasObject.Visible() == true {
|
||||||
|
item.CanvasObject.Hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
if l.GetQueueStatistics().IsChecked(queue.Status) == true && item.CanvasObject.Visible() == false {
|
||||||
|
item.CanvasObject.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
l.changeQueueStatistics(queue.Status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) RemoveQueue(queueID int, status convertor.StatusContract) {
|
||||||
|
if item, ok := l.items[queueID]; ok {
|
||||||
|
l.itemsContainer.Remove(item.CanvasObject)
|
||||||
|
l.removeQueueStatistics(status)
|
||||||
|
l.items[queueID] = queueLayoutItem{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) addQueueStatistics() {
|
||||||
|
l.GetQueueStatistics().GetWaiting().Add()
|
||||||
|
l.GetQueueStatistics().GetTotal().Add()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) changeQueueStatistics(status convertor.StatusContract) {
|
||||||
|
if status == convertor.StatusType(convertor.InProgress) {
|
||||||
|
l.GetQueueStatistics().GetWaiting().Remove()
|
||||||
|
l.GetQueueStatistics().GetInProgress().Add()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Completed) {
|
||||||
|
l.GetQueueStatistics().GetInProgress().Remove()
|
||||||
|
l.GetQueueStatistics().GetCompleted().Add()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Error) {
|
||||||
|
l.GetQueueStatistics().GetInProgress().Remove()
|
||||||
|
l.GetQueueStatistics().GetError().Add()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) removeQueueStatistics(status convertor.StatusContract) {
|
||||||
|
l.GetQueueStatistics().GetTotal().Remove()
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Completed) {
|
||||||
|
l.GetQueueStatistics().GetCompleted().Remove()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Error) {
|
||||||
|
l.GetQueueStatistics().GetError().Remove()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.InProgress) {
|
||||||
|
l.GetQueueStatistics().GetInProgress().Remove()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Waiting) {
|
||||||
|
l.GetQueueStatistics().GetWaiting().Remove()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) getStatusTitle(status convertor.StatusContract) string {
|
||||||
|
return lang.L(status.Name() + "Queue")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *queueLayout) getStatusColor(status convertor.StatusContract) color.Color {
|
||||||
|
if status == convertor.StatusType(convertor.Error) {
|
||||||
|
return theme.Color(theme.ColorNameError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == convertor.StatusType(convertor.Completed) {
|
||||||
|
return color.RGBA{R: 49, G: 127, B: 114, A: 255}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme.Color(theme.ColorNamePrimary)
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueueStatisticsAllContract interface {
|
||||||
|
GetWaiting() QueueStatisticsContract
|
||||||
|
GetInProgress() QueueStatisticsContract
|
||||||
|
GetCompleted() QueueStatisticsContract
|
||||||
|
GetError() QueueStatisticsContract
|
||||||
|
GetTotal() QueueStatisticsContract
|
||||||
|
|
||||||
|
IsChecked(status convertor.StatusContract) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type queueAllStatistics struct {
|
||||||
|
waiting QueueStatisticsContract
|
||||||
|
inProgress QueueStatisticsContract
|
||||||
|
completed QueueStatisticsContract
|
||||||
|
error QueueStatisticsContract
|
||||||
|
total QueueStatisticsContract
|
||||||
|
}
|
||||||
|
|
||||||
|
func newQueueAllStatistics(queueItems *map[int]queueLayoutItem) QueueStatisticsAllContract {
|
||||||
|
checkboxWaiting := newQueueStatistics()
|
||||||
|
checkboxInProgress := newQueueStatistics()
|
||||||
|
checkboxCompleted := newQueueStatistics()
|
||||||
|
checkboxError := newQueueStatistics()
|
||||||
|
CheckboxTotal := newQueueStatistics()
|
||||||
|
|
||||||
|
queueAllStatistics := &queueAllStatistics{
|
||||||
|
waiting: checkboxWaiting,
|
||||||
|
inProgress: checkboxInProgress,
|
||||||
|
completed: checkboxCompleted,
|
||||||
|
error: checkboxError,
|
||||||
|
total: CheckboxTotal,
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckboxTotal.GetCheckbox().OnChanged = func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
queueAllStatistics.allCheckboxChecked()
|
||||||
|
} else {
|
||||||
|
queueAllStatistics.allUnCheckboxChecked()
|
||||||
|
}
|
||||||
|
queueAllStatistics.redrawingQueueItems(queueItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxWaiting.GetCheckbox().OnChanged = func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
queueAllStatistics.checkboxChecked()
|
||||||
|
} else {
|
||||||
|
queueAllStatistics.unCheckboxChecked()
|
||||||
|
}
|
||||||
|
queueAllStatistics.redrawingQueueItems(queueItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxInProgress.GetCheckbox().OnChanged = func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
queueAllStatistics.checkboxChecked()
|
||||||
|
} else {
|
||||||
|
queueAllStatistics.unCheckboxChecked()
|
||||||
|
}
|
||||||
|
queueAllStatistics.redrawingQueueItems(queueItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxCompleted.GetCheckbox().OnChanged = func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
queueAllStatistics.checkboxChecked()
|
||||||
|
} else {
|
||||||
|
queueAllStatistics.unCheckboxChecked()
|
||||||
|
}
|
||||||
|
queueAllStatistics.redrawingQueueItems(queueItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkboxError.GetCheckbox().OnChanged = func(b bool) {
|
||||||
|
if b == true {
|
||||||
|
queueAllStatistics.checkboxChecked()
|
||||||
|
} else {
|
||||||
|
queueAllStatistics.unCheckboxChecked()
|
||||||
|
}
|
||||||
|
queueAllStatistics.redrawingQueueItems(queueItems)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queueAllStatistics
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) GetWaiting() QueueStatisticsContract {
|
||||||
|
return s.waiting
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) GetInProgress() QueueStatisticsContract {
|
||||||
|
return s.inProgress
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) GetCompleted() QueueStatisticsContract {
|
||||||
|
return s.completed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) GetError() QueueStatisticsContract {
|
||||||
|
return s.error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) GetTotal() QueueStatisticsContract {
|
||||||
|
return s.total
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) IsChecked(status convertor.StatusContract) bool {
|
||||||
|
if status == convertor.StatusType(convertor.InProgress) {
|
||||||
|
return s.inProgress.GetCheckbox().Checked
|
||||||
|
}
|
||||||
|
if status == convertor.StatusType(convertor.Completed) {
|
||||||
|
return s.completed.GetCheckbox().Checked
|
||||||
|
}
|
||||||
|
if status == convertor.StatusType(convertor.Error) {
|
||||||
|
return s.error.GetCheckbox().Checked
|
||||||
|
}
|
||||||
|
if status == convertor.StatusType(convertor.Waiting) {
|
||||||
|
return s.waiting.GetCheckbox().Checked
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) redrawingQueueItems(queueItems *map[int]queueLayoutItem) {
|
||||||
|
for _, item := range *queueItems {
|
||||||
|
if s.IsChecked(*item.status) == true && item.CanvasObject.Visible() == false {
|
||||||
|
item.CanvasObject.Show()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s.IsChecked(*item.status) == false && item.CanvasObject.Visible() == true {
|
||||||
|
item.CanvasObject.Hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) checkboxChecked() {
|
||||||
|
if s.total.GetCheckbox().Checked == true {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.waiting.GetCheckbox().Checked == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.inProgress.GetCheckbox().Checked == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.completed.GetCheckbox().Checked == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.error.GetCheckbox().Checked == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.total.GetCheckbox().Checked = true
|
||||||
|
s.total.GetCheckbox().Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) unCheckboxChecked() {
|
||||||
|
if s.total.GetCheckbox().Checked == false {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.total.GetCheckbox().Checked = false
|
||||||
|
s.total.GetCheckbox().Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) allCheckboxChecked() {
|
||||||
|
s.waiting.GetCheckbox().Checked = true
|
||||||
|
s.waiting.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.inProgress.GetCheckbox().Checked = true
|
||||||
|
s.inProgress.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.completed.GetCheckbox().Checked = true
|
||||||
|
s.completed.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.error.GetCheckbox().Checked = true
|
||||||
|
s.error.GetCheckbox().Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueAllStatistics) allUnCheckboxChecked() {
|
||||||
|
s.waiting.GetCheckbox().Checked = false
|
||||||
|
s.waiting.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.inProgress.GetCheckbox().Checked = false
|
||||||
|
s.inProgress.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.completed.GetCheckbox().Checked = false
|
||||||
|
s.completed.GetCheckbox().Refresh()
|
||||||
|
|
||||||
|
s.error.GetCheckbox().Checked = false
|
||||||
|
s.error.GetCheckbox().Refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
type QueueStatisticsContract interface {
|
||||||
|
SetTitle(title string)
|
||||||
|
GetCheckbox() *widget.Check
|
||||||
|
Add()
|
||||||
|
Remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
type queueStatistics struct {
|
||||||
|
checkbox *widget.Check
|
||||||
|
title string
|
||||||
|
count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newQueueStatistics() QueueStatisticsContract {
|
||||||
|
checkbox := widget.NewCheck(": 0", nil)
|
||||||
|
checkbox.Checked = true
|
||||||
|
|
||||||
|
return &queueStatistics{
|
||||||
|
checkbox: checkbox,
|
||||||
|
title: "",
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueStatistics) SetTitle(title string) {
|
||||||
|
s.title = strings.ToLower(title)
|
||||||
|
s.checkbox.Text = title + ": " + strconv.FormatInt(s.count, 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueStatistics) GetCheckbox() *widget.Check {
|
||||||
|
return s.checkbox
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueStatistics) Add() {
|
||||||
|
s.count += 1
|
||||||
|
s.formatText()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueStatistics) Remove() {
|
||||||
|
if s.count == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.count -= 1
|
||||||
|
s.formatText()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *queueStatistics) formatText() {
|
||||||
|
fyne.Do(func() {
|
||||||
|
s.checkbox.Text = s.title + ": " + strconv.FormatInt(s.count, 10)
|
||||||
|
s.checkbox.Refresh()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type queueLayoutItem struct {
|
||||||
|
CanvasObject fyne.CanvasObject
|
||||||
|
BlockMessageError *container.Scroll
|
||||||
|
StatusMessage *canvas.Text
|
||||||
|
MessageError *canvas.Text
|
||||||
|
buttonPlay *widget.Button
|
||||||
|
status *convertor.StatusContract
|
||||||
|
}
|
13
internal/resources/icon.go
Normal file
13
internal/resources/icon.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed icons/logo.png
|
||||||
|
var iconAppLogo []byte
|
||||||
|
|
||||||
|
func IconAppLogoResource() *fyne.StaticResource {
|
||||||
|
return fyne.NewStaticResource("icon.png", iconAppLogo)
|
||||||
|
}
|
BIN
internal/resources/icons/logo.png
Normal file
BIN
internal/resources/icons/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
12
internal/resources/translation.go
Normal file
12
internal/resources/translation.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed translations
|
||||||
|
var translations embed.FS
|
||||||
|
|
||||||
|
func GetTranslations() embed.FS {
|
||||||
|
return translations
|
||||||
|
}
|
143
internal/resources/translations/app.en.json
Normal file
143
internal/resources/translations/app.en.json
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
{
|
||||||
|
"AlsoUsedProgram": "The program also uses:",
|
||||||
|
"about": "About",
|
||||||
|
"aboutText": "A simple interface for the FFmpeg console utility. \nBut I am not the author of the FFmpeg utility itself.",
|
||||||
|
"addedFilesTitle": "Added files",
|
||||||
|
"autoClearAfterAddingToQueue": "Auto-clear after adding to queue",
|
||||||
|
"buttonDownloadFFmpeg": "Download FFmpeg automatically",
|
||||||
|
"buttonForSelectedDirTitle": "Save to folder:",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"changeFFPath": "FFmpeg, FFprobe and FFplay",
|
||||||
|
"changeLanguage": "Change language",
|
||||||
|
"checkboxOverwriteOutputFilesTitle": "Allow file to be overwritten",
|
||||||
|
"choose": "choose",
|
||||||
|
"clearAll": "Clear List",
|
||||||
|
"completedQueue": "Completed",
|
||||||
|
"converterVideoFilesSubmitTitle": "Convert",
|
||||||
|
"converterVideoFilesTitle": "Video, audio and picture converter",
|
||||||
|
"download": "Download",
|
||||||
|
"downloadFFmpegFromSite": "Will be downloaded from the site:",
|
||||||
|
"downloadRun": "Downloading...",
|
||||||
|
"dragAndDropFiles": "drag and drop files",
|
||||||
|
"encoderGroupAudio": "Audio",
|
||||||
|
"encoderGroupImage": "Images",
|
||||||
|
"encoderGroupVideo": "Video",
|
||||||
|
"encoder_apng": "APNG image",
|
||||||
|
"encoder_bmp": "BMP image",
|
||||||
|
"encoder_flv": "FLV",
|
||||||
|
"encoder_gif": "GIF image",
|
||||||
|
"encoder_h264_nvenc": "H.264 with NVIDIA support",
|
||||||
|
"encoder_libmp3lame": "libmp3lame MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libshine": "libshine MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libtwolame": "libtwolame MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_libvpx": "libvpx VP8 (codec vp8)",
|
||||||
|
"encoder_libvpx-vp9": "libvpx VP9 (codec vp9)",
|
||||||
|
"encoder_libwebp": "libwebp WebP image",
|
||||||
|
"encoder_libwebp_anim": "libwebp_anim WebP image",
|
||||||
|
"encoder_libx264": "H.264 libx264",
|
||||||
|
"encoder_libx265": "H.265 libx265",
|
||||||
|
"encoder_libxvid": "libxvidcore MPEG-4 part 2",
|
||||||
|
"encoder_mjpeg": "MJPEG (Motion JPEG)",
|
||||||
|
"encoder_mp2": "MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_mp2fixed": "MP2 fixed point (MPEG audio layer 2)",
|
||||||
|
"encoder_mpeg1video": "MPEG-1",
|
||||||
|
"encoder_mpeg2video": "MPEG-2",
|
||||||
|
"encoder_mpeg4": "MPEG-4 part 2",
|
||||||
|
"encoder_msmpeg4": "MPEG-4 part 2 Microsoft variant version 3",
|
||||||
|
"encoder_msmpeg4v2": "MPEG-4 part 2 Microsoft variant version 2",
|
||||||
|
"encoder_msvideo1": "Microsoft Video-1",
|
||||||
|
"encoder_png": "PNG image",
|
||||||
|
"encoder_qtrle": "QuickTime Animation (RLE) video",
|
||||||
|
"encoder_sgi": "SGI image",
|
||||||
|
"encoder_tiff": "TIFF image",
|
||||||
|
"encoder_wmav1": "Windows Media Audio 1",
|
||||||
|
"encoder_wmav2": "Windows Media Audio 2",
|
||||||
|
"encoder_wmv1": "Windows Media Video 7",
|
||||||
|
"encoder_wmv2": "Windows Media Video 8",
|
||||||
|
"encoder_xbm": "XBM (X BitMap) image",
|
||||||
|
"error": "An error has occurred!",
|
||||||
|
"errorConverter": "Couldn't convert video",
|
||||||
|
"errorDragAndDropFile": "Not all files were added",
|
||||||
|
"errorFFmpeg": "this is not FFmpeg",
|
||||||
|
"errorFFmpegVersion": "Could not determine FFmpeg version",
|
||||||
|
"errorFFplay": "this is not FFplay",
|
||||||
|
"errorFFplayVersion": "Could not determine FFplay version",
|
||||||
|
"errorFFprobe": "this is not FFprobe",
|
||||||
|
"errorFFprobeVersion": "Failed to determine FFprobe version",
|
||||||
|
"errorNoFilesAddedForConversion": "There are no files to convert",
|
||||||
|
"errorQueue": "Error",
|
||||||
|
"errorSelectedEncoder": "Converter not selected",
|
||||||
|
"errorSelectedFolderSave": "No save folder selected!",
|
||||||
|
"errorSelectedFormat": "File extension not selected",
|
||||||
|
"exit": "Exit",
|
||||||
|
"ffmpegLGPL": "This software uses libraries from the **FFmpeg** project under the **[LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**.",
|
||||||
|
"ffmpegTrademark": "**FFmpeg** is a trademark of **[Fabrice Bellard](http://bellard.org/)**, originator of the **[FFmpeg](https://ffmpeg.org/about.html)** project.",
|
||||||
|
"fileForConversionTitle": "File:",
|
||||||
|
"fileQueueTitle": "Queue",
|
||||||
|
"formPreset": "Preset",
|
||||||
|
"gratitude": "Gratitude",
|
||||||
|
"gratitudeText": "I sincerely thank you for your invaluable\n\r and timely assistance:",
|
||||||
|
"help": "Help",
|
||||||
|
"helpFFplay": "FFplay Player Keys",
|
||||||
|
"helpFFplayActivateFrameStepMode": "Activate frame-by-frame mode.",
|
||||||
|
"helpFFplayCycleVideoFiltersOrShowModes": "A cycle of video filters or display modes.",
|
||||||
|
"helpFFplayDecreaseVolume": "Decrease the volume.",
|
||||||
|
"helpFFplayDescription": "Description",
|
||||||
|
"helpFFplayDoubleClickLeftMouseButton": "double click\nleft mouse button",
|
||||||
|
"helpFFplayIncreaseVolume": "Increase the volume.",
|
||||||
|
"helpFFplayKeyDown": "down",
|
||||||
|
"helpFFplayKeyHoldS": "hold S",
|
||||||
|
"helpFFplayKeyLeft": "left",
|
||||||
|
"helpFFplayKeyRight": "right",
|
||||||
|
"helpFFplayKeySpace": "SPACE",
|
||||||
|
"helpFFplayKeyUp": "up",
|
||||||
|
"helpFFplayKeys": "Keys",
|
||||||
|
"helpFFplayPause": "Pause or continue playing.",
|
||||||
|
"helpFFplayQuit": "Close the player.",
|
||||||
|
"helpFFplaySeekBForward10Minutes": "Fast forward 10 minutes.",
|
||||||
|
"helpFFplaySeekBForward1Minute": "Fast forward 1 minute.",
|
||||||
|
"helpFFplaySeekBackward10Minutes": "Rewind 10 minutes.",
|
||||||
|
"helpFFplaySeekBackward10Seconds": "Rewind 10 seconds.",
|
||||||
|
"helpFFplaySeekBackward1Minute": "Rewind 1 minute.",
|
||||||
|
"helpFFplaySeekForward10Seconds": "Fast forward 10 seconds.",
|
||||||
|
"helpFFplayToggleFullScreen": "Switch to full screen or exit full screen.",
|
||||||
|
"helpFFplayToggleMute": "Mute or unmute.",
|
||||||
|
"inProgressQueue": "In Progress",
|
||||||
|
"languageSelectionFormHead": "Switch language",
|
||||||
|
"languageSelectionHead": "Choose language",
|
||||||
|
"licenseLink": "License information",
|
||||||
|
"licenseLinkOther": "Licenses from other products used in the program",
|
||||||
|
"menuSettingsLanguage": "Language",
|
||||||
|
"menuSettingsTheme": "Theme",
|
||||||
|
"or": "or",
|
||||||
|
"parameterCheckbox": "Enable option",
|
||||||
|
"pathToFfmpeg": "Path to FFmpeg:",
|
||||||
|
"pathToFfplay": "Path to FFplay:",
|
||||||
|
"pathToFfprobe": "Path to FFprobe:",
|
||||||
|
"preset_fast": "fast (slower than \"faster\", but the file will weigh less)",
|
||||||
|
"preset_faster": "faster (slower than \"veryfast\", but the file will weigh less)",
|
||||||
|
"preset_medium": "medium (slower than \"fast\", but the file will weigh less)",
|
||||||
|
"preset_placebo": "placebo (not recommended)",
|
||||||
|
"preset_slow": "slow (slower than \"medium\", but the file will weigh less)",
|
||||||
|
"preset_slower": "slower (slower than \"slow\", but the file will weigh less)",
|
||||||
|
"preset_superfast": "superfast (slower than \"ultrafast\", but the file will weigh less)",
|
||||||
|
"preset_ultrafast": "ultrafast (fast, but the file will weigh a lot)",
|
||||||
|
"preset_veryfast": "veryfast (slower than \"superfast\", but the file will weigh less)",
|
||||||
|
"preset_veryslow": "veryslow (slower than \"slower\", but the file will weigh less)",
|
||||||
|
"programmLink": "Project website",
|
||||||
|
"programmVersion": "**Program version:** {{.Version}}",
|
||||||
|
"queue": "Queue",
|
||||||
|
"save": "Save",
|
||||||
|
"selectEncoder": "Encoder:",
|
||||||
|
"selectFFPathTitle": "Specify the path to FFmpeg and FFprobe",
|
||||||
|
"selectFormat": "File extension:",
|
||||||
|
"settings": "Settings",
|
||||||
|
"testFF": "Checking FFmpeg for serviceability...",
|
||||||
|
"themesNameDark": "Dark",
|
||||||
|
"themesNameDefault": "Default",
|
||||||
|
"themesNameLight": "Light",
|
||||||
|
"titleDownloadLink": "You can download it from here",
|
||||||
|
"total": "Total",
|
||||||
|
"unzipRun": "Unpacked...",
|
||||||
|
"waitingQueue": "Waiting"
|
||||||
|
}
|
143
internal/resources/translations/app.kk.json
Normal file
143
internal/resources/translations/app.kk.json
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
{
|
||||||
|
"AlsoUsedProgram": "Бағдарлама сонымен қатар пайдаланады:",
|
||||||
|
"about": "Бағдарлама туралы",
|
||||||
|
"aboutText": "FFmpeg консоль утилитасы үшін қарапайым интерфейс. \nБірақ мен FFmpeg утилитасының авторы емеспін.",
|
||||||
|
"addedFilesTitle": "Қосылған файлдар",
|
||||||
|
"autoClearAfterAddingToQueue": "Кезекке қосқаннан кейін тазалаңыз",
|
||||||
|
"buttonDownloadFFmpeg": "FFmpeg автоматты түрде жүктеп алыңыз",
|
||||||
|
"buttonForSelectedDirTitle": "Қалтаға сақтаңыз:",
|
||||||
|
"cancel": "Болдырмау",
|
||||||
|
"changeFFPath": "FFmpeg, FFprobe және FFplay",
|
||||||
|
"changeLanguage": "Тілді өзгерту",
|
||||||
|
"checkboxOverwriteOutputFilesTitle": "Файлды қайта жазуға рұқсат беріңіз",
|
||||||
|
"choose": "таңдау",
|
||||||
|
"clearAll": "Тізімді өшіру",
|
||||||
|
"completedQueue": "Дайын",
|
||||||
|
"converterVideoFilesSubmitTitle": "Файлды түрлендіру",
|
||||||
|
"converterVideoFilesTitle": "Бейне, аудио және суретті түрлендіргіш",
|
||||||
|
"download": "Жүктеп алу",
|
||||||
|
"downloadFFmpegFromSite": "Сайттан жүктеледі:",
|
||||||
|
"downloadRun": "Жүктеп алынуда...",
|
||||||
|
"dragAndDropFiles": "файлдарды сүйреп апарыңыз",
|
||||||
|
"encoderGroupAudio": "Аудио",
|
||||||
|
"encoderGroupImage": "Суреттер",
|
||||||
|
"encoderGroupVideo": "Бейне",
|
||||||
|
"encoder_apng": "APNG image",
|
||||||
|
"encoder_bmp": "BMP image",
|
||||||
|
"encoder_flv": "FLV",
|
||||||
|
"encoder_gif": "GIF image",
|
||||||
|
"encoder_h264_nvenc": "NVIDIA қолдауымен H.264",
|
||||||
|
"encoder_libmp3lame": "libmp3lame MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libshine": "libshine MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libtwolame": "libtwolame MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_libvpx": "libvpx VP8 (codec vp8)",
|
||||||
|
"encoder_libvpx-vp9": "libvpx VP9 (codec vp9)",
|
||||||
|
"encoder_libwebp": "libwebp WebP image",
|
||||||
|
"encoder_libwebp_anim": "libwebp_anim WebP image",
|
||||||
|
"encoder_libx264": "H.264 libx264",
|
||||||
|
"encoder_libx265": "H.265 libx265",
|
||||||
|
"encoder_libxvid": "libxvidcore MPEG-4 part 2",
|
||||||
|
"encoder_mjpeg": "MJPEG (Motion JPEG)",
|
||||||
|
"encoder_mp2": "MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_mp2fixed": "MP2 fixed point (MPEG audio layer 2)",
|
||||||
|
"encoder_mpeg1video": "MPEG-1",
|
||||||
|
"encoder_mpeg2video": "MPEG-2",
|
||||||
|
"encoder_mpeg4": "MPEG-4 part 2",
|
||||||
|
"encoder_msmpeg4": "MPEG-4 part 2 Microsoft variant version 3",
|
||||||
|
"encoder_msmpeg4v2": "MPEG-4 part 2 Microsoft variant version 2",
|
||||||
|
"encoder_msvideo1": "Microsoft Video-1",
|
||||||
|
"encoder_png": "PNG image",
|
||||||
|
"encoder_qtrle": "QuickTime Animation (RLE) video",
|
||||||
|
"encoder_sgi": "SGI image",
|
||||||
|
"encoder_tiff": "TIFF image",
|
||||||
|
"encoder_wmav1": "Windows Media Audio 1",
|
||||||
|
"encoder_wmav2": "Windows Media Audio 2",
|
||||||
|
"encoder_wmv1": "Windows Media Video 7",
|
||||||
|
"encoder_wmv2": "Windows Media Video 8",
|
||||||
|
"encoder_xbm": "XBM (X BitMap) image",
|
||||||
|
"error": "Қате орын алды!",
|
||||||
|
"errorConverter": "Бейнені түрлендіру мүмкін болмады",
|
||||||
|
"errorDragAndDropFile": "Барлық файлдар қосылмаған",
|
||||||
|
"errorFFmpeg": "бұл FFmpeg емес",
|
||||||
|
"errorFFmpegVersion": "FFmpeg нұсқасын анықтау мүмкін болмады",
|
||||||
|
"errorFFplay": "бұл FFplay емес",
|
||||||
|
"errorFFplayVersion": "FFplay нұсқасын анықтау мүмкін болмады",
|
||||||
|
"errorFFprobe": "бұл FFprobe емес",
|
||||||
|
"errorFFprobeVersion": "FFprobe нұсқасын анықтау мүмкін болмады",
|
||||||
|
"errorNoFilesAddedForConversion": "Түрлендіруге арналған файлдар жоқ",
|
||||||
|
"errorQueue": "Қате",
|
||||||
|
"errorSelectedEncoder": "Түрлендіргіш таңдалмаған",
|
||||||
|
"errorSelectedFolderSave": "Сақтау қалтасы таңдалмаған!",
|
||||||
|
"errorSelectedFormat": "Файл кеңейтімі таңдалмаған",
|
||||||
|
"exit": "Шығу",
|
||||||
|
"ffmpegLGPL": "Бұл бағдарламалық құрал **[LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)** астында **FFmpeg** жобасының кітапханаларын пайдаланады.",
|
||||||
|
"ffmpegTrademark": "FFmpeg — **[FFmpeg](https://ffmpeg.org/about.html)** жобасын жасаушы **[Fabrice Bellard](http://bellard.org/)** сауда белгісі.",
|
||||||
|
"fileForConversionTitle": "Файл:",
|
||||||
|
"fileQueueTitle": "Кезек",
|
||||||
|
"formPreset": "Алдын ала орнатылған",
|
||||||
|
"gratitude": "Алғыс",
|
||||||
|
"gratitudeText": "Сізге баға жетпес және уақтылы көмектескеніңіз\n\r үшін шын жүректен алғыс айтамын:",
|
||||||
|
"help": "Анықтама",
|
||||||
|
"helpFFplay": "FFplay ойнатқышының пернелері",
|
||||||
|
"helpFFplayActivateFrameStepMode": "Уақыт аралығын іске қосыңыз.",
|
||||||
|
"helpFFplayCycleVideoFiltersOrShowModes": "Бейне сүзгілерінің немесе дисплей режимдерінің циклі.",
|
||||||
|
"helpFFplayDecreaseVolume": "Дыбыс деңгейін төмендетіңіз.",
|
||||||
|
"helpFFplayDescription": "Сипаттама",
|
||||||
|
"helpFFplayDoubleClickLeftMouseButton": "тінтуірдің сол жақ\nбатырмасын екі рет басу",
|
||||||
|
"helpFFplayIncreaseVolume": "Дыбыс деңгейін арттыру.",
|
||||||
|
"helpFFplayKeyDown": "төмен",
|
||||||
|
"helpFFplayKeyHoldS": "ұстау S",
|
||||||
|
"helpFFplayKeyLeft": "сол",
|
||||||
|
"helpFFplayKeyRight": "құқық",
|
||||||
|
"helpFFplayKeySpace": "SPACE (пробел)",
|
||||||
|
"helpFFplayKeyUp": "жоғары",
|
||||||
|
"helpFFplayKeys": "Кілттер",
|
||||||
|
"helpFFplayPause": "Кідіртіңіз немесе жоғалтуды жалғастырыңыз.",
|
||||||
|
"helpFFplayQuit": "Ойнатқышты жабыңыз.",
|
||||||
|
"helpFFplaySeekBForward10Minutes": "10 минутқа алға айналдырыңыз.",
|
||||||
|
"helpFFplaySeekBForward1Minute": "1 минутқа алға айналдырыңыз.",
|
||||||
|
"helpFFplaySeekBackward10Minutes": "10 минутқа артқа айналдырыңыз.",
|
||||||
|
"helpFFplaySeekBackward10Seconds": "10 секундқа артқа айналдырыңыз.",
|
||||||
|
"helpFFplaySeekBackward1Minute": "1 минутқа артқа айналдырыңыз.",
|
||||||
|
"helpFFplaySeekForward10Seconds": "10 секунд алға айналдырыңыз.",
|
||||||
|
"helpFFplayToggleFullScreen": "Толық экранға ауысу немесе толық экраннан шығу.",
|
||||||
|
"helpFFplayToggleMute": "Дыбысты өшіріңіз немесе дыбысты қосыңыз.",
|
||||||
|
"inProgressQueue": "Орындалуда",
|
||||||
|
"languageSelectionFormHead": "Тілді ауыстыру",
|
||||||
|
"languageSelectionHead": "Тілді таңдаңыз",
|
||||||
|
"licenseLink": "Лицензия туралы ақпарат",
|
||||||
|
"licenseLinkOther": "Бағдарламада пайдаланылатын басқа өнімдердің лицензиялары",
|
||||||
|
"menuSettingsLanguage": "Тіл",
|
||||||
|
"menuSettingsTheme": "Тақырып",
|
||||||
|
"or": "немесе",
|
||||||
|
"parameterCheckbox": "Опцияны қосу",
|
||||||
|
"pathToFfmpeg": "FFmpeg жол:",
|
||||||
|
"pathToFfplay": "FFplay жол:",
|
||||||
|
"pathToFfprobe": "FFprobe жол:",
|
||||||
|
"preset_fast": "fast («faster» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_faster": "faster («veryfast» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_medium": "medium («fast» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_placebo": "placebo (ұсынылмайды)",
|
||||||
|
"preset_slow": "slow («medium» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_slower": "slower («slow» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_superfast": "superfast («ultrafast» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_ultrafast": "ultrafast (жылдам, бірақ файлдың салмағы көп болады)",
|
||||||
|
"preset_veryfast": "veryfast («superfast» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"preset_veryslow": "veryslow («slower» қарағанда баяуырақ, бірақ файлдың салмағы аз болады)",
|
||||||
|
"programmLink": "Жобаның веб-сайты",
|
||||||
|
"programmVersion": "**Бағдарлама нұсқасы:** {{.Version}}",
|
||||||
|
"queue": "Кезек",
|
||||||
|
"save": "Сақтау",
|
||||||
|
"selectEncoder": "Кодировщик:",
|
||||||
|
"selectFFPathTitle": "FFmpeg және FFprobe жолын көрсетіңіз",
|
||||||
|
"selectFormat": "Файл кеңейтімі:",
|
||||||
|
"settings": "Параметрлер",
|
||||||
|
"testFF": "FFmpeg функционалдығы тексерілуде...",
|
||||||
|
"themesNameDark": "Қараңғы тақырып",
|
||||||
|
"themesNameDefault": "Әдепкі бойынша",
|
||||||
|
"themesNameLight": "Жеңіл тақырып",
|
||||||
|
"titleDownloadLink": "Сіз оны осы жерден жүктей аласыз",
|
||||||
|
"total": "Барлығы",
|
||||||
|
"unzipRun": "Орамнан шығарылуда...",
|
||||||
|
"waitingQueue": "Күту"
|
||||||
|
}
|
143
internal/resources/translations/app.ru.json
Normal file
143
internal/resources/translations/app.ru.json
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
{
|
||||||
|
"AlsoUsedProgram": "Также в программе используется:",
|
||||||
|
"about": "О программе",
|
||||||
|
"aboutText": "Простенький интерфейс для консольной утилиты FFmpeg. \nНо я не являюсь автором самой утилиты FFmpeg.",
|
||||||
|
"addedFilesTitle": "Добавленные файлы",
|
||||||
|
"autoClearAfterAddingToQueue": "Очищать после добавления в очередь",
|
||||||
|
"buttonDownloadFFmpeg": "Скачать автоматически FFmpeg",
|
||||||
|
"buttonForSelectedDirTitle": "Сохранить в папку:",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"changeFFPath": "FFmpeg, FFprobe и FFplay",
|
||||||
|
"changeLanguage": "Поменять язык",
|
||||||
|
"checkboxOverwriteOutputFilesTitle": "Разрешить перезаписать файл",
|
||||||
|
"choose": "выбрать",
|
||||||
|
"clearAll": "Очистить список",
|
||||||
|
"completedQueue": "Готово",
|
||||||
|
"converterVideoFilesSubmitTitle": "Конвертировать",
|
||||||
|
"converterVideoFilesTitle": "Конвертер видео, аудио и картинок",
|
||||||
|
"download": "Скачать",
|
||||||
|
"downloadFFmpegFromSite": "Будет скачано с сайта:",
|
||||||
|
"downloadRun": "Скачивается...",
|
||||||
|
"dragAndDropFiles": "перетащить файлы",
|
||||||
|
"encoderGroupAudio": "Аудио",
|
||||||
|
"encoderGroupImage": "Картинки",
|
||||||
|
"encoderGroupVideo": "Видео",
|
||||||
|
"encoder_apng": "APNG image",
|
||||||
|
"encoder_bmp": "BMP image",
|
||||||
|
"encoder_flv": "FLV",
|
||||||
|
"encoder_gif": "GIF image",
|
||||||
|
"encoder_h264_nvenc": "H.264 с поддержкой NVIDIA",
|
||||||
|
"encoder_libmp3lame": "libmp3lame MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libshine": "libshine MP3 (MPEG audio layer 3)",
|
||||||
|
"encoder_libtwolame": "libtwolame MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_libvpx": "libvpx VP8 (codec vp8)",
|
||||||
|
"encoder_libvpx-vp9": "libvpx VP9 (codec vp9)",
|
||||||
|
"encoder_libwebp": "libwebp WebP image",
|
||||||
|
"encoder_libwebp_anim": "libwebp_anim WebP image",
|
||||||
|
"encoder_libx264": "H.264 libx264",
|
||||||
|
"encoder_libx265": "H.265 libx265",
|
||||||
|
"encoder_libxvid": "libxvidcore MPEG-4 part 2",
|
||||||
|
"encoder_mjpeg": "MJPEG (Motion JPEG)",
|
||||||
|
"encoder_mp2": "MP2 (MPEG audio layer 2)",
|
||||||
|
"encoder_mp2fixed": "MP2 fixed point (MPEG audio layer 2)",
|
||||||
|
"encoder_mpeg1video": "MPEG-1",
|
||||||
|
"encoder_mpeg2video": "MPEG-2",
|
||||||
|
"encoder_mpeg4": "MPEG-4 part 2",
|
||||||
|
"encoder_msmpeg4": "MPEG-4 part 2 Microsoft variant version 3",
|
||||||
|
"encoder_msmpeg4v2": "MPEG-4 part 2 Microsoft variant version 2",
|
||||||
|
"encoder_msvideo1": "Microsoft Video-1",
|
||||||
|
"encoder_png": "PNG image",
|
||||||
|
"encoder_qtrle": "QuickTime Animation (RLE) video",
|
||||||
|
"encoder_sgi": "SGI image",
|
||||||
|
"encoder_tiff": "TIFF image",
|
||||||
|
"encoder_wmav1": "Windows Media Audio 1",
|
||||||
|
"encoder_wmav2": "Windows Media Audio 2",
|
||||||
|
"encoder_wmv1": "Windows Media Video 7",
|
||||||
|
"encoder_wmv2": "Windows Media Video 8",
|
||||||
|
"encoder_xbm": "XBM (X BitMap) image",
|
||||||
|
"error": "Произошла ошибка!",
|
||||||
|
"errorConverter": "не смогли отконвертировать видео",
|
||||||
|
"errorDragAndDropFile": "Не все файлы добавились",
|
||||||
|
"errorFFmpeg": "это не FFmpeg",
|
||||||
|
"errorFFmpegVersion": "Не смогли определить версию FFmpeg",
|
||||||
|
"errorFFplay": "это не FFplay",
|
||||||
|
"errorFFplayVersion": "Не смогли определить версию FFplay",
|
||||||
|
"errorFFprobe": "это не FFprobe",
|
||||||
|
"errorFFprobeVersion": "Не смогли определить версию FFprobe",
|
||||||
|
"errorNoFilesAddedForConversion": "Нет файлов для конвертации",
|
||||||
|
"errorQueue": "Ошибка",
|
||||||
|
"errorSelectedEncoder": "Конвертер не выбран",
|
||||||
|
"errorSelectedFolderSave": "Папка для сохранения не выбрана!",
|
||||||
|
"errorSelectedFormat": "Расширение файла не выбрана",
|
||||||
|
"exit": "Выход",
|
||||||
|
"ffmpegLGPL": "Это программное обеспечение использует библиотеки из проекта **FFmpeg** под **[LGPLv2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html)**.",
|
||||||
|
"ffmpegTrademark": "**FFmpeg** — торговая марка **[Fabrice Bellard](http://bellard.org/)** , создателя проекта **[FFmpeg](https://ffmpeg.org/about.html)**.",
|
||||||
|
"fileForConversionTitle": "Файл:",
|
||||||
|
"fileQueueTitle": "Очередь",
|
||||||
|
"formPreset": "Предустановка",
|
||||||
|
"gratitude": "Благодарность",
|
||||||
|
"gratitudeText": "Я искренне благодарю вас за неоценимую\n\rи своевременную помощь:",
|
||||||
|
"help": "Справка",
|
||||||
|
"helpFFplay": "Клавиши проигрывателя FFplay",
|
||||||
|
"helpFFplayActivateFrameStepMode": "Активировать покадровый режим.",
|
||||||
|
"helpFFplayCycleVideoFiltersOrShowModes": "Цикл видеофильтров или режимов показа.",
|
||||||
|
"helpFFplayDecreaseVolume": "Уменьшить громкость.",
|
||||||
|
"helpFFplayDescription": "Описание",
|
||||||
|
"helpFFplayDoubleClickLeftMouseButton": "двойной щелчок\nлевой кнопкой мыши",
|
||||||
|
"helpFFplayIncreaseVolume": "Увеличить громкость.",
|
||||||
|
"helpFFplayKeyDown": "вниз",
|
||||||
|
"helpFFplayKeyHoldS": "держать S",
|
||||||
|
"helpFFplayKeyLeft": "лево",
|
||||||
|
"helpFFplayKeyRight": "право",
|
||||||
|
"helpFFplayKeySpace": "SPACE (пробел)",
|
||||||
|
"helpFFplayKeyUp": "вверх",
|
||||||
|
"helpFFplayKeys": "Клавиши",
|
||||||
|
"helpFFplayPause": "Поставить на паузу или продолжить проигрывать.",
|
||||||
|
"helpFFplayQuit": "Закрыть проигрыватель.",
|
||||||
|
"helpFFplaySeekBForward10Minutes": "Перемотать вперёд на 10 минут.",
|
||||||
|
"helpFFplaySeekBForward1Minute": "Перемотать вперёд на 1 минуту.",
|
||||||
|
"helpFFplaySeekBackward10Minutes": "Перемотать назад на 10 минут.",
|
||||||
|
"helpFFplaySeekBackward10Seconds": "Перемотать назад на 10 секунд.",
|
||||||
|
"helpFFplaySeekBackward1Minute": "Перемотать назад на 1 минуту.",
|
||||||
|
"helpFFplaySeekForward10Seconds": "Перемотать вперёд на 10 секунд.",
|
||||||
|
"helpFFplayToggleFullScreen": "Переключиться на полный экран или выйти с полного экрана.",
|
||||||
|
"helpFFplayToggleMute": "Отключить звук или включить звук.",
|
||||||
|
"inProgressQueue": "Выполняется",
|
||||||
|
"languageSelectionFormHead": "Переключить язык",
|
||||||
|
"languageSelectionHead": "Выберите язык",
|
||||||
|
"licenseLink": "Сведения о лицензии",
|
||||||
|
"licenseLinkOther": "Лицензии от других продуктов, которые используются в программе",
|
||||||
|
"menuSettingsLanguage": "Язык",
|
||||||
|
"menuSettingsTheme": "Тема",
|
||||||
|
"or": "или",
|
||||||
|
"parameterCheckbox": "Включить параметр",
|
||||||
|
"pathToFfmpeg": "Путь к FFmpeg:",
|
||||||
|
"pathToFfplay": "Путь к FFplay:",
|
||||||
|
"pathToFfprobe": "Путь к FFprobe:",
|
||||||
|
"preset_fast": "fast (медленней чем faster, но будет файл и меньше весить)",
|
||||||
|
"preset_faster": "faster (медленней чем veryfast, но будет файл и меньше весить)",
|
||||||
|
"preset_medium": "medium (медленней чем fast, но будет файл и меньше весить)",
|
||||||
|
"preset_placebo": "placebo (не рекомендуется)",
|
||||||
|
"preset_slow": "slow (медленней чем medium, но будет файл и меньше весить)",
|
||||||
|
"preset_slower": "slower (медленней чем slow, но будет файл и меньше весить)",
|
||||||
|
"preset_superfast": "superfast (медленней чем ultrafast, но будет файл и меньше весить)",
|
||||||
|
"preset_ultrafast": "ultrafast (быстро, но файл будет много весить)",
|
||||||
|
"preset_veryfast": "veryfast (медленней чем superfast, но будет файл и меньше весить)",
|
||||||
|
"preset_veryslow": "veryslow (медленней чем slower, но будет файл и меньше весить)",
|
||||||
|
"programmLink": "Сайт проекта",
|
||||||
|
"programmVersion": "**Версия программы:** {{.Version}}",
|
||||||
|
"queue": "Очередь",
|
||||||
|
"save": "Сохранить",
|
||||||
|
"selectEncoder": "Кодировщик:",
|
||||||
|
"selectFFPathTitle": "Укажите путь к FFmpeg и к FFprobe",
|
||||||
|
"selectFormat": "Расширение файла:",
|
||||||
|
"settings": "Настройки",
|
||||||
|
"testFF": "Проверка FFmpeg на работоспособность...",
|
||||||
|
"themesNameDark": "Тёмная",
|
||||||
|
"themesNameDefault": "По умолчанию",
|
||||||
|
"themesNameLight": "Светлая",
|
||||||
|
"titleDownloadLink": "Скачать можно от сюда",
|
||||||
|
"total": "Всего",
|
||||||
|
"unzipRun": "Распаковывается...",
|
||||||
|
"waitingQueue": "В очереди"
|
||||||
|
}
|
45
internal/resources/translations/base.en.json
Normal file
45
internal/resources/translations/base.en.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"Advanced": "Advanced",
|
||||||
|
"Cancel": "Cancel",
|
||||||
|
"Confirm": "Confirm",
|
||||||
|
"Copy": "Copy",
|
||||||
|
"Create Folder": "Create Folder",
|
||||||
|
"Cut": "Cut",
|
||||||
|
"Enter filename": "Enter filename",
|
||||||
|
"Error": "Error",
|
||||||
|
"Favourites": "Favourites",
|
||||||
|
"File": "File",
|
||||||
|
"Folder": "Folder",
|
||||||
|
"New Folder": "New Folder",
|
||||||
|
"No": "No",
|
||||||
|
"OK": "OK",
|
||||||
|
"Open": "Open",
|
||||||
|
"Paste": "Paste",
|
||||||
|
"Quit": "Quit",
|
||||||
|
"Redo": "Redo",
|
||||||
|
"Save": "Save",
|
||||||
|
"Select all": "Select all",
|
||||||
|
"Show Hidden Files": "Show Hidden Files",
|
||||||
|
"Undo": "Undo",
|
||||||
|
"Yes": "Yes",
|
||||||
|
"file.name": {
|
||||||
|
"other": "Name"
|
||||||
|
},
|
||||||
|
"file.parent": {
|
||||||
|
"other": "Parent"
|
||||||
|
},
|
||||||
|
"friday": "Friday",
|
||||||
|
"friday.short": "Fri",
|
||||||
|
"monday": "Monday",
|
||||||
|
"monday.short": "Mon",
|
||||||
|
"saturday": "Saturday",
|
||||||
|
"saturday.short": "Sat",
|
||||||
|
"sunday": "Sunday",
|
||||||
|
"sunday.short": "Sun",
|
||||||
|
"thursday": "Thursday",
|
||||||
|
"thursday.short": "Thu",
|
||||||
|
"tuesday": "Tuesday",
|
||||||
|
"tuesday.short": "Tue",
|
||||||
|
"wednesday": "Wednesday",
|
||||||
|
"wednesday.short": "Wed"
|
||||||
|
}
|
45
internal/resources/translations/base.kk.json
Normal file
45
internal/resources/translations/base.kk.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"Advanced": "Кеңейтілген",
|
||||||
|
"Cancel": "Бас тарту",
|
||||||
|
"Confirm": "Растау",
|
||||||
|
"Copy": "Көшіру",
|
||||||
|
"Create Folder": "Қалта жасау",
|
||||||
|
"Cut": "Кесу",
|
||||||
|
"Enter filename": "Файл атауын енгізіңіз",
|
||||||
|
"Error": "Қате",
|
||||||
|
"Favourites": "Таңдаулылар",
|
||||||
|
"File": "Файл",
|
||||||
|
"Folder": "Қалта",
|
||||||
|
"New Folder": "Жаңа қалта",
|
||||||
|
"No": "Жоқ",
|
||||||
|
"OK": "ОК",
|
||||||
|
"Open": "Ашу",
|
||||||
|
"Paste": "Кірістіру",
|
||||||
|
"Quit": "Шығу",
|
||||||
|
"Redo": "Қайталау",
|
||||||
|
"Save": "Сақтау",
|
||||||
|
"Select all": "Барлығын таңдаңыз",
|
||||||
|
"Show Hidden Files": "Жасырын файлдарды көрсету",
|
||||||
|
"Undo": "Бас тарту",
|
||||||
|
"Yes": "Иә",
|
||||||
|
"file.name": {
|
||||||
|
"other": "Аты"
|
||||||
|
},
|
||||||
|
"file.parent": {
|
||||||
|
"other": "Жоғары"
|
||||||
|
},
|
||||||
|
"friday": "Жұма",
|
||||||
|
"friday.short": "Жұ",
|
||||||
|
"monday": "Дүйсенбі",
|
||||||
|
"monday.short": "Дү",
|
||||||
|
"saturday": "Сенбі",
|
||||||
|
"saturday.short": "Сен",
|
||||||
|
"sunday": "Жексенбі",
|
||||||
|
"sunday.short": "Же",
|
||||||
|
"thursday": "Сейсенбі",
|
||||||
|
"thursday.short": "Се",
|
||||||
|
"tuesday": "Бейсенбі",
|
||||||
|
"tuesday.short": "Бе",
|
||||||
|
"wednesday": "Сәрсенбі",
|
||||||
|
"wednesday.short": "Сә"
|
||||||
|
}
|
45
internal/resources/translations/base.ru.json
Normal file
45
internal/resources/translations/base.ru.json
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"Advanced": "Расширенные",
|
||||||
|
"Cancel": "Отмена",
|
||||||
|
"Confirm": "Подтвердить",
|
||||||
|
"Copy": "Копировать",
|
||||||
|
"Create Folder": "Создать папку",
|
||||||
|
"Cut": "Вырезать",
|
||||||
|
"Enter filename": "Введите имя файла",
|
||||||
|
"Error": "Ошибка",
|
||||||
|
"Favourites": "Избранное",
|
||||||
|
"File": "Файл",
|
||||||
|
"Folder": "Папка",
|
||||||
|
"New Folder": "Новая папка",
|
||||||
|
"No": "Нет",
|
||||||
|
"OK": "ОК",
|
||||||
|
"Open": "Открыть",
|
||||||
|
"Paste": "Вставить",
|
||||||
|
"Quit": "Выйти",
|
||||||
|
"Redo": "Повторить",
|
||||||
|
"Save": "Сохранить",
|
||||||
|
"Select all": "Выбрать всё",
|
||||||
|
"Show Hidden Files": "Показать скрытые файлы",
|
||||||
|
"Undo": "Отменить",
|
||||||
|
"Yes": "Да",
|
||||||
|
"file.name": {
|
||||||
|
"other": "Имя"
|
||||||
|
},
|
||||||
|
"file.parent": {
|
||||||
|
"other": "Вверх"
|
||||||
|
},
|
||||||
|
"friday": "Пятница",
|
||||||
|
"friday.short": "Пт",
|
||||||
|
"monday": "Понедельник",
|
||||||
|
"monday.short": "Пн",
|
||||||
|
"saturday": "Суббота",
|
||||||
|
"saturday.short": "Сб",
|
||||||
|
"sunday": "Воскресенье",
|
||||||
|
"sunday.short": "Вс",
|
||||||
|
"thursday": "Вторник",
|
||||||
|
"thursday.short": "Вт",
|
||||||
|
"tuesday": "Четверг",
|
||||||
|
"tuesday.short": "Чт",
|
||||||
|
"wednesday": "Среда",
|
||||||
|
"wednesday.short": "Ср"
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user