gomu/start.go

276 lines
6.5 KiB
Go
Raw Normal View History

2020-06-22 00:05:56 +08:00
// Copyright (C) 2020 Raziman
2020-06-19 16:29:51 +08:00
package main
import (
2020-08-18 12:26:45 +08:00
"errors"
2020-07-18 15:43:20 +08:00
"flag"
2020-07-21 20:51:10 +08:00
"fmt"
2020-08-02 16:01:18 +08:00
"io/ioutil"
2020-06-25 10:46:45 +08:00
"os"
2020-08-18 12:26:45 +08:00
"os/signal"
2020-08-02 16:01:18 +08:00
"path"
"strings"
2020-08-18 12:26:45 +08:00
"syscall"
2020-06-25 10:46:45 +08:00
2021-01-21 01:30:16 +08:00
"github.com/gdamore/tcell/v2"
2020-06-19 16:29:51 +08:00
"github.com/rivo/tview"
2020-06-24 20:09:47 +08:00
"github.com/spf13/viper"
2020-06-19 16:29:51 +08:00
)
2020-07-23 15:34:56 +08:00
// Created so we can keep track of childrens in slices
2020-07-06 17:02:59 +08:00
type Panel interface {
HasFocus() bool
SetBorderColor(color tcell.Color) *tview.Box
SetTitleColor(color tcell.Color) *tview.Box
SetTitle(s string) *tview.Box
GetTitle() string
2020-07-23 15:15:39 +08:00
help() []string
2020-07-06 17:02:59 +08:00
}
2020-08-11 14:36:20 +08:00
const (
CONFIG_PATH = ".config/gomu/config"
HISTORY_PATH = "~/.local/share/gomu/urls"
MUSIC_PATH = "~/music"
2020-08-11 14:36:20 +08:00
)
// Reads config file and sets the options
2020-07-23 15:15:39 +08:00
func readConfig(args Args) {
2020-08-22 14:41:03 +08:00
const config = `
2020-08-21 15:25:04 +08:00
general:
2020-08-25 21:44:20 +08:00
# confirmation popup to add the whole playlist to the queue
2020-08-21 15:25:04 +08:00
confirm_bulk_add: true
confirm_on_exit: true
load_prev_queue: true
2020-08-25 21:44:20 +08:00
# change this to directory that contains mp3 files
2020-08-21 15:25:04 +08:00
music_dir: ~/music
# url history of downloaded audio will be saved here
history_path: ~/.local/share/gomu/urls
2020-08-21 15:25:04 +08:00
popup_timeout: 5s
2020-08-22 22:03:52 +08:00
# initial volume when gomu starts up
2020-08-21 15:25:04 +08:00
volume: 100
2020-08-22 22:03:52 +08:00
# some of the terminal supports unicode character
2020-08-25 18:20:27 +08:00
# you can set this to true to enable emojis
emoji: false
2020-08-22 22:03:52 +08:00
# you may use fzf as your finder inside gomu
# but it is recommended to use built-in finder
# as it integrates well with gomu
2020-08-21 15:25:04 +08:00
fzf: false
2020-08-25 18:20:27 +08:00
2020-08-25 21:44:20 +08:00
# not all colors can be reproducible in terminal
# changing hex colors may or may not produce expected result
color:
accent: "#008B8B"
# none is transparent
# only background has none attribute
background: none
foreground: "#FFFFFF"
now_playing_title: "#017702"
playlist: "#008B8B"
popup: "#0A0F14"
# default emoji here is using awesome-terminal-fonts
# you can change these to your liking
emoji:
playlist:
file:
2020-08-25 18:20:27 +08:00
# vi:ft=yaml
2020-08-21 15:25:04 +08:00
`
2020-08-11 14:36:20 +08:00
// config path passed by flag
2020-07-23 15:15:39 +08:00
configPath := *args.config
home, err := os.UserHomeDir()
2020-07-06 17:02:59 +08:00
2020-07-23 15:15:39 +08:00
if err != nil {
logError(err)
}
2020-07-06 17:02:59 +08:00
2020-08-11 14:36:20 +08:00
defaultPath := path.Join(home, CONFIG_PATH)
2020-07-06 17:02:59 +08:00
2020-07-23 15:15:39 +08:00
if err != nil {
logError(err)
}
2020-07-06 17:02:59 +08:00
2020-07-23 15:15:39 +08:00
viper.SetConfigName("config")
viper.SetConfigType("yaml")
2020-08-11 14:36:20 +08:00
viper.AddConfigPath(strings.TrimSuffix(expandFilePath(configPath), "/config"))
2020-07-23 15:15:39 +08:00
viper.AddConfigPath("$HOME/.config/gomu")
2020-07-06 17:02:59 +08:00
2020-07-23 15:15:39 +08:00
if err := viper.ReadInConfig(); err != nil {
2020-07-06 17:02:59 +08:00
2020-07-28 11:24:58 +08:00
// General config
2020-08-11 14:36:20 +08:00
viper.SetDefault("general.music_dir", MUSIC_PATH)
viper.SetDefault("general.history_path", HISTORY_PATH)
2020-07-28 11:24:58 +08:00
viper.SetDefault("general.confirm_on_exit", true)
viper.SetDefault("general.confirm_bulk_add", true)
viper.SetDefault("general.popup_timeout", "5s")
viper.SetDefault("general.volume", 100)
viper.SetDefault("general.load_prev_queue", true)
2020-08-11 18:31:33 +08:00
viper.SetDefault("general.use_emoji", true)
2020-07-28 11:24:58 +08:00
2020-07-23 15:15:39 +08:00
// creates gomu config dir if does not exist
if _, err := os.Stat(defaultPath); err != nil {
if err := os.MkdirAll(home+"/.config/gomu", 0755); err != nil {
logError(err)
2020-07-06 17:02:59 +08:00
}
}
2020-07-23 15:15:39 +08:00
// if config file was not found
2020-08-02 16:01:18 +08:00
// copy default config to default config path
2020-07-23 15:15:39 +08:00
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
2020-08-02 16:01:18 +08:00
2020-08-21 15:25:04 +08:00
err = ioutil.WriteFile(defaultPath, []byte(config), 0644)
2020-08-02 16:01:18 +08:00
if err != nil {
logError(err)
}
2020-07-23 15:15:39 +08:00
}
2020-07-06 17:02:59 +08:00
2020-07-28 11:24:58 +08:00
}
2020-07-06 17:02:59 +08:00
}
2020-07-23 15:15:39 +08:00
type Args struct {
config *string
2020-08-11 13:39:02 +08:00
empty *bool
2020-07-23 15:15:39 +08:00
music *string
version *bool
2020-07-06 17:02:59 +08:00
}
2020-07-23 15:15:39 +08:00
func getArgs() Args {
ar := Args{
2020-08-11 14:36:20 +08:00
config: flag.String("config", CONFIG_PATH, "Specify config file"),
2020-08-11 13:39:02 +08:00
empty: flag.Bool("empty", false, "Open gomu with empty queue. Does not override previous queue"),
2020-08-11 14:36:20 +08:00
music: flag.String("music", MUSIC_PATH, "Specify music directory"),
version: flag.Bool("version", false, "Print gomu version"),
}
2020-07-23 15:15:39 +08:00
flag.Parse()
return ar
}
2020-07-23 15:15:39 +08:00
// Sets the layout of the application
func layout(gomu *Gomu) *tview.Flex {
flex := tview.NewFlex().
AddItem(gomu.playlist, 0, 1, false).
AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
AddItem(gomu.queue, 0, 5, false).
AddItem(gomu.playingBar, 0, 1, false), 0, 3, false)
2020-07-23 15:15:39 +08:00
return flex
}
2020-07-23 15:15:39 +08:00
// Initialize
2020-07-18 15:43:20 +08:00
func start(application *tview.Application, args Args) {
2020-07-23 15:15:39 +08:00
// Print version and exit
2020-07-21 20:51:10 +08:00
if *args.version {
fmt.Printf("Gomu %s\n", VERSION)
return
}
2020-08-22 14:41:03 +08:00
// Assigning to global variable gomu
gomu = newGomu()
gomu.args = args
2020-08-22 14:41:03 +08:00
2020-06-19 16:29:51 +08:00
// override default border
// change double line border to one line border when focused
2020-08-22 14:41:03 +08:00
tview.Borders.HorizontalFocus = tview.Borders.Horizontal
tview.Borders.VerticalFocus = tview.Borders.Vertical
tview.Borders.TopLeftFocus = tview.Borders.TopLeft
tview.Borders.TopRightFocus = tview.Borders.TopRight
tview.Borders.BottomLeftFocus = tview.Borders.BottomLeft
2020-07-06 18:58:27 +08:00
tview.Borders.BottomRightFocus = tview.Borders.BottomRight
2020-08-22 14:41:03 +08:00
tview.Styles.PrimitiveBackgroundColor = gomu.colors.background
2020-07-28 11:24:58 +08:00
2020-08-11 13:39:02 +08:00
gomu.initPanels(application, args)
gomu.command.defineCommands()
2020-06-19 16:29:51 +08:00
2020-07-23 15:15:39 +08:00
flex := layout(gomu)
gomu.pages.AddPage("main", flex, true, true)
2020-06-25 14:12:19 +08:00
2020-07-18 15:43:20 +08:00
// sets the first focused panel
2020-07-23 15:15:39 +08:00
gomu.setFocusPanel(gomu.playlist)
gomu.prevPanel = gomu.playlist
2020-06-25 14:12:19 +08:00
2020-08-18 12:26:45 +08:00
if !*args.empty && viper.GetBool("general.load_prev_queue") {
// load saved queue from previous session
2020-07-23 15:15:39 +08:00
if err := gomu.queue.loadQueue(); err != nil {
logError(err)
2020-07-18 15:43:20 +08:00
}
2020-07-10 16:52:37 +08:00
}
2020-08-18 12:26:45 +08:00
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGKILL)
go func() {
sig := <-sigs
errMsg := fmt.Sprintf("Received %s. Exiting program", sig.String())
logError(errors.New(errMsg))
err := gomu.quit(args)
if err != nil {
logError(errors.New("Unable to quit program"))
}
}()
// global keybindings are handled here
application.SetInputCapture(func(e *tcell.EventKey) *tcell.EventKey {
2020-06-19 16:29:51 +08:00
2020-07-24 15:22:50 +08:00
popupName, _ := gomu.pages.GetFrontPage()
// disables keybindings when writing in input fields
if strings.Contains(popupName, "-input-") {
return e
2020-07-24 15:22:50 +08:00
}
switch e.Key() {
2020-06-19 16:29:51 +08:00
// cycle through each section
case tcell.KeyTAB:
2020-07-24 15:22:50 +08:00
if strings.Contains(popupName, "confirmation-") {
return e
}
gomu.cyclePanels2()
2020-06-19 16:29:51 +08:00
}
cmds := map[rune]string{
'q': "quit",
' ': "toggle_pause",
'+': "volume_up",
2021-01-27 01:10:48 +08:00
'=': "volume_up",
'-': "volume_down",
2021-01-27 01:10:48 +08:00
'_': "volume_down",
'n': "skip",
':': "command_search",
'?': "toggle_help",
2021-01-27 01:10:48 +08:00
'f': "forward",
'F': "forward_fast",
'b': "rewind",
'B': "rewind_fast",
}
2020-06-21 23:47:12 +08:00
for key, cmd := range cmds {
if e.Rune() != key {
continue
2020-06-26 17:09:15 +08:00
}
fn, err := gomu.command.getFn(cmd)
if err != nil {
logError(err)
return e
2020-06-27 00:09:59 +08:00
}
fn()
2020-06-19 16:29:51 +08:00
}
return e
2020-06-19 16:29:51 +08:00
})
// fix transparent background issue
2020-06-26 12:54:48 +08:00
application.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
2020-06-19 16:29:51 +08:00
screen.Clear()
return false
})
// main loop
2020-07-23 15:15:39 +08:00
if err := application.SetRoot(gomu.pages, true).SetFocus(gomu.playlist).Run(); err != nil {
logError(err)
2020-06-19 16:29:51 +08:00
}
}