diff --git a/command.go b/command.go index 73e070b..31f4b68 100644 --- a/command.go +++ b/command.go @@ -1,6 +1,7 @@ package main import ( + "github.com/issadarkthing/gomu/player" "github.com/rivo/tview" "github.com/ztrue/tracerr" ) @@ -198,12 +199,12 @@ func (c Command) defineCommands() { } gomu.queue.pushFront(a) - gomu.player.skip() + gomu.player.Skip() } }) c.define("toggle_loop", func() { - gomu.queue.isLoop = gomu.player.toggleLoop() + gomu.queue.isLoop = !gomu.queue.isLoop gomu.queue.updateTitle() }) @@ -248,27 +249,27 @@ func (c Command) defineCommands() { }) c.define("toggle_pause", func() { - gomu.player.togglePause() + gomu.player.TogglePause() }) c.define("volume_up", func() { - v := volToHuman(gomu.player.volume) + v := player.VolToHuman(gomu.player.GetVolume()) if v < 100 { - vol := gomu.player.setVolume(0.5) + vol := gomu.player.SetVolume(0.5) volumePopup(vol) } }) c.define("volume_down", func() { - v := volToHuman(gomu.player.volume) + v := player.VolToHuman(gomu.player.GetVolume()) if v > 0 { - vol := gomu.player.setVolume(-0.5) + vol := gomu.player.SetVolume(-0.5) volumePopup(vol) } }) c.define("skip", func() { - gomu.player.skip() + gomu.player.Skip() }) c.define("toggle_help", func() { @@ -299,10 +300,10 @@ func (c Command) defineCommands() { }) c.define("forward", func() { - if gomu.player.isRunning && !gomu.player.ctrl.Paused { + if gomu.player.IsRunning() && !gomu.player.IsPaused() { position := gomu.playingBar.progress + 10 if position < gomu.playingBar.full { - err := gomu.player.seek(position) + err := gomu.player.Seek(position) if err != nil { logError(err) } @@ -312,16 +313,16 @@ func (c Command) defineCommands() { }) c.define("rewind", func() { - if gomu.player.isRunning && !gomu.player.ctrl.Paused { + if gomu.player.IsRunning() && !gomu.player.IsPaused() { position := gomu.playingBar.progress - 10 if position-1 > 0 { - err := gomu.player.seek(position) + err := gomu.player.Seek(position) if err != nil { logError(err) } gomu.playingBar.progress = position } else { - err := gomu.player.seek(0) + err := gomu.player.Seek(0) if err != nil { logError(err) } @@ -331,10 +332,10 @@ func (c Command) defineCommands() { }) c.define("forward_fast", func() { - if gomu.player.isRunning && !gomu.player.ctrl.Paused { + if gomu.player.IsRunning() && !gomu.player.IsPaused() { position := gomu.playingBar.progress + 60 if position < gomu.playingBar.full { - err := gomu.player.seek(position) + err := gomu.player.Seek(position) if err != nil { logError(err) } @@ -344,16 +345,16 @@ func (c Command) defineCommands() { }) c.define("rewind_fast", func() { - if gomu.player.isRunning && !gomu.player.ctrl.Paused { + if gomu.player.IsRunning() && !gomu.player.IsPaused() { position := gomu.playingBar.progress - 60 if position-1 > 0 { - err := gomu.player.seek(position) + err := gomu.player.Seek(position) if err != nil { logError(err) } gomu.playingBar.progress = position } else { - err := gomu.player.seek(0) + err := gomu.player.Seek(0) if err != nil { logError(err) } diff --git a/gomu.go b/gomu.go index e4720dd..a534e47 100644 --- a/gomu.go +++ b/gomu.go @@ -1,10 +1,12 @@ package main import ( - "github.com/issadarkthing/gomu/anko" - "github.com/issadarkthing/gomu/hook" "github.com/rivo/tview" "github.com/ztrue/tracerr" + + "github.com/issadarkthing/gomu/anko" + "github.com/issadarkthing/gomu/hook" + "github.com/issadarkthing/gomu/player" ) var VERSION = "N/A" @@ -16,7 +18,7 @@ type Gomu struct { playingBar *PlayingBar queue *Queue playlist *Playlist - player *Player + player *player.Player pages *tview.Pages colors *Colors command Command @@ -49,7 +51,7 @@ func (g *Gomu) initPanels(app *tview.Application, args Args) { g.playingBar = newPlayingBar() g.queue = newQueue() g.playlist = newPlaylist(args) - g.player = newPlayer() + g.player = player.New(g.anko.GetInt("General.volume")) g.pages = tview.NewPages() g.panels = []Panel{g.playlist, g.queue, g.playingBar} } diff --git a/player.go b/player/player.go similarity index 51% rename from player.go rename to player/player.go index 3e64f7d..1d8e69a 100644 --- a/player.go +++ b/player/player.go @@ -1,9 +1,6 @@ -// Copyright (C) 2020 Raziman - -package main +package player import ( - "fmt" "os" "time" @@ -14,30 +11,33 @@ import ( "github.com/ztrue/tracerr" ) +type Audio interface { + Name() string + Path() string +} + type Player struct { hasInit bool - isLoop bool isRunning bool volume float64 - isSkipped chan struct{} - done chan struct{} - // to control the vol internally vol *effects.Volume ctrl *beep.Ctrl format *beep.Format length time.Duration - currentSong *AudioFile + currentSong Audio streamSeekCloser beep.StreamSeekCloser - // is used to send progress - i int + + songFinish func(Audio) + songStart func(Audio) + songSkip func(Audio) } -func newPlayer() *Player { +// New returns new Player instance. +func New(volume int) *Player { - volume := gomu.anko.GetInt("General.volume") // Read initial volume from config - initVol := absVolume(volume) + initVol := AbsVolume(volume) // making sure user does not give invalid volume if volume > 100 || volume < 0 { @@ -47,28 +47,61 @@ func newPlayer() *Player { return &Player{volume: initVol} } -func (p *Player) run(currSong *AudioFile) error { +// SetSongFinish accepts callback which will be executed when the song finishes. +func (p *Player) SetSongFinish(f func(Audio)) { + p.songFinish = f +} - p.isSkipped = make(chan struct{}, 1) - f, err := os.Open(currSong.path) +// SetSongStart accepts callback which will be executed when the song starts. +func (p *Player) SetSongStart(f func(Audio)) { + p.songStart = f +} +// SetSongSkip accepts callback which will be executed when the song is skipped. +func (p *Player) SetSongSkip(f func(Audio)) { + p.songSkip = f +} + +// executes songFinish callback. +func (p *Player) execSongFinish(a Audio) { + if p.songFinish != nil { + p.songFinish(a) + } +} + +// executes songStart callback. +func (p *Player) execSongStart(a Audio) { + if p.songStart != nil { + p.songStart(a) + } +} + +// executes songFinish callback. +func (p *Player) execSongSkip(a Audio) { + if p.songSkip != nil { + p.songSkip(a) + } +} + +// Run plays the passed Audio. +func (p *Player) Run(currSong Audio) error { + + p.isRunning = true + p.execSongStart(currSong) + + f, err := os.Open(currSong.Path()) if err != nil { return tracerr.Wrap(err) } - defer f.Close() - stream, format, err := mp3.Decode(f) + if err != nil { + return tracerr.Wrap(err) + } p.streamSeekCloser = stream p.format = &format - if err != nil { - return tracerr.Wrap(err) - } - - defer stream.Close() - // song duration p.length = p.format.SampleRate.D(p.streamSeekCloser.Len()) @@ -86,18 +119,14 @@ func (p *Player) run(currSong *AudioFile) error { p.currentSong = currSong - popupMessage := fmt.Sprintf("%s\n\n[ %s ]", - currSong.name, fmtDuration(p.length)) - - defaultTimedPopup(" Current Song ", popupMessage) - // resample to adapt to sample rate of new songs resampled := beep.Resample(4, p.format.SampleRate, sr, p.streamSeekCloser) - done := make(chan struct{}, 1) - p.done = done sstreamer := beep.Seq(resampled, beep.Callback(func() { - done <- struct{}{} + p.isRunning = false + p.format = nil + p.streamSeekCloser.Close() + go p.execSongFinish(currSong) })) ctrl := &beep.Ctrl{ @@ -106,7 +135,6 @@ func (p *Player) run(currSong *AudioFile) error { } p.ctrl = ctrl - resampler := beep.ResampleRatio(4, 1, ctrl) volume := &effects.Volume{ @@ -122,94 +150,28 @@ func (p *Player) run(currSong *AudioFile) error { // starts playing the audio speaker.Play(p.vol) - gomu.hook.RunHooks("new_song") - - p.isRunning = true - - gomu.playingBar.newProgress(currSong, int(p.length.Seconds())) - - go func() { - if err := gomu.playingBar.run(); err != nil { - logError(err) - } - }() - - // is used to send progress - p.i = 0 - -next: - for { - - select { - case <-done: - if p.isLoop { - gomu.queue.enqueue(currSong) - gomu.app.Draw() - } - - p.isRunning = false - p.format = nil - gomu.playingBar.stop() - - nextSong, err := gomu.queue.dequeue() - gomu.app.Draw() - - if err != nil { - // when there are no songs to be played, set currentSong as nil - p.currentSong = nil - gomu.playingBar.setDefault() - gomu.app.Draw() - break next - } - - go func() { - if err := p.run(nextSong); err != nil { - logError(err) - } - }() - - break next - - case <-time.After(time.Second): - // stop progress bar from progressing when paused - if !p.isRunning { - continue - } - - p.i++ - if p.i >= gomu.playingBar.full { - done <- struct{}{} - continue - } - - gomu.playingBar.update <- struct{}{} - - } - - } return nil } -func (p *Player) pause() { - gomu.hook.RunHooks("pause") +// Pause pauses Player. +func (p *Player) Pause() { speaker.Lock() p.ctrl.Paused = true p.isRunning = false speaker.Unlock() } -func (p *Player) play() { - gomu.hook.RunHooks("play") +// Play unpauses Player. +func (p *Player) Play() { speaker.Lock() p.ctrl.Paused = false p.isRunning = true speaker.Unlock() - gomu.playingBar.setSongTitle(p.currentSong.name) } -// volume up and volume down using -0.5 or +0.5 -func (p *Player) setVolume(v float64) float64 { +// Volume up and volume down using -0.5 or +0.5. +func (p *Player) SetVolume(v float64) float64 { // check if no songs playing currently if p.vol == nil { @@ -224,56 +186,59 @@ func (p *Player) setVolume(v float64) float64 { return p.volume } -func (p *Player) togglePause() { +// Toggles the pause state. +func (p *Player) TogglePause() { if p.ctrl == nil { return } if p.ctrl.Paused { - p.play() + p.Play() } else { - p.pause() + p.Pause() } } -// skips current song -func (p *Player) skip() { +// Skips current song. +func (p *Player) Skip() { - gomu.hook.RunHooks("skip") + p.execSongSkip(p.currentSong) if p.currentSong == nil { return } + // drain the stream p.ctrl.Streamer = nil + p.streamSeekCloser.Close() - p.done <- struct{}{} + p.isRunning = false + p.format = nil + p.execSongFinish(p.currentSong) } -// Toggles the queue to loop -// dequeued item will be enqueued back -// function returns loop state -func (p *Player) toggleLoop() bool { - p.isLoop = !p.isLoop - return p.isLoop -} -func (p *Player) getPosition() time.Duration { +// GetPosition returns the current position of audio file. +func (p *Player) GetPosition() time.Duration { + + if p.format == nil || p.streamSeekCloser == nil { + return 1 + } + return p.format.SampleRate.D(p.streamSeekCloser.Position()) } // seek is the function to move forward and rewind -func (p *Player) seek(pos int) error { +func (p *Player) Seek(pos int) error { speaker.Lock() defer speaker.Unlock() err := p.streamSeekCloser.Seek(pos * int(p.format.SampleRate)) - p.i = pos return err } -// isPaused is used to distinguish the player between pause and stop -func (p *Player) isPaused() bool { +// IsPaused is used to distinguish the player between pause and stop +func (p *Player) IsPaused() bool { if p.ctrl == nil { return false } @@ -281,8 +246,29 @@ func (p *Player) isPaused() bool { return p.ctrl.Paused } +// GetVolume returns current volume. +func (p *Player) GetVolume() float64 { + return p.volume +} + +// GetCurrentSong returns current song. +func (p *Player) GetCurrentSong() Audio { + return p.currentSong +} + +// HasInit checks if the speaker has been initialized or not. Speaker +// initialization will only happen once. +func (p *Player) HasInit() bool { + return p.hasInit +} + +// IsRunning returns true if Player is running an audio. +func (p *Player) IsRunning() bool { + return p.isRunning +} + // Gets the length of the song in the queue -func getLength(audioPath string) (time.Duration, error) { +func GetLength(audioPath string) (time.Duration, error) { f, err := os.Open(audioPath) if err != nil { @@ -301,14 +287,14 @@ func getLength(audioPath string) (time.Duration, error) { return format.SampleRate.D(streamer.Len()), nil } -// volToHuman converts float64 volume that is used by audio library to human +// VolToHuman converts float64 volume that is used by audio library to human // readable form (0 - 100) -func volToHuman(volume float64) int { +func VolToHuman(volume float64) int { return int(volume*10) + 100 } -// absVolume converts human readable form volume (0 - 100) to float64 volume +// AbsVolume converts human readable form volume (0 - 100) to float64 volume // that is used by the audio library -func absVolume(volume int) float64 { +func AbsVolume(volume int) float64 { return (float64(volume) - 100) / 10 } diff --git a/playingbar.go b/playingbar.go index 75c7e6c..a6d90f2 100644 --- a/playingbar.go +++ b/playingbar.go @@ -67,12 +67,10 @@ func (p *PlayingBar) run() error { break } - <-p.update - p.progress++ + p.progress = int(gomu.player.GetPosition().Seconds()) + - p.text.Clear() start, err := time.ParseDuration(strconv.Itoa(p.progress) + "s") - if err != nil { return tracerr.Wrap(err) } @@ -129,20 +127,29 @@ func (p *PlayingBar) run() error { } } - p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s\n%v", - fmtDuration(start), - progressBar, - fmtDuration(end), - lyricText, - )) + gomu.app.QueueUpdateDraw(func() { + p.text.Clear() + p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s\n%v", + fmtDuration(start), + progressBar, + fmtDuration(end), + lyricText, + )) + }) + } else { - p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s", - fmtDuration(start), - progressBar, - fmtDuration(end), - )) + + gomu.app.QueueUpdateDraw(func() { + p.text.Clear() + p.text.SetText(fmt.Sprintf("%s ┃%s┫ %s", + fmtDuration(start), + progressBar, + fmtDuration(end), + )) + }) } - gomu.app.Draw() + + <-time.After(time.Second) } return nil @@ -241,7 +248,7 @@ func (p *PlayingBar) switchLyrics() { func (p *PlayingBar) delayLyric(lyricDelay int) (err error) { p.subtitle.ResyncSubs(lyricDelay) - err = embedLyric(gomu.player.currentSong.path, p.subtitle.AsSRT(), p.langLyricCurrentPlaying) + err = embedLyric(gomu.player.GetCurrentSong().Path(), p.subtitle.AsSRT(), p.langLyricCurrentPlaying) if err != nil { return tracerr.Wrap(err) } diff --git a/playlist.go b/playlist.go index d6a12da..c73bd8e 100644 --- a/playlist.go +++ b/playlist.go @@ -18,10 +18,12 @@ import ( "github.com/rivo/tview" spin "github.com/tj/go-spin" "github.com/ztrue/tracerr" + + "github.com/issadarkthing/gomu/player" ) -// AudioFile is representing directories and mp3 files -// if isAudioFile equals to false it is a directory +// AudioFile represents directories and mp3 files +// isAudioFile equals to false if it is a directory type AudioFile struct { name string path string @@ -31,6 +33,14 @@ type AudioFile struct { parent *tview.TreeNode } +func (a *AudioFile) Name() string { + return a.name +} + +func (a *AudioFile) Path() string { + return a.path +} + // Playlist struct represents playlist panel // that shows the tree of the music directory type Playlist struct { @@ -238,8 +248,8 @@ func (p *Playlist) deleteSong(audioFile *AudioFile) (err error) { // Here we remove the song from queue songPaths := gomu.queue.getItems() - if audioName == getName(gomu.player.currentSong.name) { - gomu.player.skip() + if audioName == getName(gomu.player.GetCurrentSong().Name()) { + gomu.player.Skip() } for i, songPath := range songPaths { if strings.Contains(songPath, audioName) { @@ -310,9 +320,12 @@ func (p *Playlist) addAllToQueue(root *tview.TreeNode) { for _, v := range childrens { currNode := v.GetReference().(*AudioFile) if currNode.isAudioFile { - if currNode != gomu.player.currentSong { + + currSong := gomu.player.GetCurrentSong() + if currSong == nil || (currNode.Name() != currSong.Name()) { gomu.queue.enqueue(currNode) } + } } @@ -356,7 +369,7 @@ func (p *Playlist) addSongToPlaylist( songName := getName(audioPath) node := tview.NewTreeNode(songName) - audioLength, err := getLength(audioPath) + audioLength, err := player.GetLength(audioPath) if err != nil { return tracerr.Wrap(err) } @@ -370,7 +383,7 @@ func (p *Playlist) addSongToPlaylist( parent: selPlaylist, } - displayText := setDisplayText(songName) + displayText := setDisplayText(audioFile) node.SetReference(audioFile) node.SetText(displayText) @@ -708,7 +721,7 @@ func populate(root *tview.TreeNode, rootPath string) error { parent: root, } - displayText := setDisplayText(songName) + displayText := setDisplayText(audioFile) child.SetReference(audioFile) child.SetText(displayText) @@ -726,7 +739,7 @@ func populate(root *tview.TreeNode, rootPath string) error { parent: root, } - displayText := setDisplayText(songName) + displayText := setDisplayText(audioFile) child.SetReference(audioFile) child.SetColor(gomu.colors.accent) @@ -799,14 +812,19 @@ func (p *Playlist) paste() error { return nil } -func setDisplayText(songName string) string { +func setDisplayText(audioFile *AudioFile) string { useEmoji := gomu.anko.GetBool("General.use_emoji") if !useEmoji { - return songName + return audioFile.name } - emojiFile := gomu.anko.GetString("Emoji.file") - return fmt.Sprintf(" %s %s", emojiFile, songName) + if audioFile.isAudioFile { + emojiFile := gomu.anko.GetString("Emoji.file") + return fmt.Sprintf(" %s %s", emojiFile, audioFile.name) + } + + emojiDir := gomu.anko.GetString("Emoji.playlist") + return fmt.Sprintf(" %s %s", emojiDir, audioFile.name) } // populateAudioLength is the most time consuming part of startup, @@ -815,7 +833,7 @@ func populateAudioLength(root *tview.TreeNode) error { root.Walk(func(node *tview.TreeNode, _ *tview.TreeNode) bool { audioFile := node.GetReference().(*AudioFile) if audioFile.isAudioFile { - audioLength, err := getLength(audioFile.path) + audioLength, err := player.GetLength(audioFile.path) if err != nil { logError(err) return false diff --git a/playlist_test.go b/playlist_test.go index 3f80a71..a5156fb 100644 --- a/playlist_test.go +++ b/playlist_test.go @@ -7,13 +7,14 @@ import ( "testing" "github.com/rivo/tview" + "github.com/issadarkthing/gomu/player" ) // Prepares for test func prepareTest() *Gomu { gomu := newGomu() - gomu.player = &Player{} + gomu.player = player.New(0) gomu.queue = newQueue() gomu.playlist = &Playlist{ TreeView: tview.NewTreeView(), diff --git a/popup.go b/popup.go index 94ff4e5..09bee72 100644 --- a/popup.go +++ b/popup.go @@ -18,6 +18,7 @@ import ( "github.com/issadarkthing/gomu/invidious" "github.com/issadarkthing/gomu/lyric" + "github.com/issadarkthing/gomu/player" ) // this is used to make the popup unique @@ -200,7 +201,7 @@ func defaultTimedPopup(title, description string) { // Shows popup for the current volume func volumePopup(volume float64) { - currVol := volToHuman(volume) + currVol := player.VolToHuman(volume) maxVol := 100 // max progress bar length maxLength := 50 diff --git a/queue.go b/queue.go index 6f94103..65d3f64 100644 --- a/queue.go +++ b/queue.go @@ -15,6 +15,7 @@ import ( "time" "github.com/gdamore/tcell/v2" + "github.com/issadarkthing/gomu/player" "github.com/rivo/tview" "github.com/ztrue/tracerr" ) @@ -154,19 +155,14 @@ func (q *Queue) dequeue() (*AudioFile, error) { // Add item to the list and returns the length of the queue func (q *Queue) enqueue(audioFile *AudioFile) (int, error) { - player := gomu.player + isTestEnv := os.Getenv("TEST") == "false" - if !player.isRunning && !player.isPaused() && os.Getenv("TEST") == "false" { + if !gomu.player.IsRunning() && !gomu.player.IsPaused() && isTestEnv { - gomu.player.isRunning = true - - go func() { - - if err := gomu.player.run(audioFile); err != nil { - logError(err) - } - - }() + err := gomu.player.Run(audioFile) + if err != nil { + die(err) + } return q.GetItemCount(), nil } @@ -176,7 +172,7 @@ func (q *Queue) enqueue(audioFile *AudioFile) (int, error) { } q.items = append(q.items, audioFile) - songLength, err := getLength(audioFile.path) + songLength, err := player.GetLength(audioFile.path) if err != nil { return 0, tracerr.Wrap(err) @@ -214,8 +210,8 @@ func (q *Queue) saveQueue(isQuit bool) error { songPaths := q.getItems() var content strings.Builder - if gomu.player.hasInit && isQuit && gomu.player.currentSong != nil { - currentSongPath := gomu.player.currentSong.path + if gomu.player.HasInit() && isQuit && gomu.player.GetCurrentSong() != nil { + currentSongPath := gomu.player.GetCurrentSong().Path() currentSongInQueue := false for _, songPath := range songPaths { if getName(songPath) == getName(currentSongPath) { @@ -347,7 +343,7 @@ func (q *Queue) shuffle() { q.Clear() for _, v := range q.items { - audioLen, err := getLength(v.path) + audioLen, err := player.GetLength(v.path) if err != nil { logError(err) } diff --git a/queue_test.go b/queue_test.go index c8b3067..ce54deb 100644 --- a/queue_test.go +++ b/queue_test.go @@ -91,12 +91,13 @@ func TestPushFront(t *testing.T) { gomu = prepareTest() rapPlaylist := gomu.playlist.GetRoot().GetChildren()[1] + gomu.playlist.addAllToQueue(rapPlaylist) - selSong, err := gomu.queue.deleteItem(2) + selSong, err := gomu.queue.deleteItem(2) if err != nil { - panic(err) + t.Error(err) } gomu.queue.pushFront(selSong) diff --git a/start.go b/start.go index a7cde23..d62c502 100644 --- a/start.go +++ b/start.go @@ -13,10 +13,12 @@ import ( "syscall" "github.com/gdamore/tcell/v2" - "github.com/issadarkthing/gomu/anko" - "github.com/issadarkthing/gomu/hook" "github.com/rivo/tview" "github.com/ztrue/tracerr" + + "github.com/issadarkthing/gomu/anko" + "github.com/issadarkthing/gomu/hook" + "github.com/issadarkthing/gomu/player" ) // Panel is used to keep track of childrens in slices @@ -318,6 +320,47 @@ func start(application *tview.Application, args Args) { gomu.initPanels(application, args) + gomu.player.SetSongStart(func(audio player.Audio) { + name := audio.Name() + defaultTimedPopup(" Now Playing ", name) + + duration, err := player.GetLength(audio.Path()) + if err != nil { + logError(err) + return + } + + audioFile := audio.(*AudioFile) + gomu.playingBar.newProgress(audioFile, int(duration.Seconds())) + + go func() { + err := gomu.playingBar.run() + if err != nil { + logError(err) + } + }() + }) + + gomu.player.SetSongFinish(func(_ player.Audio) { + audio, err := gomu.queue.dequeue() + if err != nil { + gomu.playingBar.setDefault() + return + } + + err = gomu.player.Run(audio) + if err != nil { + die(err) + } + + if gomu.queue.isLoop { + _, err = gomu.queue.enqueue(audio) + if err != nil { + logError(err) + } + } + }) + flex := layout(gomu) gomu.pages.AddPage("main", flex, true, true) @@ -329,8 +372,7 @@ func start(application *tview.Application, args Args) { isQueueLoop := gomu.anko.GetBool("General.queue_loop") - gomu.player.isLoop = isQueueLoop - gomu.queue.isLoop = gomu.player.isLoop + gomu.queue.isLoop = isQueueLoop loadQueue := gomu.anko.GetBool("General.load_prev_queue") @@ -427,7 +469,7 @@ func start(application *tview.Application, args Args) { init := false gomu.app.SetAfterDrawFunc(func(_ tcell.Screen) { - if !init && !gomu.player.isRunning { + if !init && !gomu.player.IsRunning() { gomu.playingBar.setDefault() init = true }