Files
ffui/main.go
T

156 lines
3.7 KiB
Go

package main
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
tea "github.com/charmbracelet/bubbletea"
"github.com/gabriel-vasile/mimetype"
)
func main() {
if len(os.Args) < 2 {
log.Fatal("No directory or file provided.")
}
path := os.Args[1]
if path == "" {
log.Fatal("No directory or file provided.")
}
absolutePath, err := filepath.Abs(path)
if err != nil {
log.Fatal(err)
}
fileInfo, err := os.Stat(absolutePath)
if err != nil {
log.Fatal(err)
}
ffui := initialModel(fileInfo, absolutePath)
p := tea.NewProgram(ffui, tea.WithAltScreen())
ffui.Program = p
f, err := tea.LogToFile("ffui.log", "ffui")
defer f.Close()
if err != nil {
log.Fatal(err)
}
final, err := p.Run()
if err != nil {
fmt.Println(err)
log.Fatal(err)
}
finalModel, _ := final.(Model)
if finalModel.DryRun {
for _, file := range finalModel.Files {
parentDir := filepath.Dir(file.Path)
fileName := filepath.Base(file.Path)
extensionIndex := strings.LastIndex(fileName, ".")
newFileName := fileName[:extensionIndex]
extension := fileName[extensionIndex:]
outFileFullPath := filepath.Join(parentDir, newFileName+fmt.Sprintf("_[%s]_[%s]", finalModel.ParsedConfig.VideoEncoder, finalModel.ParsedConfig.AudioEncoder)+extension)
cmd := exec.Command("ffmpeg", buildFFmpegCmdArgs(file.Path, outFileFullPath, finalModel.ParsedConfig)...)
fmt.Println(fmt.Sprintf("%s %s", Checkmark, cmd.String()))
}
}
}
func buildFFmpegCmdArgs(fullFilePath string, outFullFilePath string, cfg ParsedConfig, additionalArgs ...string) []string {
args := make([]string, 0, 10)
// Input file
args = append(args, "-i")
args = append(args, fullFilePath)
// Encoding parameters
args = append(args, "-c:v")
args = append(args, cfg.VideoEncoder)
switch cfg.VideoEncoder {
case "copy":
// No options
case "libx264", "libx265":
args = append(args, "-crf")
args = append(args, cfg.CRF)
args = append(args, "-preset")
args = append(args, cfg.Preset)
case "libvpx-vp9":
args = append(args, "-crf")
args = append(args, cfg.CRF)
case "librav1e":
// No options
case "libsvtav1":
args = append(args, "-crf")
args = append(args, cfg.CRF)
// TODO: preset is a number for this encoder (-2 to 13)
}
switch cfg.AudioEncoder {
case "None":
args = append(args, "-an")
case "copy", "aac", "libopus":
args = append(args, "-c:a")
args = append(args, cfg.AudioEncoder)
}
args = append(args, additionalArgs...)
// Output file
args = append(args, outFullFilePath)
return args
}
func encode(file File, fileName string, teaP *tea.Program, cfg ParsedConfig) {
mType, err := mimetype.DetectFile(file.Path)
if err != nil {
log.Fatal(err)
}
if !strings.HasPrefix(mType.String(), "video/") {
log.Fatalf("%s is not a valid video file\n", fileName)
}
parentDir := filepath.Dir(file.Path)
extensionIndex := strings.LastIndex(fileName, ".")
newFileName := fileName[:extensionIndex]
extension := fileName[extensionIndex:]
newFileFullPath := filepath.Join(parentDir, newFileName+fmt.Sprintf("_[%s]_[%s]", cfg.VideoEncoder, cfg.AudioEncoder)+extension)
if _, err := os.Stat(newFileFullPath); err == nil {
if cfg.IgnoreConflictingName {
log.Printf("Skipping \"%s\" because it already exists with the exact same encodings (crf and preset might be different though)", newFileFullPath)
teaP.Send(finishedEncodingVideo{})
return
} else {
os.Remove(newFileFullPath)
}
}
cmdArgs := buildFFmpegCmdArgs(file.Path, newFileFullPath, cfg, "-progress", "unix://"+getProgressSocket(file.Path, teaP))
cmd := exec.Command("ffmpeg", cmdArgs...)
teaP.Send(ffmpegProcessStart{cmd})
err = cmd.Run()
if err != nil {
teaP.Send(errQuitMsg{msg: fmt.Sprintf("FFmpeg exited with error code: %s\n\nError: %v", err, cmd.Stderr)})
}
}