2020-06-22 00:05:56 +08:00
|
|
|
// Copyright (C) 2020 Raziman
|
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
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-02 16:01:18 +08:00
|
|
|
"path"
|
2020-07-01 21:21:46 +08:00
|
|
|
"strings"
|
2020-06-25 10:46:45 +08:00
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
"github.com/gdamore/tcell"
|
|
|
|
"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-07-04 16:16:57 +08:00
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
func readConfig(args Args) {
|
2020-07-04 16:16:57 +08:00
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
configPath := *args.config
|
|
|
|
musicDir := *args.music
|
|
|
|
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-02 16:01:18 +08:00
|
|
|
defaultPath := path.Join(home, ".config/gomu/config")
|
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")
|
|
|
|
viper.AddConfigPath(expandTilde(configPath))
|
|
|
|
viper.AddConfigPath("$HOME/.config/gomu")
|
2020-07-06 17:02:59 +08:00
|
|
|
|
2020-07-28 11:24:58 +08:00
|
|
|
colors := map[string]string{
|
|
|
|
"color.foreground": "#FFFFFF",
|
|
|
|
"color.background": "none",
|
|
|
|
"color.accent": "#008B8B",
|
|
|
|
"color.popup": "#0A0F14",
|
|
|
|
"color.now_playing_title": "#017702",
|
|
|
|
"color.playlist": "#008B8B",
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
viper.SetDefault("general.music_dir", musicDir)
|
|
|
|
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)
|
|
|
|
|
|
|
|
// Colors
|
|
|
|
for k, v := range colors {
|
|
|
|
viper.SetDefault(k, v)
|
|
|
|
}
|
2020-07-06 17:02:59 +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
|
|
|
|
|
|
|
input, err := ioutil.ReadFile("config")
|
|
|
|
if err != nil {
|
2020-07-23 15:15:39 +08:00
|
|
|
logError(err)
|
|
|
|
}
|
2020-08-02 16:01:18 +08:00
|
|
|
|
|
|
|
err = ioutil.WriteFile(defaultPath, input, 0644)
|
|
|
|
if err != nil {
|
|
|
|
logError(err)
|
|
|
|
}
|
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
}
|
2020-07-06 17:02:59 +08:00
|
|
|
|
2020-08-02 17:26:39 +08:00
|
|
|
} else {
|
2020-07-06 17:02:59 +08:00
|
|
|
|
2020-08-02 17:26:39 +08:00
|
|
|
// Validate hex color
|
|
|
|
for k, v := range colors {
|
|
|
|
cfgColor := viper.GetString(k)
|
|
|
|
if validateHexColor(cfgColor) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// use default value if invalid hex color was given
|
|
|
|
viper.Set(k, v)
|
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
|
|
|
|
load *bool
|
|
|
|
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{
|
|
|
|
config: flag.String("config", "~/.config/gomu/config", "specify config file"),
|
|
|
|
load: flag.Bool("load", true, "load previous queue"),
|
|
|
|
music: flag.String("music", "~/music", "specify music directory"),
|
|
|
|
version: flag.Bool("version", false, "print gomu version"),
|
2020-07-23 13:10:29 +08:00
|
|
|
}
|
2020-07-23 15:15:39 +08:00
|
|
|
flag.Parse()
|
|
|
|
return ar
|
2020-07-23 13:10:29 +08:00
|
|
|
}
|
|
|
|
|
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 13:10:29 +08:00
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
return flex
|
2020-07-04 16:16:57 +08:00
|
|
|
}
|
|
|
|
|
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-06-19 16:29:51 +08:00
|
|
|
// override default border
|
|
|
|
// change double line border to one line border when focused
|
2020-07-06 18:58:27 +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
|
|
|
|
tview.Borders.BottomRightFocus = tview.Borders.BottomRight
|
2020-07-28 11:24:58 +08:00
|
|
|
|
|
|
|
var bgColor tcell.Color
|
|
|
|
bg := viper.GetString("color.background")
|
|
|
|
if bg == "none" {
|
|
|
|
bgColor = tcell.ColorDefault
|
|
|
|
} else {
|
|
|
|
bgColor = tcell.GetColor(bg)
|
|
|
|
}
|
|
|
|
|
|
|
|
tview.Styles.PrimitiveBackgroundColor = bgColor
|
2020-07-04 16:16:57 +08:00
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
// Assigning to global variable gomu
|
|
|
|
gomu = newGomu()
|
|
|
|
gomu.initPanels(application)
|
2020-06-19 16:29:51 +08:00
|
|
|
|
2020-07-24 17:07:53 +08:00
|
|
|
debugLog("App start")
|
2020-07-02 16:11:10 +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-07-18 15:43:20 +08:00
|
|
|
if *args.load {
|
|
|
|
// load saved queue from previous
|
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-06-26 12:54:48 +08:00
|
|
|
application.SetInputCapture(func(event *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 event
|
|
|
|
}
|
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
switch event.Key() {
|
|
|
|
// cycle through each section
|
|
|
|
case tcell.KeyTAB:
|
2020-07-24 14:51:45 +08:00
|
|
|
|
2020-07-24 15:22:50 +08:00
|
|
|
if strings.Contains(popupName, "confirmation-") {
|
2020-07-24 14:51:45 +08:00
|
|
|
return event
|
|
|
|
}
|
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
gomu.cyclePanels()
|
2020-07-06 17:02:59 +08:00
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
switch event.Rune() {
|
|
|
|
case 'q':
|
2020-06-19 16:42:30 +08:00
|
|
|
|
2020-07-28 11:24:58 +08:00
|
|
|
if !viper.GetBool("general.confirm_on_exit") {
|
2020-08-02 16:01:18 +08:00
|
|
|
err := gomu.quit()
|
|
|
|
if err != nil {
|
|
|
|
logError(err)
|
|
|
|
}
|
2020-06-24 20:09:47 +08:00
|
|
|
}
|
2020-06-19 16:42:30 +08:00
|
|
|
|
2020-07-24 14:51:10 +08:00
|
|
|
exitConfirmation()
|
2020-06-19 16:29:51 +08:00
|
|
|
|
2020-06-21 00:00:17 +08:00
|
|
|
case ' ':
|
2020-07-23 15:15:39 +08:00
|
|
|
gomu.player.togglePause()
|
2020-06-21 23:47:12 +08:00
|
|
|
|
|
|
|
case '+':
|
2020-07-24 15:47:36 +08:00
|
|
|
v := int(gomu.player.volume*10) + 100
|
|
|
|
if v < 100 {
|
2020-07-23 15:15:39 +08:00
|
|
|
vol := gomu.player.setVolume(0.5)
|
2020-06-26 17:09:15 +08:00
|
|
|
volumePopup(vol)
|
|
|
|
}
|
2020-06-21 23:47:12 +08:00
|
|
|
|
|
|
|
case '-':
|
2020-07-24 15:47:36 +08:00
|
|
|
v := int(gomu.player.volume*10) + 100
|
2020-06-26 17:09:15 +08:00
|
|
|
if v > 0 {
|
2020-07-23 15:15:39 +08:00
|
|
|
vol := gomu.player.setVolume(-0.5)
|
2020-06-26 17:09:15 +08:00
|
|
|
volumePopup(vol)
|
|
|
|
}
|
2020-06-21 00:00:17 +08:00
|
|
|
|
2020-06-23 18:42:18 +08:00
|
|
|
case 'n':
|
2020-07-23 15:15:39 +08:00
|
|
|
gomu.player.skip()
|
2020-06-23 18:42:18 +08:00
|
|
|
|
2020-06-27 00:09:59 +08:00
|
|
|
case '?':
|
|
|
|
|
2020-07-23 15:15:39 +08:00
|
|
|
name, _ := gomu.pages.GetFrontPage()
|
2020-06-27 00:09:59 +08:00
|
|
|
|
|
|
|
if name == "help-page" {
|
2020-07-23 15:15:39 +08:00
|
|
|
gomu.pages.RemovePage(name)
|
|
|
|
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
2020-06-27 00:09:59 +08:00
|
|
|
} else {
|
2020-07-23 15:15:39 +08:00
|
|
|
helpPopup(gomu.prevPanel)
|
2020-06-27 00:09:59 +08:00
|
|
|
}
|
|
|
|
|
2020-06-19 16:29:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return event
|
|
|
|
})
|
|
|
|
|
|
|
|
// 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
|
|
|
}
|
|
|
|
}
|