mirror of
https://github.com/issadarkthing/gomu.git
synced 2025-05-06 19:29:18 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
1362c9925b
@ -101,8 +101,8 @@ Each panel has it's own additional keybinding. To view the available keybinding
|
|||||||
|
|
||||||
### Scripting
|
### Scripting
|
||||||
|
|
||||||
Gomu uses [anko](github.com/mattn/anko) as its scripting language. You can read
|
Gomu uses [anko](https://github.com/mattn/anko) as its scripting language. You can read
|
||||||
more about scripting at our [wiki](github.com/issadarkthing/gomu/wiki)
|
more about scripting at our [wiki](https://github.com/issadarkthing/gomu/wiki)
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ type Anko struct {
|
|||||||
env *env.Env
|
env *env.Env
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAnko() Anko {
|
func NewAnko() *Anko {
|
||||||
|
|
||||||
env := core.Import(env.NewEnv())
|
env := core.Import(env.NewEnv())
|
||||||
importToX(env)
|
importToX(env)
|
||||||
@ -45,7 +45,7 @@ func NewAnko() Anko {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Anko{env}
|
return &Anko{env}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define defines new symbol and value to the Anko env.
|
// Define defines new symbol and value to the Anko env.
|
||||||
|
97
command.go
97
command.go
@ -1,10 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"github.com/ztrue/tracerr"
|
"github.com/ztrue/tracerr"
|
||||||
)
|
)
|
||||||
@ -66,98 +62,7 @@ func (c Command) defineCommands() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
c.define("youtube_search", func() {
|
c.define("youtube_search", func() {
|
||||||
|
ytSearchPopup()
|
||||||
popupId := "youtube-search-input-popup"
|
|
||||||
|
|
||||||
input := newInputPopup(popupId, " Youtube Search ", "search: ", "")
|
|
||||||
|
|
||||||
// quick hack to change the autocomplete text color
|
|
||||||
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack
|
|
||||||
input.SetAutocompleteFunc(func(currentText string) (entries []string) {
|
|
||||||
|
|
||||||
if currentText == "" {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
suggestions, err := getSuggestions(currentText)
|
|
||||||
if err != nil {
|
|
||||||
logError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestions
|
|
||||||
})
|
|
||||||
|
|
||||||
input.SetDoneFunc(func(key tcell.Key) {
|
|
||||||
|
|
||||||
switch key {
|
|
||||||
case tcell.KeyEnter:
|
|
||||||
search := input.GetText()
|
|
||||||
defaultTimedPopup(" Youtube Search ", "Searching for "+search)
|
|
||||||
gomu.pages.RemovePage(popupId)
|
|
||||||
gomu.popups.pop()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
|
|
||||||
results, err := getSearchResult(search)
|
|
||||||
if err != nil {
|
|
||||||
logError(err)
|
|
||||||
defaultTimedPopup(" Error ", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
titles := []string{}
|
|
||||||
urls := make(map[string]string)
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
duration, err := time.ParseDuration(fmt.Sprintf("%ds", result.LengthSeconds))
|
|
||||||
if err != nil {
|
|
||||||
logError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
durationText := fmt.Sprintf("[ %s ] ", fmtDuration(duration))
|
|
||||||
title := durationText + result.Title
|
|
||||||
|
|
||||||
urls[title] = `https://www.youtube.com/watch?v=` + result.VideoId
|
|
||||||
|
|
||||||
titles = append(titles, title)
|
|
||||||
}
|
|
||||||
|
|
||||||
searchPopup("Youtube Videos", titles, func(title string) {
|
|
||||||
|
|
||||||
audioFile := gomu.playlist.getCurrentFile()
|
|
||||||
|
|
||||||
var dir *tview.TreeNode
|
|
||||||
|
|
||||||
if audioFile.isAudioFile {
|
|
||||||
dir = audioFile.parent
|
|
||||||
} else {
|
|
||||||
dir = audioFile.node
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
url := urls[title]
|
|
||||||
if err := ytdl(url, dir); err != nil {
|
|
||||||
logError(err)
|
|
||||||
}
|
|
||||||
gomu.playlist.refresh()
|
|
||||||
}()
|
|
||||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
|
||||||
})
|
|
||||||
|
|
||||||
gomu.app.Draw()
|
|
||||||
}()
|
|
||||||
|
|
||||||
case tcell.KeyEscape:
|
|
||||||
gomu.pages.RemovePage(popupId)
|
|
||||||
gomu.popups.pop()
|
|
||||||
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
|
||||||
|
|
||||||
default:
|
|
||||||
input.Autocomplete()
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
c.define("download_audio", func() {
|
c.define("download_audio", func() {
|
||||||
|
25
command_test.go
Normal file
25
command_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TestGetFn(t *testing.T) {
|
||||||
|
|
||||||
|
c := newCommand()
|
||||||
|
|
||||||
|
c.define("sample", func() {})
|
||||||
|
|
||||||
|
f, err := c.getFn("sample")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.NotNil(t, f)
|
||||||
|
|
||||||
|
f, err = c.getFn("x")
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
7
gomu.go
7
gomu.go
@ -1,9 +1,10 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/issadarkthing/gomu/anko"
|
||||||
|
"github.com/issadarkthing/gomu/hook"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"github.com/ztrue/tracerr"
|
"github.com/ztrue/tracerr"
|
||||||
"github.com/issadarkthing/gomu/anko"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var VERSION = "N/A"
|
var VERSION = "N/A"
|
||||||
@ -24,7 +25,8 @@ type Gomu struct {
|
|||||||
prevPanel Panel
|
prevPanel Panel
|
||||||
panels []Panel
|
panels []Panel
|
||||||
args Args
|
args Args
|
||||||
anko anko.Anko
|
anko *anko.Anko
|
||||||
|
hook *hook.EventHook
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates new instance of gomu with default values
|
// Creates new instance of gomu with default values
|
||||||
@ -33,6 +35,7 @@ func newGomu() *Gomu {
|
|||||||
gomu := &Gomu{
|
gomu := &Gomu{
|
||||||
command: newCommand(),
|
command: newCommand(),
|
||||||
anko: anko.NewAnko(),
|
anko: anko.NewAnko(),
|
||||||
|
hook: hook.NewEventHook(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return gomu
|
return gomu
|
||||||
|
35
hook/hook.go
Normal file
35
hook/hook.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package hook
|
||||||
|
|
||||||
|
type EventHook struct {
|
||||||
|
events map[string][]func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNewEventHook returns new instance of EventHook
|
||||||
|
func NewEventHook() *EventHook {
|
||||||
|
return &EventHook{make(map[string][]func())}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook accepts a function which will be executed when the event is emitted.
|
||||||
|
func (e *EventHook) AddHook(eventName string, handler func()) {
|
||||||
|
|
||||||
|
hooks, ok := e.events[eventName]
|
||||||
|
if !ok {
|
||||||
|
e.events[eventName] = []func(){handler}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e.events[eventName] = append(hooks, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunHooks executes all hooks installed for an event.
|
||||||
|
func (e *EventHook) RunHooks(eventName string) {
|
||||||
|
|
||||||
|
hooks, ok := e.events[eventName]
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hook := range hooks {
|
||||||
|
hook()
|
||||||
|
}
|
||||||
|
}
|
57
hook/hook_test.go
Normal file
57
hook/hook_test.go
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package hook
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAddHook(t *testing.T) {
|
||||||
|
|
||||||
|
h := NewEventHook()
|
||||||
|
|
||||||
|
h.AddHook("a", nil)
|
||||||
|
h.AddHook("a", nil)
|
||||||
|
h.AddHook("a", nil)
|
||||||
|
h.AddHook("a", nil)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(h.events), "should only contain 1 event")
|
||||||
|
|
||||||
|
hooks := h.events["a"]
|
||||||
|
assert.Equal(t, 4, len(hooks), "should contain 4 hooks")
|
||||||
|
|
||||||
|
h.AddHook("b", nil)
|
||||||
|
h.AddHook("c", nil)
|
||||||
|
|
||||||
|
assert.Equal(t, 3, len(h.events), "should contain 3 events")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunHooks(t *testing.T) {
|
||||||
|
|
||||||
|
h := NewEventHook()
|
||||||
|
x := 0
|
||||||
|
|
||||||
|
for i := 0; i < 100; i ++ {
|
||||||
|
h.AddHook("sample", func() {
|
||||||
|
x++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
h.AddHook("noop", func() {
|
||||||
|
x++
|
||||||
|
})
|
||||||
|
|
||||||
|
h.AddHook("noop", func() {
|
||||||
|
x++
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, x, 0, "should not execute any hook")
|
||||||
|
|
||||||
|
h.RunHooks("x")
|
||||||
|
|
||||||
|
assert.Equal(t, x, 0, "should not execute any hook")
|
||||||
|
|
||||||
|
h.RunHooks("sample")
|
||||||
|
|
||||||
|
assert.Equal(t, x, 100, "should only execute event 'sample'")
|
||||||
|
}
|
10
player.go
10
player.go
@ -121,7 +121,10 @@ func (p *Player) run(currSong *AudioFile) error {
|
|||||||
// sets the volume of previous player
|
// sets the volume of previous player
|
||||||
volume.Volume += p.volume
|
volume.Volume += p.volume
|
||||||
p._volume = volume
|
p._volume = volume
|
||||||
|
|
||||||
|
// starts playing the audio
|
||||||
speaker.Play(p._volume)
|
speaker.Play(p._volume)
|
||||||
|
gomu.hook.RunHooks("new_song")
|
||||||
|
|
||||||
p.isRunning = true
|
p.isRunning = true
|
||||||
|
|
||||||
@ -157,6 +160,7 @@ next:
|
|||||||
// when there are no songs to be played, set currentSong as nil
|
// when there are no songs to be played, set currentSong as nil
|
||||||
p.currentSong = nil
|
p.currentSong = nil
|
||||||
gomu.playingBar.setDefault()
|
gomu.playingBar.setDefault()
|
||||||
|
gomu.app.Draw()
|
||||||
break next
|
break next
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +194,7 @@ next:
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) pause() {
|
func (p *Player) pause() {
|
||||||
|
gomu.hook.RunHooks("pause")
|
||||||
speaker.Lock()
|
speaker.Lock()
|
||||||
p.ctrl.Paused = true
|
p.ctrl.Paused = true
|
||||||
p.isRunning = false
|
p.isRunning = false
|
||||||
@ -197,6 +202,7 @@ func (p *Player) pause() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *Player) play() {
|
func (p *Player) play() {
|
||||||
|
gomu.hook.RunHooks("play")
|
||||||
speaker.Lock()
|
speaker.Lock()
|
||||||
p.ctrl.Paused = false
|
p.ctrl.Paused = false
|
||||||
p.isRunning = true
|
p.isRunning = true
|
||||||
@ -235,7 +241,9 @@ func (p *Player) togglePause() {
|
|||||||
// skips current song
|
// skips current song
|
||||||
func (p *Player) skip() {
|
func (p *Player) skip() {
|
||||||
|
|
||||||
if gomu.queue.GetItemCount() < 1 {
|
gomu.hook.RunHooks("skip")
|
||||||
|
|
||||||
|
if p.currentSong == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,14 +38,6 @@ func newPlayingBar() *PlayingBar {
|
|||||||
progress: make(chan int),
|
progress: make(chan int),
|
||||||
}
|
}
|
||||||
|
|
||||||
textView.SetChangedFunc(func() {
|
|
||||||
gomu.app.Draw()
|
|
||||||
|
|
||||||
if !gomu.player.isRunning {
|
|
||||||
p.setDefault()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +76,7 @@ func (p *PlayingBar) run() error {
|
|||||||
progressBar,
|
progressBar,
|
||||||
fmtDuration(end),
|
fmtDuration(end),
|
||||||
))
|
))
|
||||||
|
gomu.app.Draw()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
139
popup.go
139
popup.go
@ -8,6 +8,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -53,6 +54,8 @@ func (s *Stack) pop() tview.Primitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
last := s.popups[len(s.popups)-1]
|
last := s.popups[len(s.popups)-1]
|
||||||
|
s.popups[len(s.popups)-1] = nil // avoid memory leak
|
||||||
|
|
||||||
res := s.popups[:len(s.popups)-1]
|
res := s.popups[:len(s.popups)-1]
|
||||||
s.popups = res
|
s.popups = res
|
||||||
|
|
||||||
@ -611,16 +614,20 @@ func replPopup() {
|
|||||||
|
|
||||||
switch event.Key() {
|
switch event.Key() {
|
||||||
case tcell.KeyUp:
|
case tcell.KeyUp:
|
||||||
input.SetText(history[upCount])
|
|
||||||
|
|
||||||
if upCount < len(history)-1 {
|
if upCount < len(history) {
|
||||||
|
input.SetText(history[upCount])
|
||||||
upCount++
|
upCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
case tcell.KeyDown:
|
case tcell.KeyDown:
|
||||||
|
|
||||||
if upCount > 0 {
|
if upCount > 0 {
|
||||||
upCount--
|
if upCount == len(history) {
|
||||||
|
upCount -= 2
|
||||||
|
} else {
|
||||||
|
upCount -= 1
|
||||||
|
}
|
||||||
input.SetText(history[upCount])
|
input.SetText(history[upCount])
|
||||||
} else if upCount == 0 {
|
} else if upCount == 0 {
|
||||||
input.SetText("")
|
input.SetText("")
|
||||||
@ -642,15 +649,20 @@ func replPopup() {
|
|||||||
|
|
||||||
input.SetText("")
|
input.SetText("")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
res, err := gomu.anko.Execute(text)
|
res, err := gomu.anko.Execute(text)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, err)
|
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, err)
|
||||||
return nil
|
return nil
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if res != nil {
|
|
||||||
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, res)
|
fmt.Fprintf(textview, "%s%s\n%v\n\n", prompt, text, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return event
|
return event
|
||||||
@ -671,6 +683,121 @@ func replPopup() {
|
|||||||
gomu.popups.push(flex)
|
gomu.popups.push(flex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ytSearchPopup() {
|
||||||
|
|
||||||
|
popupId := "youtube-search-input-popup"
|
||||||
|
|
||||||
|
input := newInputPopup(popupId, " Youtube Search ", "search: ", "")
|
||||||
|
|
||||||
|
var mutex sync.Mutex
|
||||||
|
prefixMap := make(map[string][]string)
|
||||||
|
|
||||||
|
// quick hack to change the autocomplete text color
|
||||||
|
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack
|
||||||
|
input.SetAutocompleteFunc(func(currentText string) []string {
|
||||||
|
|
||||||
|
// Ignore empty text.
|
||||||
|
prefix := strings.TrimSpace(strings.ToLower(currentText))
|
||||||
|
if prefix == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
entries, ok := prefixMap[prefix]
|
||||||
|
if ok {
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
suggestions, err := getSuggestions(currentText)
|
||||||
|
if err != nil {
|
||||||
|
logError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex.Lock()
|
||||||
|
prefixMap[prefix] = suggestions
|
||||||
|
mutex.Unlock()
|
||||||
|
|
||||||
|
input.Autocomplete()
|
||||||
|
gomu.app.Draw()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
input.SetDoneFunc(func(key tcell.Key) {
|
||||||
|
|
||||||
|
switch key {
|
||||||
|
case tcell.KeyEnter:
|
||||||
|
search := input.GetText()
|
||||||
|
defaultTimedPopup(" Youtube Search ", "Searching for "+search)
|
||||||
|
gomu.pages.RemovePage(popupId)
|
||||||
|
gomu.popups.pop()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
|
||||||
|
results, err := getSearchResult(search)
|
||||||
|
if err != nil {
|
||||||
|
logError(err)
|
||||||
|
defaultTimedPopup(" Error ", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
titles := []string{}
|
||||||
|
urls := make(map[string]string)
|
||||||
|
|
||||||
|
for _, result := range results {
|
||||||
|
duration, err := time.ParseDuration(fmt.Sprintf("%ds", result.LengthSeconds))
|
||||||
|
if err != nil {
|
||||||
|
logError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
durationText := fmt.Sprintf("[ %s ] ", fmtDuration(duration))
|
||||||
|
title := durationText + result.Title
|
||||||
|
|
||||||
|
urls[title] = `https://www.youtube.com/watch?v=` + result.VideoId
|
||||||
|
|
||||||
|
titles = append(titles, title)
|
||||||
|
}
|
||||||
|
|
||||||
|
searchPopup("Youtube Videos", titles, func(title string) {
|
||||||
|
|
||||||
|
audioFile := gomu.playlist.getCurrentFile()
|
||||||
|
|
||||||
|
var dir *tview.TreeNode
|
||||||
|
|
||||||
|
if audioFile.isAudioFile {
|
||||||
|
dir = audioFile.parent
|
||||||
|
} else {
|
||||||
|
dir = audioFile.node
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
url := urls[title]
|
||||||
|
if err := ytdl(url, dir); err != nil {
|
||||||
|
logError(err)
|
||||||
|
}
|
||||||
|
gomu.playlist.refresh()
|
||||||
|
}()
|
||||||
|
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||||
|
})
|
||||||
|
|
||||||
|
gomu.app.Draw()
|
||||||
|
}()
|
||||||
|
|
||||||
|
case tcell.KeyEscape:
|
||||||
|
gomu.pages.RemovePage(popupId)
|
||||||
|
gomu.popups.pop()
|
||||||
|
gomu.app.SetFocus(gomu.prevPanel.(tview.Primitive))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func tagPopup(node *AudioFile) bool {
|
func tagPopup(node *AudioFile) bool {
|
||||||
var tag *id3v2.Tag
|
var tag *id3v2.Tag
|
||||||
var err error
|
var err error
|
||||||
|
85
start.go
85
start.go
@ -13,6 +13,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
"github.com/issadarkthing/gomu/anko"
|
||||||
|
"github.com/issadarkthing/gomu/hook"
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"github.com/ztrue/tracerr"
|
"github.com/ztrue/tracerr"
|
||||||
)
|
)
|
||||||
@ -62,9 +64,33 @@ func defineBuiltins() {
|
|||||||
gomu.anko.Define("shell", shell)
|
gomu.anko.Define("shell", shell)
|
||||||
}
|
}
|
||||||
|
|
||||||
// execInit executes helper modules and default config that should only be
|
func setupHooks(hook *hook.EventHook, anko *anko.Anko) {
|
||||||
|
|
||||||
|
events := []string{
|
||||||
|
"enter",
|
||||||
|
"new_song",
|
||||||
|
"skip",
|
||||||
|
"play",
|
||||||
|
"pause",
|
||||||
|
"exit",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range events {
|
||||||
|
name := event
|
||||||
|
hook.AddHook(name, func() {
|
||||||
|
src := fmt.Sprintf(`Event.run_hooks("%s")`, name)
|
||||||
|
_, err := anko.Execute(src)
|
||||||
|
if err != nil {
|
||||||
|
err = tracerr.Errorf("error execute hook: %w", err)
|
||||||
|
logError(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadModules executes helper modules and default config that should only be
|
||||||
// executed once
|
// executed once
|
||||||
func execInit() error {
|
func loadModules(env *anko.Anko) error {
|
||||||
|
|
||||||
const listModule = `
|
const listModule = `
|
||||||
module List {
|
module List {
|
||||||
@ -94,6 +120,35 @@ module List {
|
|||||||
return acc
|
return acc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
`
|
||||||
|
const eventModule = `
|
||||||
|
module Event {
|
||||||
|
events = {}
|
||||||
|
|
||||||
|
func add_hook(name, f) {
|
||||||
|
hooks = events[name]
|
||||||
|
|
||||||
|
if hooks == nil {
|
||||||
|
events[name] = [f]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hooks += f
|
||||||
|
events[name] = hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
func run_hooks(name) {
|
||||||
|
hooks = events[name]
|
||||||
|
|
||||||
|
if hooks == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for hook in hooks {
|
||||||
|
hook()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const keybindModule = `
|
const keybindModule = `
|
||||||
@ -115,8 +170,7 @@ module Keybinds {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
_, err := env.Execute(eventModule + listModule + keybindModule)
|
||||||
_, err := gomu.anko.Execute(listModule + keybindModule)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tracerr.Wrap(err)
|
return tracerr.Wrap(err)
|
||||||
}
|
}
|
||||||
@ -231,7 +285,8 @@ func start(application *tview.Application, args Args) {
|
|||||||
gomu = newGomu()
|
gomu = newGomu()
|
||||||
gomu.command.defineCommands()
|
gomu.command.defineCommands()
|
||||||
defineBuiltins()
|
defineBuiltins()
|
||||||
err := execInit()
|
|
||||||
|
err := loadModules(gomu.anko)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
die(err)
|
die(err)
|
||||||
}
|
}
|
||||||
@ -241,6 +296,9 @@ func start(application *tview.Application, args Args) {
|
|||||||
die(err)
|
die(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupHooks(gomu.hook, gomu.anko)
|
||||||
|
|
||||||
|
gomu.hook.RunHooks("enter")
|
||||||
gomu.args = args
|
gomu.args = args
|
||||||
gomu.colors = newColor()
|
gomu.colors = newColor()
|
||||||
|
|
||||||
@ -357,15 +415,26 @@ func start(application *tview.Application, args Args) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// fix transparent background issue
|
// fix transparent background issue
|
||||||
application.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
|
gomu.app.SetBeforeDrawFunc(func(screen tcell.Screen) bool {
|
||||||
screen.Clear()
|
screen.Clear()
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
init := false
|
||||||
|
gomu.app.SetAfterDrawFunc(func(_ tcell.Screen) {
|
||||||
|
if !init && !gomu.player.isRunning {
|
||||||
|
gomu.playingBar.setDefault()
|
||||||
|
init = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
go populateAudioLength(gomu.playlist.GetRoot())
|
go populateAudioLength(gomu.playlist.GetRoot())
|
||||||
|
gomu.app.SetRoot(gomu.pages, true).SetFocus(gomu.playlist)
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
if err := application.SetRoot(gomu.pages, true).SetFocus(gomu.playlist).Run(); err != nil {
|
if err := gomu.app.Run(); err != nil {
|
||||||
logError(err)
|
die(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gomu.hook.RunHooks("exit")
|
||||||
}
|
}
|
||||||
|
47
start_test.go
Normal file
47
start_test.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/issadarkthing/gomu/anko"
|
||||||
|
"github.com/issadarkthing/gomu/hook"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TestSetupHooks(t *testing.T) {
|
||||||
|
|
||||||
|
gomu := newGomu()
|
||||||
|
gomu.anko = anko.NewAnko()
|
||||||
|
gomu.hook = hook.NewEventHook()
|
||||||
|
|
||||||
|
err := loadModules(gomu.anko)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
setupHooks(gomu.hook, gomu.anko)
|
||||||
|
|
||||||
|
const src = `
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
Event.add_hook("skip", func() {
|
||||||
|
i++
|
||||||
|
})
|
||||||
|
`
|
||||||
|
|
||||||
|
_, err = gomu.anko.Execute(src)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gomu.hook.RunHooks("enter")
|
||||||
|
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
gomu.hook.RunHooks("skip")
|
||||||
|
}
|
||||||
|
|
||||||
|
got := gomu.anko.GetInt("i")
|
||||||
|
|
||||||
|
assert.Equal(t, 12, got)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user