Audio player
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
3.5 KiB

package main
import (
"flag"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path/filepath"
"runtime/pprof"
"strings"
"syscall"
"time"
)
const (
volumeBase = 2
versionInfo = `ditty - Audio player - v0.0.0
https://gitlab.com/tslocum/ditty
The MIT License (MIT)
Copyright (c) 2020 Trevor Slocum <trevor@rocketnine.space>
`
)
var (
configPath string
printVersionInfo bool
bufferSize time.Duration
debugAddress string
cpuProfile string
streamFdInt int
streamFd *os.File
restrictLibrary string
showHiddenFolders bool
version = "0.0.0"
done = make(chan bool)
)
func exit() {
done <- true
}
func main() {
log.SetFlags(0)
flag.StringVar(&configPath, "config", "", "path to configuration file")
flag.BoolVar(&printVersionInfo, "version", false, "print version information and exit")
flag.IntVar(&streamFdInt, "fd", -1, "stream audio to file descriptor")
flag.StringVar(&restrictLibrary, "restrict-library", "", "restrict library to path")
flag.DurationVar(&bufferSize, "buffer-size", defaultBufferSize, "audio buffer size")
flag.StringVar(&debugAddress, "debug-address", "", "address to serve debug info")
flag.BoolVar(&showHiddenFolders, "hidden-folders", false, "show hidden folders")
flag.StringVar(&cpuProfile, "cpu-profile", "", "path to save CPU profiling")
flag.Parse()
if printVersionInfo {
fmt.Print(strings.Replace(versionInfo, "0.0.0", version, 1))
return
}
if restrictLibrary != "" {
var err error
restrictLibrary, err = filepath.Abs(restrictLibrary)
if err != nil {
log.Fatalf("failed to restrict library to %s: %s", restrictLibrary, err)
}
}
if debugAddress != "" {
go func() {
log.Fatal(http.ListenAndServe(debugAddress, nil))
}()
}
if cpuProfile != "" {
f, err := os.Create(cpuProfile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
defer f.Close()
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
}
err := readConfig(configPath)
if err != nil {
log.Fatalf("failed to read configuration file: %s", err)
}
err = setKeyBinds()
if err != nil {
log.Fatalf("failed to set keybinds: %s", err)
}
err = initTUI()
if err != nil {
log.Fatalf("failed to initialize terminal user interface: %s", err)
}
sigc := make(chan os.Signal, 1)
signal.Notify(sigc,
syscall.SIGINT,
syscall.SIGTERM)
go func() {
<-sigc
done <- true
}()
go func() {
err := app.Run()
if err != nil {
log.Fatal(err)
}
done <- true
}()
startPath := strings.Join(flag.Args(), " ")
if startPath == "" {
if restrictLibrary == "" {
wd, err := os.Getwd()
if err != nil || wd == "" {
homeDir, err := os.UserHomeDir()
if err == nil && homeDir != "" {
startPath = homeDir
}
} else {
startPath = wd
}
} else {
startPath = restrictLibrary
}
}
if startPath == "" {
log.Fatal("supply a path to browse")
}
fileInfo, err := os.Stat(startPath)
if err != nil {
log.Fatal(err)
}
if fileInfo.IsDir() {
browseFolder(startPath)
} else {
browseFolder(filepath.Dir(startPath))
audioFile, err := openFile(strings.Join(flag.Args(), " "), nil)
if err != nil {
statusText = err.Error()
app.QueueUpdateDraw(updateMain)
} else {
play(audioFile)
}
}
defer func() {
if app != nil {
app.Stop()
}
}()
t := time.NewTicker(time.Second)
for {
select {
case <-done:
if streamFd != nil {
streamFd.Close()
}
return
case <-t.C:
app.QueueUpdateDraw(updateStatus)
}
}
}