mirror of
https://github.com/IllusionMan1212/ffui.git
synced 2026-10-24 02:12:35 +00:00
feat: add button to print compiled ffmpeg command and exit
This commit is contained in:
@@ -4,11 +4,13 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/progress"
|
||||
"github.com/charmbracelet/bubbles/spinner"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
ffmpeg "github.com/u2takey/ffmpeg-go"
|
||||
)
|
||||
|
||||
type Screen int
|
||||
@@ -38,6 +40,7 @@ type model struct {
|
||||
Config map[int]Config
|
||||
FocusIndex int
|
||||
ParsedConfig ParsedConfig
|
||||
DryRun bool
|
||||
ErrQuit bool
|
||||
ErrQuitMessage string
|
||||
}
|
||||
@@ -99,7 +102,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case "enter", " ":
|
||||
// parse config and switch to main screen if we're focused on the start button
|
||||
if m.FocusIndex == len(Configs) {
|
||||
return m, m.parseConfig
|
||||
return m, m.parseConfig(false)
|
||||
}
|
||||
// parse config, print it and exit
|
||||
if m.FocusIndex == len(Configs)+1 {
|
||||
return m, m.parseConfig(true)
|
||||
}
|
||||
case "tab", "shift+tab", "up", "down":
|
||||
if key == "up" || key == "shift+tab" {
|
||||
@@ -108,10 +115,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.FocusIndex++
|
||||
}
|
||||
|
||||
if m.FocusIndex >= len(Configs)+1 {
|
||||
if m.FocusIndex >= len(Configs)+2 {
|
||||
m.FocusIndex = 0
|
||||
} else if m.FocusIndex < 0 {
|
||||
m.FocusIndex = len(Configs)
|
||||
m.FocusIndex = len(Configs) + 1
|
||||
}
|
||||
case "left", "right":
|
||||
if cfg, ok := m.Config[m.FocusIndex]; ok {
|
||||
@@ -130,6 +137,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.Config[m.FocusIndex] = cfg
|
||||
}
|
||||
}
|
||||
case quitMsg:
|
||||
m.Quitting = true
|
||||
return m, tea.Quit
|
||||
case parsedCfgMsg:
|
||||
m.Screen = Main
|
||||
m.ParsedConfig = msg.parsedConfig
|
||||
@@ -141,6 +151,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.FileCount = msg.fileCount
|
||||
m.Files = msg.files
|
||||
|
||||
if m.DryRun {
|
||||
return m, gracefullyQuit
|
||||
}
|
||||
|
||||
return m, encodeVideo
|
||||
case encodeVideoMsg:
|
||||
m.CurrentFileName = filepath.Base(m.Files[len(m.Files)-1])
|
||||
@@ -160,7 +174,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
m.Files = m.Files[:len(m.Files)-1]
|
||||
|
||||
if len(m.Files) == 0 {
|
||||
return m, m.gracefullyQuit
|
||||
return m, gracefullyQuit
|
||||
}
|
||||
|
||||
return m, encodeVideo
|
||||
@@ -217,9 +231,15 @@ func CfgScreenView(m model) string {
|
||||
}
|
||||
|
||||
if m.FocusIndex == len(Configs) {
|
||||
view += FocusedButton
|
||||
view += FocusedStartButton
|
||||
} else {
|
||||
view += BlurredButton
|
||||
view += BlurredStartButton
|
||||
}
|
||||
|
||||
if m.FocusIndex == len(Configs)+1 {
|
||||
view += FocusedDryRunButton
|
||||
} else {
|
||||
view += BlurredDryRunButton
|
||||
}
|
||||
|
||||
view += "\n"
|
||||
@@ -252,8 +272,26 @@ func MainScreenView(m model) string {
|
||||
|
||||
func (m model) View() string {
|
||||
if m.Quitting {
|
||||
if m.DryRun {
|
||||
fullFilePath := m.Files[len(m.Files)-1]
|
||||
fileName := filepath.Base(fullFilePath)
|
||||
extensionIndex := strings.LastIndex(fileName, ".")
|
||||
extension := fileName[extensionIndex:]
|
||||
newFullFilePath := "./test-out" + extension
|
||||
|
||||
cli := ffmpeg.Input(fullFilePath).Output(newFullFilePath, ffmpeg.KwArgs{
|
||||
"c:v": m.ParsedConfig.VideoEncoder,
|
||||
"crf": m.ParsedConfig.CRF,
|
||||
"preset": m.ParsedConfig.Preset,
|
||||
"c:a": m.ParsedConfig.AudioEncoder,
|
||||
"b:a": "128k"}).
|
||||
Compile()
|
||||
|
||||
return fmt.Sprintf("%s %s\n", checkmark, strings.Join(cli.Args, " "))
|
||||
} else {
|
||||
return fmt.Sprintf("%s %d/%d files encoded\n", checkmark, m.FileCount-len(m.Files), m.FileCount)
|
||||
}
|
||||
}
|
||||
|
||||
if m.ErrQuit {
|
||||
return fmt.Sprintf("%s %s\n", x, m.ErrQuitMessage)
|
||||
|
||||
@@ -66,7 +66,7 @@ func encodeVideo() tea.Msg {
|
||||
|
||||
type quitMsg struct{}
|
||||
|
||||
func (m model) gracefullyQuit() tea.Msg {
|
||||
func gracefullyQuit() tea.Msg {
|
||||
return quitMsg{}
|
||||
}
|
||||
|
||||
@@ -78,9 +78,13 @@ func initCfg() tea.Msg {
|
||||
|
||||
type parsedCfgMsg struct {
|
||||
parsedConfig ParsedConfig
|
||||
dryRun bool
|
||||
}
|
||||
|
||||
func (m *model) parseConfig() tea.Msg {
|
||||
func (m *model) parseConfig(dryRun bool) tea.Cmd {
|
||||
m.DryRun = dryRun
|
||||
|
||||
return func() tea.Msg {
|
||||
vEncoder := find(m.Config, "Video Encoder")
|
||||
aEncoder := find(m.Config, "Audio Encoder")
|
||||
preset := find(m.Config, "Preset (libx264 & libx265 only)")
|
||||
@@ -95,6 +99,8 @@ func (m *model) parseConfig() tea.Msg {
|
||||
Preset: preset.Opts[preset.FocusedOption],
|
||||
CRF: crf.Opts[crf.FocusedOption],
|
||||
},
|
||||
dryRun: dryRun,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,5 +7,5 @@ require (
|
||||
github.com/charmbracelet/bubbletea v0.20.0
|
||||
github.com/charmbracelet/lipgloss v0.5.0
|
||||
github.com/gabriel-vasile/mimetype v1.4.0
|
||||
github.com/u2takey/ffmpeg-go v0.4.1
|
||||
github.com/u2takey/ffmpeg-go v0.5.0
|
||||
)
|
||||
|
||||
@@ -73,6 +73,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/u2takey/ffmpeg-go v0.4.1 h1:l5ClIwL3N2LaH1zF3xivb3kP2HW95eyG5xhHE1JdZ9Y=
|
||||
github.com/u2takey/ffmpeg-go v0.4.1/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc=
|
||||
github.com/u2takey/ffmpeg-go v0.5.0 h1:r7d86XuL7uLWJ5mzSeQ03uvjfIhiJYvsRAJFCW4uklU=
|
||||
github.com/u2takey/ffmpeg-go v0.5.0/go.mod h1:ruZWkvC1FEiUNjmROowOAps3ZcWxEiOpFoHCvk97kGc=
|
||||
github.com/u2takey/go-utils v0.3.1 h1:TaQTgmEZZeDHQFYfd+AdUT1cT4QJgJn/XVPELhHw4ys=
|
||||
github.com/u2takey/go-utils v0.3.1/go.mod h1:6e+v5vEZ/6gu12w/DC2ixZdZtCrNokVxD0JUklcqdCs=
|
||||
gocv.io/x/gocv v0.25.0/go.mod h1:Rar2PS6DV+T4FL+PM535EImD/h13hGVaHhnCu1xarBs=
|
||||
|
||||
@@ -79,8 +79,11 @@ func encode(fullFilePath string, fileName string, teaP *tea.Program, cfg ParsedC
|
||||
}
|
||||
}
|
||||
|
||||
err = ffmpeg.Input(fullFilePath).
|
||||
Output(newFileFullPath, ffmpeg.KwArgs{
|
||||
quotedFilePath := fmt.Sprintf("\"%s\"", fullFilePath)
|
||||
quotedNewFilePath := fmt.Sprintf("\"%s\"", newFileFullPath)
|
||||
|
||||
err = ffmpeg.Input(quotedFilePath).
|
||||
Output(quotedNewFilePath, ffmpeg.KwArgs{
|
||||
"c:v": cfg.VideoEncoder,
|
||||
"crf": cfg.CRF,
|
||||
"preset": cfg.Preset,
|
||||
|
||||
@@ -32,7 +32,7 @@ var (
|
||||
FocusedOption = lipgloss.NewStyle().
|
||||
Foreground(SecondaryColor)
|
||||
|
||||
FocusedButton = lipgloss.NewStyle().
|
||||
FocusedStartButton = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder()).
|
||||
BorderForeground(AccentColor).
|
||||
Foreground(AccentColor).
|
||||
@@ -41,7 +41,7 @@ var (
|
||||
Align(lipgloss.Center).
|
||||
Bold(true).
|
||||
Render("Start Encoding!")
|
||||
BlurredButton = lipgloss.NewStyle().
|
||||
BlurredStartButton = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder()).
|
||||
BorderForeground(PrimaryColor).
|
||||
Foreground(PrimaryColor).
|
||||
@@ -49,4 +49,22 @@ var (
|
||||
Padding(0, 2).
|
||||
Align(lipgloss.Center).
|
||||
Render("Start Encoding!")
|
||||
|
||||
FocusedDryRunButton = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder()).
|
||||
BorderForeground(AccentColor).
|
||||
Foreground(AccentColor).
|
||||
MarginTop(1).
|
||||
Padding(0, 2).
|
||||
Align(lipgloss.Center).
|
||||
Bold(true).
|
||||
Render("Print FFmpeg command and exit")
|
||||
BlurredDryRunButton = lipgloss.NewStyle().
|
||||
Border(lipgloss.NormalBorder()).
|
||||
BorderForeground(PrimaryColor).
|
||||
Foreground(PrimaryColor).
|
||||
MarginTop(1).
|
||||
Padding(0, 2).
|
||||
Align(lipgloss.Center).
|
||||
Render("Print FFmpeg command and exit")
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user