94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
// VibEdit is a small video cutter: it splits clips out of source videos and
|
|
// joins them back together using ffmpeg. The UI is a local web page served by
|
|
// this program and opened in an Edge/Chrome app window.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const appName = "VibEdit"
|
|
|
|
var version = "1.0.0"
|
|
|
|
func main() {
|
|
addr := flag.String("addr", "127.0.0.1:0", "address to listen on")
|
|
noBrowser := flag.Bool("no-browser", false, "do not open the editor window automatically")
|
|
defaultBrowser := flag.Bool("default-browser", false, "open in the default web browser instead of an Edge/Chrome app window")
|
|
ffmpegPath := flag.String("ffmpeg", "", "path to ffmpeg (default: next to this program, then PATH)")
|
|
ffprobePath := flag.String("ffprobe", "", "path to ffprobe (default: next to this program, then PATH)")
|
|
keepAlive := flag.Bool("keep-alive", false, "keep running after the editor window is closed")
|
|
flag.Parse()
|
|
|
|
log.SetFlags(log.Ltime)
|
|
fmt.Printf("%s %s - simple ffmpeg video cutter\n\n", appName, version)
|
|
|
|
app := newApp(*ffmpegPath, *ffprobePath, *keepAlive)
|
|
if !app.tools.OK() {
|
|
fmt.Println("WARNING: ffmpeg/ffprobe not found.")
|
|
fmt.Println(" Put ffmpeg" + exeSuffix + " and ffprobe" + exeSuffix + " in the same folder as this program")
|
|
fmt.Println(" (or on your PATH). Windows builds: https://www.gyan.dev/ffmpeg/builds/")
|
|
fmt.Println()
|
|
} else {
|
|
fmt.Printf("ffmpeg: %s\nffprobe: %s\n\n", app.tools.FFmpeg, app.tools.FFprobe)
|
|
}
|
|
|
|
ln, err := net.Listen("tcp", *addr)
|
|
if err != nil {
|
|
fatal("Could not start the local web server: %v", err)
|
|
}
|
|
tcp := ln.Addr().(*net.TCPAddr)
|
|
host := tcp.IP.String()
|
|
if tcp.IP.IsUnspecified() {
|
|
host = "127.0.0.1"
|
|
}
|
|
hostPort := net.JoinHostPort(host, fmt.Sprint(tcp.Port))
|
|
app.configureHost(tcp)
|
|
url := fmt.Sprintf("http://%s/?t=%s", hostPort, app.token)
|
|
|
|
fmt.Println("Editor address (open this if no window appears):")
|
|
fmt.Println(" " + url)
|
|
fmt.Println()
|
|
fmt.Println("Close the editor window or this console to quit.")
|
|
fmt.Println()
|
|
|
|
if !*noBrowser {
|
|
go func() {
|
|
if err := openBrowser(url, *defaultBrowser); err != nil {
|
|
log.Printf("could not open a browser: %v", err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
sig := make(chan os.Signal, 1)
|
|
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
|
|
go func() {
|
|
<-sig
|
|
app.requestQuit("interrupted")
|
|
}()
|
|
|
|
srv := &http.Server{Handler: app, ReadHeaderTimeout: 10 * time.Second}
|
|
go func() {
|
|
<-app.quit
|
|
srv.Close()
|
|
}()
|
|
if err := srv.Serve(ln); err != nil && err != http.ErrServerClosed {
|
|
fatal("Web server stopped: %v", err)
|
|
}
|
|
app.shutdown()
|
|
}
|
|
|
|
func fatal(format string, args ...any) {
|
|
fmt.Fprintf(os.Stderr, "\nERROR: "+format+"\n", args...)
|
|
waitBeforeExit()
|
|
os.Exit(1)
|
|
}
|