start of JukeboxPlayer backend
This commit is contained in:
@@ -148,6 +148,25 @@ type SupportsRating interface {
|
||||
SetRating(params RatingFavoriteParameters, rating int) error
|
||||
}
|
||||
|
||||
type JukeboxProvider interface {
|
||||
JukeboxStart() error
|
||||
JukeboxStop() error
|
||||
JukeboxSeek(idx, seconds int) error
|
||||
JukeboxClear() error
|
||||
JukeboxSet(trackID string) error
|
||||
JukeboxAdd(trackID string) error
|
||||
JukeboxRemove(idx int) error
|
||||
JukeboxSetVolume(vol int) error
|
||||
JukeboxGetStatus() (*JukeboxStatus, error)
|
||||
}
|
||||
|
||||
type JukeboxStatus struct {
|
||||
Volume int
|
||||
CurrentTrack int
|
||||
Playing bool
|
||||
PositionSeconds float64
|
||||
}
|
||||
|
||||
func genresMatch(filterGenres, albumGenres []string) bool {
|
||||
for _, g1 := range filterGenres {
|
||||
for _, g2 := range albumGenres {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package subsonic
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||
)
|
||||
|
||||
var _ mediaprovider.JukeboxProvider = (*subsonicMediaProvider)(nil)
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxStart() error {
|
||||
_, err := s.client.JukeboxControl("start", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxStop() error {
|
||||
_, err := s.client.JukeboxControl("stop", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxClear() error {
|
||||
_, err := s.client.JukeboxControl("clear", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxSetVolume(vol int) error {
|
||||
_, err := s.client.JukeboxControl("setGain",
|
||||
map[string]string{"gain": strconv.Itoa(vol)})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxSeek(idx, seconds int) error {
|
||||
_, err := s.client.JukeboxControl("skip",
|
||||
map[string]string{"index": strconv.Itoa(idx), "offset": strconv.Itoa(seconds)})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxRemove(idx int) error {
|
||||
_, err := s.client.JukeboxControl("remove",
|
||||
map[string]string{"index": strconv.Itoa(idx)})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxSet(trackID string) error {
|
||||
_, err := s.client.JukeboxControl("set",
|
||||
map[string]string{"id": trackID})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxAdd(trackID string) error {
|
||||
_, err := s.client.JukeboxControl("add",
|
||||
map[string]string{"id": trackID})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *subsonicMediaProvider) JukeboxGetStatus() (*mediaprovider.JukeboxStatus, error) {
|
||||
stat, err := s.client.JukeboxControl("status", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &mediaprovider.JukeboxStatus{
|
||||
Volume: int(stat.Gain * 100),
|
||||
CurrentTrack: stat.CurrentIndex,
|
||||
Playing: stat.Playing,
|
||||
PositionSeconds: float64(stat.Position),
|
||||
}, nil
|
||||
}
|
||||
@@ -229,8 +229,8 @@ func (p *PlaybackManager) LoadTracks(tracks []*mediaprovider.Track, appendToQueu
|
||||
return err
|
||||
}
|
||||
urlP.AppendFile(url)
|
||||
} else if trP, ok := p.player.(player.TrackIDPlayer); ok {
|
||||
trP.AppendTrack(tracks[i].ID)
|
||||
} else if trP, ok := p.player.(player.TrackPlayer); ok {
|
||||
trP.AppendTrack(tracks[i])
|
||||
} else {
|
||||
panic("unsupported player type")
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ require (
|
||||
github.com/deluan/sanitize v0.0.0-20230310221930-6e18967d9fc1
|
||||
github.com/dweymouth/go-jellyfin v0.0.0-20231116161116-e800860bdacc
|
||||
github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231216234924-3f62122dc53a
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231217175944-9b48c9ffc002
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/google/uuid v1.3.0
|
||||
|
||||
@@ -75,8 +75,8 @@ github.com/dweymouth/go-jellyfin v0.0.0-20231116161116-e800860bdacc h1:wJy4U12Ys
|
||||
github.com/dweymouth/go-jellyfin v0.0.0-20231116161116-e800860bdacc/go.mod h1:BMwS4vdjEYf1gmjPGSKCzWP/I6YlI6fkefJ9nsjBjaU=
|
||||
github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee h1:ZGyJ6wp7CAfT31BugypcF/TPKEy2RrGR9JFq1JOjOpY=
|
||||
github.com/dweymouth/go-mpv v0.0.0-20230406003141-7f1858e503ee/go.mod h1:Ov0ieN90M7i+0k3OxhA/g1dozGs+UcPHDsMKqPgRDk0=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231216234924-3f62122dc53a h1:UJcwloSIzRpUOIwRE207JF2SHoTmOg7vJWzfQWpztSk=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231216234924-3f62122dc53a/go.mod h1:OWtcumdQsan8uM6wmx6PqKhldaCthH10CQ+vb+94kzo=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231217175944-9b48c9ffc002 h1:DhWQZJObkCUSFmHu/eEzHRqy0R33DcR266nPAvZJE34=
|
||||
github.com/dweymouth/go-subsonic v0.0.0-20231217175944-9b48c9ffc002/go.mod h1:OWtcumdQsan8uM6wmx6PqKhldaCthH10CQ+vb+94kzo=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package jukebox
|
||||
|
||||
import (
|
||||
"github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||
"github.com/dweymouth/supersonic/player"
|
||||
)
|
||||
|
||||
const (
|
||||
stopped = 0
|
||||
playing = 1
|
||||
paused = 2
|
||||
)
|
||||
|
||||
type JukeboxPlayer struct {
|
||||
provider mediaprovider.JukeboxProvider
|
||||
|
||||
state int // stopped, playing, paused
|
||||
volume int
|
||||
seeking bool
|
||||
numTracks int
|
||||
|
||||
curTrack int
|
||||
curTrackDuration float64
|
||||
startTrackTime float64
|
||||
startedAtUnixSecs float64
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) SetVolume(vol int) error {
|
||||
go func() {
|
||||
if err := j.provider.JukeboxSetVolume(vol); err == nil {
|
||||
j.volume = vol
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) GetVolume() int {
|
||||
return j.volume
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) PlayTrackAt(idx int) error {
|
||||
go func() {
|
||||
if err := j.provider.JukeboxSeek(idx, 0); err == nil {
|
||||
j.curTrack = idx
|
||||
j.Continue()
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) Continue() error {
|
||||
if j.state == playing {
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
if err := j.provider.JukeboxStart(); err != nil {
|
||||
return
|
||||
}
|
||||
j.state = playing
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) Pause() error {
|
||||
if j.state != playing {
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
if err := j.provider.JukeboxStop(); err != nil {
|
||||
return
|
||||
}
|
||||
j.state = paused
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) Stop() error {
|
||||
if j.state == stopped {
|
||||
return nil
|
||||
}
|
||||
go func() {
|
||||
if err := j.provider.JukeboxStop(); err != nil {
|
||||
return
|
||||
}
|
||||
j.state = stopped
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) SeekPrevious() error {
|
||||
track := j.curTrack
|
||||
if track > 0 {
|
||||
track = j.curTrack - 1
|
||||
}
|
||||
return j.PlayTrackAt(track)
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) SeekNext() error {
|
||||
track := j.curTrack
|
||||
if track >= j.numTracks {
|
||||
return nil
|
||||
}
|
||||
return j.PlayTrackAt(track + 1)
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) SeekSeconds(secs float64) error {
|
||||
j.seeking = true
|
||||
go func() {
|
||||
j.provider.JukeboxSeek(j.curTrack, int(secs))
|
||||
j.seeking = false
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) IsSeeking() bool {
|
||||
return j.seeking
|
||||
}
|
||||
|
||||
func (j *JukeboxPlayer) GetStatus() player.Status {
|
||||
state := player.Stopped
|
||||
if j.state == playing {
|
||||
state = player.Playing
|
||||
} else if j.state == paused {
|
||||
state = player.Paused
|
||||
}
|
||||
|
||||
// TODO - the rest
|
||||
|
||||
return player.Status{
|
||||
State: state,
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,15 +1,15 @@
|
||||
package player
|
||||
|
||||
import "github.com/dweymouth/supersonic/backend/mediaprovider"
|
||||
|
||||
type URLPlayer interface {
|
||||
BasePlayer
|
||||
AppendFile(url string) error
|
||||
PlayFile(url string) error
|
||||
}
|
||||
|
||||
type TrackIDPlayer interface {
|
||||
type TrackPlayer interface {
|
||||
BasePlayer
|
||||
AppendTrack(trackID string) error
|
||||
PlayTrack(trackID string) error
|
||||
AppendTrack(track *mediaprovider.Track) error
|
||||
}
|
||||
|
||||
type BasePlayer interface {
|
||||
|
||||
Reference in New Issue
Block a user