I'm using libvlc
(go binding) to play music in a TUI. Instead of using the media_list_player
, which has Next
and Previous
methods, I followed the advice of this answer https://stackoverflow.com/a/44647523/4443226 to use the regular media_player
and a loop:
import vlc
import time
my_list = ['vp1.mp3','happy.mp3']
instance = vlc.Instance()
player = instance.media_player_new()
playing = set([1,2,3,4])
for i in my_list:
player.set_mrl(i)
player.play()
play=True
while play == True:
time.sleep(1)
play_state = player.get_state()
if play_state in playing:
continue
else:
play = False
This has the benefit that I can get the index of the current song and I can get the position and duration of the current playing song.
I implemented it in Go, and one of the problems, is that I am unable to implement (effectively) Next
and Previous
song.
Part of the problem is that this playback loop must be in a separate goroutine
than the UI thread. I use chan
to send signals for stopping the goroutine
and skipping the song.
func playAlbum(p *vlc.Player, a Album, l *tui.List, s *tui.StatusBar, done, next, prev chan struct{}) (err error) {
playlist := make([]*vlc.Media, 0)
for _, path := range a.Paths {
media, err := vlc.NewMediaFromPath(path)
// check eturn err
playlist = append(playlist, media)
}
for idx := range playlist {
p.SetMedia(playlist[idx])
err = p.Play()
// check return err
status, err := p.MediaState()
// check return err
PlaybackLoop:
for status != vlc.MediaEnded {
status, err = p.MediaState()
// continue with err
l.SetSelected(idx) // TUI list of songs
song := songStatus(a, l.Selected())
s.SetPermanentText(song) // TUI status bar
select {
case <-next:
break PlaybackLoop
case <-prev:
continue // TODO: implement previous
case <-done:
return err
default:
time.Sleep(50 * time.Millisecond)
}
}
}
return err
}
I am unable to implement Previous
, because I can't just go back in the for loop.
Ideally I think I would like to use the libvlc
media_list_player
. However, if I can't get the song duration and length as well as the index of the song in the media_list
, I would rather do this method.
If I must use the media_player
instead, is there a better way to handle playback than using nested loops and channels? Something that can use previous?
Based on the comments and discussion with the OP It was determined that a linked list was probably the best route in trying to control how to go forward and backwards with a bit less effort. Since Go is being used and the modules that are being used require goroutines the linked list also would have to be safe to use within goroutines.