mirror of
https://github.com/issadarkthing/gomu.git
synced 2025-04-28 13:48:53 +08:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0150f6b3da
37
command.go
37
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)
|
||||
}
|
||||
|
10
gomu.go
10
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}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
46
playlist.go
46
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
|
||||
|
@ -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(),
|
||||
|
3
popup.go
3
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
|
||||
|
26
queue.go
26
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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
52
start.go
52
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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user