feat: ConvertGUI v2.0 (Wails + preview/trim + NSIS + Gitea CI)
Build Windows Installer / build (push) Successful in 4m11s
Build Windows Installer / build (push) Successful in 4m11s
This commit is contained in:
40 files changed
+6084
-266
No files matched your search
@@ -1,187 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||
"github.com/wailsapp/wails/v2/pkg/options/windows"
|
||||
)
|
||||
|
||||
const DEFAULT_PRESET = "slow"
|
||||
const DEFAULT_CRF = "20"
|
||||
// Version is injected at build time via -ldflags "-X main.Version=..."
|
||||
var Version = "2.0.0-dev"
|
||||
|
||||
func scanArgFromConsole(text string, v *string) error {
|
||||
fmt.Print(text)
|
||||
if _, err := fmt.Scanln(v); err != nil && err.Error() == "EOF" {
|
||||
return err
|
||||
//go:embed all:frontend/dist
|
||||
var assets embed.FS
|
||||
|
||||
func parseInitialFile(args []string) string {
|
||||
fs := flag.NewFlagSet("convert", flag.ContinueOnError)
|
||||
var input string
|
||||
var debug bool
|
||||
fs.StringVar(&input, "i", "", "input video path")
|
||||
fs.BoolVar(&debug, "debug", false, "debug flag (ignored in GUI)")
|
||||
_ = fs.Parse(args)
|
||||
if input != "" {
|
||||
return input
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pressEnterToExit(code int) {
|
||||
fmt.Print("\npress enter to exit... ")
|
||||
_, _ = fmt.Scanln()
|
||||
os.Exit(code)
|
||||
if fs.NArg() > 0 {
|
||||
return fs.Arg(0)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
var debug bool
|
||||
var vfArgs []string
|
||||
var audioFilters []string
|
||||
var videoFilters []string
|
||||
var inputVideo, ss, to, an, crf, preset, mergeAudioStreams, speedUp string
|
||||
initialFile := parseInitialFile(os.Args[1:])
|
||||
app := NewApp(initialFile)
|
||||
|
||||
ffmpegExecutable := "ffmpeg"
|
||||
ffmpegArgs := append(make([]string, 0, 30), "-hide_banner")
|
||||
inputArgs := []string{
|
||||
"-hwaccel", "nvdec",
|
||||
"-threads", "1",
|
||||
}
|
||||
postArgs := []string{
|
||||
"-c:v", "h264",
|
||||
"-profile:v", "high",
|
||||
"-pix_fmt", "yuv420p",
|
||||
"-tune", "film",
|
||||
"-movflags", "+faststart",
|
||||
"-r", "60",
|
||||
}
|
||||
|
||||
flag.StringVar(&inputVideo, "i", "", "input video path")
|
||||
flag.BoolVar(&debug, "debug", false, "debug mode (default params)")
|
||||
flag.Parse()
|
||||
|
||||
// check video exists
|
||||
if _, err := os.Stat(inputVideo); err != nil {
|
||||
fmt.Println(err)
|
||||
pressEnterToExit(1)
|
||||
}
|
||||
|
||||
stat, err := ffprobe(inputVideo)
|
||||
err := wails.Run(&options.App{
|
||||
Title: "ConvertGUI",
|
||||
Width: 1240,
|
||||
Height: 840,
|
||||
MinWidth: 980,
|
||||
MinHeight: 680,
|
||||
AssetServer: &assetserver.Options{
|
||||
Assets: assets,
|
||||
},
|
||||
BackgroundColour: &options.RGBA{R: 13, G: 17, B: 23, A: 1},
|
||||
OnStartup: app.startup,
|
||||
OnShutdown: app.shutdown,
|
||||
DragAndDrop: &options.DragAndDrop{
|
||||
EnableFileDrop: true,
|
||||
DisableWebViewDrop: false,
|
||||
},
|
||||
Windows: &windows.Options{
|
||||
WebviewIsTransparent: false,
|
||||
WindowIsTranslucent: false,
|
||||
Theme: windows.Dark,
|
||||
},
|
||||
Bind: []interface{}{
|
||||
app,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !debug {
|
||||
err = func() error {
|
||||
if err = scanArgFromConsole("ss > ", &ss); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole("to > ", &to); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole("an > ", &an); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole(fmt.Sprintf("crf [%v] > ", DEFAULT_CRF), &crf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole("speed up > ", &speedUp); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole(fmt.Sprintf("preset [%v] > ", DEFAULT_PRESET), &preset); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = scanArgFromConsole("merge audio streams > ", &mergeAudioStreams); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
if err != nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range []*string{&ss, &to, &an, &crf, &preset, &mergeAudioStreams, &speedUp} {
|
||||
*v = strings.ToLower(strings.TrimSpace(*v))
|
||||
}
|
||||
|
||||
if len(ss) != 0 {
|
||||
inputArgs = append(inputArgs, "-ss", ss)
|
||||
}
|
||||
|
||||
if len(to) != 0 {
|
||||
inputArgs = append(inputArgs, "-to", to)
|
||||
}
|
||||
|
||||
if len(an) != 0 {
|
||||
postArgs = append(postArgs, "-an")
|
||||
} else {
|
||||
audioFilters = append(audioFilters, "amix=inputs=2:normalize=0")
|
||||
}
|
||||
|
||||
if len(crf) == 0 {
|
||||
crf = DEFAULT_CRF
|
||||
}
|
||||
|
||||
if len(preset) == 0 {
|
||||
preset = DEFAULT_PRESET
|
||||
}
|
||||
|
||||
postArgs = append(postArgs, "-preset", preset)
|
||||
postArgs = append(postArgs, "-crf", crf)
|
||||
|
||||
// speed up video and audio(?)
|
||||
if len(speedUp) != 0 {
|
||||
videoFilters = append(videoFilters, fmt.Sprintf("setpts=1/%s*PTS", speedUp))
|
||||
if len(an) == 0 {
|
||||
audioFilters = append(audioFilters, fmt.Sprintf("atempo=%s", speedUp))
|
||||
}
|
||||
}
|
||||
|
||||
if len(videoFilters) != 0 {
|
||||
vfArgs = append(vfArgs, "[0:v:0]"+strings.Join(videoFilters, ",")+"[v]")
|
||||
postArgs = append(postArgs, "-map", "[v]")
|
||||
} else {
|
||||
postArgs = append(postArgs, "-map", "0:v:0")
|
||||
}
|
||||
|
||||
if len(audioFilters) != 0 {
|
||||
vfArgs = append(vfArgs, "[0:a]"+strings.Join(audioFilters, ",")+"[a]")
|
||||
postArgs = append(postArgs, "-map", "[a]")
|
||||
} else {
|
||||
postArgs = append(postArgs, "-map", "0:a")
|
||||
}
|
||||
|
||||
// merge filter complex args
|
||||
if len(vfArgs) != 0 {
|
||||
postArgs = append(postArgs, "-filter_complex", strings.Join(vfArgs, ";"))
|
||||
}
|
||||
|
||||
// out file name
|
||||
outDir, _ := filepath.Split(inputVideo)
|
||||
outFile := filepath.Join(outDir, strconv.FormatInt(time.Now().Unix(), 10)+".mp4")
|
||||
|
||||
// merge args to one slice
|
||||
ffmpegArgs = append(ffmpegArgs, inputArgs...)
|
||||
ffmpegArgs = append(ffmpegArgs, "-i", inputVideo)
|
||||
ffmpegArgs = append(ffmpegArgs, postArgs...)
|
||||
ffmpegArgs = append(ffmpegArgs, outFile)
|
||||
|
||||
fmt.Printf("
|
||||
running %v: %v
|
||||
|
||||
", ffmpegExecutable, strings.Join(ffmpegArgs, " "))
|
||||
|
||||
proc := exec.Command(ffmpegExecutable, ffmpegArgs...)
|
||||
proc.Stderr = os.Stderr
|
||||
err = proc.Start()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
pressEnterToExit(1)
|
||||
}
|
||||
err = proc.Wait()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
pressEnterToExit(1)
|
||||
}
|
||||
if proc.ProcessState.ExitCode() != 0 {
|
||||
fmt.Println(err)
|
||||
pressEnterToExit(1)
|
||||
println("Error:", err.Error())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user