diff --git a/backend/app.go b/backend/app.go index acb6948..b1d1366 100644 --- a/backend/app.go +++ b/backend/app.go @@ -37,6 +37,7 @@ type App struct { PlaybackManager *PlaybackManager Player *player.Player UpdateChecker UpdateChecker + MPRISHandler *MPRISHandler OnReactivate func() appName string @@ -103,6 +104,9 @@ func StartupApp(appName, appVersionTag, configFile, latestReleaseURL string) (*A _, _ = a.ImageManager.GetCoverThumbnail(coverID) }) + a.MPRISHandler = NewMPRISHandler(a.Player, a.PlaybackManager) + a.MPRISHandler.Start() + return a, nil } @@ -221,6 +225,7 @@ func (a *App) DeleteServerCacheDir(serverID uuid.UUID) error { } func (a *App) Shutdown() { + a.MPRISHandler.Shutdown() a.PlaybackManager.DisableCallbacks() a.Player.Stop() // will trigger scrobble check a.Config.LocalPlayback.Volume = a.Player.GetVolume() diff --git a/backend/mpris.go b/backend/mpris.go new file mode 100644 index 0000000..3ecf1c8 --- /dev/null +++ b/backend/mpris.go @@ -0,0 +1,172 @@ +package backend + +import ( + "errors" + + "github.com/dweymouth/supersonic/player" + "github.com/quarckster/go-mpris-server/pkg/events" + "github.com/quarckster/go-mpris-server/pkg/server" + "github.com/quarckster/go-mpris-server/pkg/types" +) + +var ( + _ types.OrgMprisMediaPlayer2Adapter = (*MPRISHandler)(nil) + _ types.OrgMprisMediaPlayer2PlayerAdapter = (*MPRISHandler)(nil) +) +var ( + notImplemented = errors.New("not implemented") +) + +type MPRISHandler struct { + p *player.Player + pm *PlaybackManager + s *server.Server + evt *events.EventHandler +} + +func NewMPRISHandler(p *player.Player, pm *PlaybackManager) *MPRISHandler { + m := &MPRISHandler{p: p, pm: pm} + m.s = server.NewServer("Supersonic", m, m) + m.evt = events.NewEventHandler(m.s) + return m +} + +func (m *MPRISHandler) Start() { + go m.s.Listen() +} + +func (m *MPRISHandler) Shutdown() { + m.s.Stop() +} + +// OrgMprisMediaPlayer2Adapter implementation + +func (m *MPRISHandler) Identity() (string, error) { + return "supersonic", nil +} + +func (m *MPRISHandler) CanQuit() (bool, error) { + return false, nil +} + +func (m *MPRISHandler) Quit() error { + return errors.New("not implemented") +} + +func (m *MPRISHandler) CanRaise() (bool, error) { + return false, nil +} + +func (m *MPRISHandler) Raise() error { + return errors.New("not implemented") +} + +func (m *MPRISHandler) HasTrackList() (bool, error) { + return false, nil +} + +func (m *MPRISHandler) SupportedUriSchemes() ([]string, error) { + return nil, nil +} + +func (m *MPRISHandler) SupportedMimeTypes() ([]string, error) { + return nil, nil +} + +// OrgMprisMediaPlayer2PlayerAdapter implementation + +func (m *MPRISHandler) Next() error { + return m.p.SeekNext() +} + +func (m *MPRISHandler) Previous() error { + return m.p.SeekBackOrPrevious() +} + +func (m *MPRISHandler) Pause() error { + return notImplemented +} + +func (m *MPRISHandler) PlayPause() error { + return m.p.PlayPause() +} + +func (m *MPRISHandler) Stop() error { + return notImplemented +} + +func (m *MPRISHandler) Play() error { + return notImplemented +} + +func (m *MPRISHandler) Seek(offset types.Microseconds) error { + return notImplemented +} + +func (m *MPRISHandler) SetPosition(trackId string, position types.Microseconds) error { + return notImplemented +} + +func (m *MPRISHandler) OpenUri(uri string) error { + return notImplemented +} + +func (m *MPRISHandler) PlaybackStatus() (types.PlaybackStatus, error) { + return "", notImplemented +} + +func (m *MPRISHandler) Rate() (float64, error) { + return 0, notImplemented +} + +func (m *MPRISHandler) SetRate(float64) error { + return notImplemented +} + +func (m *MPRISHandler) Metadata() (types.Metadata, error) { + return types.Metadata{}, notImplemented +} + +func (m *MPRISHandler) Volume() (float64, error) { + return 0, notImplemented +} + +func (m *MPRISHandler) SetVolume(float64) error { + return notImplemented +} + +func (m *MPRISHandler) Position() (int64, error) { + return 0, notImplemented +} + +func (m *MPRISHandler) MinimumRate() (float64, error) { + return 0, notImplemented +} + +func (m *MPRISHandler) MaximumRate() (float64, error) { + return 0, notImplemented +} + +func (m *MPRISHandler) CanGoNext() (bool, error) { + return false, notImplemented +} + +func (m *MPRISHandler) CanGoPrevious() (bool, error) { + return false, notImplemented +} + +func (m *MPRISHandler) CanPlay() (bool, error) { + return false, notImplemented +} + +func (m *MPRISHandler) CanPause() (bool, error) { + return false, notImplemented +} + +func (m *MPRISHandler) CanSeek() (bool, error) { + return false, notImplemented +} + +func (m *MPRISHandler) CanControl() (bool, error) { + return false, notImplemented +} diff --git a/go.mod b/go.mod index e427fcf..58c4d55 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/quarckster/go-mpris-server v1.0.0 // indirect github.com/srwiley/oksvg v0.0.0-20220731023508-a61f04f16b76 // indirect github.com/srwiley/rasterx v0.0.0-20210519020934-456a8d69b780 // indirect github.com/stretchr/testify v1.8.3 // indirect diff --git a/go.sum b/go.sum index 5420507..0087109 100644 --- a/go.sum +++ b/go.sum @@ -265,6 +265,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/quarckster/go-mpris-server v1.0.0 h1:9EKh8Ink7d3OigBLXGlRJ0jDJi+O6T/XMroA5Gl4c5Q= +github.com/quarckster/go-mpris-server v1.0.0/go.mod h1:2b4IdrpnEoEfU+6fQKjYhAgdvsiz4JxmTpDAUrMJVO4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=