pax_global_header00006660000000000000000000000064137563305160014523gustar00rootroot0000000000000052 comment=125634cc82c20948b36dd362ec344dd73f1f3b1f go-mpris-1.4.0/000077500000000000000000000000001375633051600132625ustar00rootroot00000000000000go-mpris-1.4.0/.gitignore000066400000000000000000000004121375633051600152470ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof go-mpris-1.4.0/LICENSE000066400000000000000000000020641375633051600142710ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2015 emersion Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-mpris-1.4.0/README.md000066400000000000000000000020451375633051600145420ustar00rootroot00000000000000# GO-MPRIS A Go library for MPRIS. ## Install > $ go get github.com/Pauloo27/go-mpris _the dependency github.com/godbus/dbus/v5 is going to be installed as well._ ## Example Printing the current playback status and then changing it: ```go import ( "log" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func main() { conn, err := dbus.SessionBus() if err != nil { panic(err) } names, err := mpris.List(conn) if err != nil { panic(err) } if len(names) == 0 { log.Fatal("No player found") } name := names[0] player := mpris.New(conn, name) status, err := player.GetPlaybackStatus() if err != nil { log.Fatal("Could not get current playback status") } log.Printf("The player was %s...", status) err = player.PlayPause() if err != nil { log.Fatal("Could not play/pause player") } } ``` **For more examples, see the [examples folder](./examples).** ## Go Docs Read the docs at https://pkg.go.dev/github.com/Pauloo27/go-mpris. ## Credits [emersion](https://github.com/emersion/go-mpris) for the original code. go-mpris-1.4.0/examples/000077500000000000000000000000001375633051600151005ustar00rootroot00000000000000go-mpris-1.4.0/examples/playpause.go000066400000000000000000000011341375633051600174310ustar00rootroot00000000000000package main import ( "log" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func main() { conn, err := dbus.SessionBus() if err != nil { panic(err) } names, err := mpris.List(conn) if err != nil { panic(err) } if len(names) == 0 { log.Fatal("No player found") } name := names[0] player := mpris.New(conn, name) status, err := player.GetPlaybackStatus() if err != nil { log.Fatal("Could not get current playback status") } log.Printf("The player was %s...", status) err = player.PlayPause() if err != nil { log.Fatal("Could not play/pause player") } } go-mpris-1.4.0/examples/raise.go000066400000000000000000000011061375633051600165300ustar00rootroot00000000000000package main import ( "log" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func main() { conn, err := dbus.SessionBus() if err != nil { panic(err) } names, err := mpris.List(conn) if err != nil { panic(err) } if len(names) == 0 { log.Fatal("No media player found.") } name := names[0] log.Println("Found media player:", name) player := mpris.New(conn, name) identity, err := player.GetIdentity() if err != nil { panic(err) } log.Println("Media player identity:", identity) err = player.Raise() if err != nil { panic(err) } } go-mpris-1.4.0/examples/signal.go000066400000000000000000000007421375633051600167070ustar00rootroot00000000000000package main import ( "log" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func main() { conn, err := dbus.SessionBus() if err != nil { panic(err) } names, err := mpris.List(conn) if err != nil { panic(err) } if len(names) == 0 { log.Fatal("No player found") } name := names[0] player := mpris.New(conn, name) ch := make(chan *dbus.Signal) err := player.OnSignal(ch) if err != nil { panic(err) } sig := <-ch fmt.Println(sig.Body) } go-mpris-1.4.0/examples/volume.go000066400000000000000000000010241375633051600167330ustar00rootroot00000000000000package main import ( "log" "github.com/Pauloo27/go-mpris" "github.com/godbus/dbus/v5" ) func main() { conn, err := dbus.SessionBus() if err != nil { panic(err) } names, err := mpris.List(conn) if err != nil { panic(err) } if len(names) == 0 { log.Fatal("No player found") } name := names[0] player := mpris.New(conn, name) volume, err := player.GetVolume() if err != nil { log.Fatal("Could not get current volume") } log.Printf("The player volume is %f...", volume) player.SetVolume(volume - 0.1) } go-mpris-1.4.0/go.mod000066400000000000000000000001341375633051600143660ustar00rootroot00000000000000module github.com/Pauloo27/go-mpris go 1.14 require ( github.com/godbus/dbus/v5 v5.0.3 ) go-mpris-1.4.0/go.sum000066400000000000000000000002511375633051600144130ustar00rootroot00000000000000github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= go-mpris-1.4.0/mpris.go000066400000000000000000000221251375633051600147450ustar00rootroot00000000000000package mpris import ( "fmt" "strings" "github.com/godbus/dbus/v5" ) const ( dbusObjectPath = "/org/mpris/MediaPlayer2" propertiesChangedSignal = "org.freedesktop.DBus.Properties.PropertiesChanged" BaseInterface = "org.mpris.MediaPlayer2" PlayerInterface = "org.mpris.MediaPlayer2.Player" TrackListInterface = "org.mpris.MediaPlayer2.TrackList" PlaylistsInterface = "org.mpris.MediaPlayer2.Playlists" getPropertyMethod = "org.freedesktop.DBus.Properties.Get" setPropertyMethod = "org.freedesktop.DBus.Properties.Set" ) func getProperty(obj *dbus.Object, iface string, prop string) (dbus.Variant, error) { result := dbus.Variant{} err := obj.Call(getPropertyMethod, 0, iface, prop).Store(&result) if err != nil { return dbus.Variant{}, err } return result, nil } func setProperty(obj *dbus.Object, iface string, prop string, val interface{}) error { call := obj.Call(setPropertyMethod, 0, iface, prop, dbus.MakeVariant(val)) return call.Err } func convertToMicroseconds(seconds float64) int64 { return int64(seconds * 1000000) } func convertToSeconds(microseconds int64) float64 { return float64(microseconds) / 1000000.0 } // List lists the available players. func List(conn *dbus.Conn) ([]string, error) { var names []string err := conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&names) if err != nil { return nil, err } var mprisNames []string for _, name := range names { if strings.HasPrefix(name, BaseInterface) { mprisNames = append(mprisNames, name) } } return mprisNames, nil } // Player represents a mpris player. type Player struct { conn *dbus.Conn obj *dbus.Object name string } // Raise raises player priority. func (i *Player) Raise() error { return i.obj.Call(BaseInterface+".Raise", 0).Err } // Quit closes the player. func (i *Player) Quit() error { return i.obj.Call(BaseInterface+".Quit", 0).Err } // GetIdentity returns the player identity. func (i *Player) GetIdentity() (string, error) { value, err := getProperty(i.obj, BaseInterface, "Identity") return value.Value().(string), err } // Next skips to the next track in the tracklist. func (i *Player) Next() error { return i.obj.Call(PlayerInterface+".Next", 0).Err } // Previous skips to the previous track in the tracklist. func (i *Player) Previous() error { return i.obj.Call(PlayerInterface+".Previous", 0).Err } // Pause pauses the current track. func (i *Player) Pause() error { return i.obj.Call(PlayerInterface+".Pause", 0).Err } // PlayPause resumes the current track if it's paused and pauses it if it's playing. func (i *Player) PlayPause() error { return i.obj.Call(PlayerInterface+".PlayPause", 0).Err } // Stop stops the current track. func (i *Player) Stop() error { return i.obj.Call(PlayerInterface+".Stop", 0).Err } // Play starts or resumes the current track. func (i *Player) Play() error { return i.obj.Call(PlayerInterface+".Play", 0).Err } // Seek seeks the current track position by the offset. The offset should be in seconds. // If the offset is negative it's seeked back. func (i *Player) Seek(offset float64) error { return i.obj.Call(PlayerInterface+".Seek", 0, convertToMicroseconds(offset)).Err } // SetTrackPosition sets the position of a track. The position should be in seconds. func (i *Player) SetTrackPosition(trackId *dbus.ObjectPath, position float64) error { return i.obj.Call(PlayerInterface+".SetPosition", 0, trackId, convertToMicroseconds(position)).Err } // OpenUri opens and plays the uri if supported. func (i *Player) OpenUri(uri string) error { return i.obj.Call(PlayerInterface+".OpenUri", 0, uri).Err } // PlaybackStatus the status of the playback. It can be "Playing", "Paused" or "Stopped". type PlaybackStatus string const ( PlaybackPlaying PlaybackStatus = "Playing" PlaybackPaused PlaybackStatus = "Paused" PlaybackStopped PlaybackStatus = "Stopped" ) // GetPlaybackStatus gets the playback status. func (i *Player) GetPlaybackStatus() (PlaybackStatus, error) { variant, err := i.obj.GetProperty(PlayerInterface + ".PlaybackStatus") if err != nil { return "", err } if variant.Value() == nil { return "", fmt.Errorf("Variant value is nil") } return PlaybackStatus(variant.Value().(string)), nil } // LoopStatus the status of the player loop. It can be "None", "Track" or "Playlist". type LoopStatus string const ( LoopNone LoopStatus = "None" LoopTrack LoopStatus = "Track" LoopPlaylist LoopStatus = "Playlist" ) // GetLoopStatus returns the loop status. func (i *Player) GetLoopStatus() (LoopStatus, error) { variant, err := getProperty(i.obj, PlayerInterface, "LoopStatus") if err != nil { return LoopStatus(""), err } if variant.Value() == nil { return "", fmt.Errorf("Variant value is nil") } return LoopStatus(variant.Value().(string)), nil } // SetLoopStatus sets the loop status to loopStatus. func (i *Player) SetLoopStatus(loopStatus LoopStatus) error { return i.SetPlayerProperty("LoopStatus", loopStatus) } // SetProperty sets the value of a propertyName in the targetInterface. func (i *Player) SetProperty(targetInterface, propertyName string, value interface{}) error { return setProperty(i.obj, targetInterface, propertyName, value) } // SetPlayerProperty sets the propertyName from the player interface. func (i *Player) SetPlayerProperty(propertyName string, value interface{}) error { return setProperty(i.obj, PlayerInterface, propertyName, value) } // GetProperty returns the properityName in the targetInterface. func (i *Player) GetProperty(targetInterface, properityName string) (dbus.Variant, error) { return getProperty(i.obj, targetInterface, properityName) } // GetPlayerProperty returns the properityName from the player interface. func (i *Player) GetPlayerProperty(properityName string) (dbus.Variant, error) { return getProperty(i.obj, PlayerInterface, properityName) } // Returns the current playback rate. func (i *Player) GetRate() (float64, error) { variant, err := getProperty(i.obj, PlayerInterface, "Rate") if err != nil { return 0.0, err } if variant.Value() == nil { return 0.0, fmt.Errorf("Variant value is nil") } return variant.Value().(float64), nil } // GetShuffle returns false if the player is going linearly through a playlist and false if it's // in some other order. func (i *Player) GetShuffle() (bool, error) { variant, err := getProperty(i.obj, PlayerInterface, "Shuffle") if err != nil { return false, err } if variant.Value() == nil { return false, fmt.Errorf("Variant value is nil") } return variant.Value().(bool), nil } // SetShuffle sets the shuffle playlist mode. func (i *Player) SetShuffle(value bool) error { return setProperty(i.obj, PlayerInterface, "Shuffle", value) } // GetMetadata returns the metadata. func (i *Player) GetMetadata() (map[string]dbus.Variant, error) { variant, err := getProperty(i.obj, PlayerInterface, "Metadata") if err != nil { return nil, err } if variant.Value() == nil { return nil, fmt.Errorf("Variant value is nil") } return variant.Value().(map[string]dbus.Variant), nil } // GetVolume returns the volume. func (i *Player) GetVolume() (float64, error) { variant, err := getProperty(i.obj, PlayerInterface, "Volume") if err != nil { return 0.0, err } if variant.Value() == nil { return 0.0, fmt.Errorf("Variant value is nil") } return variant.Value().(float64), nil } // SetVolume sets the volume. func (i *Player) SetVolume(volume float64) error { return setProperty(i.obj, PlayerInterface, "Volume", volume) } // GetLength returns the current track length in seconds. func (i *Player) GetLength() (float64, error) { metadata, err := i.GetMetadata() if err != nil { return 0.0, err } if metadata == nil || metadata["mpris:length"].Value() == nil { return 0.0, fmt.Errorf("Variant value is nil") } return convertToSeconds(metadata["mpris:length"].Value().(int64)), nil } // GetPosition returns the position in seconds of the current track. func (i *Player) GetPosition() (float64, error) { variant, err := getProperty(i.obj, PlayerInterface, "Position") if err != nil { return 0.0, err } if variant.Value() == nil { return 0.0, fmt.Errorf("Variant value is nil") } return convertToSeconds(variant.Value().(int64)), nil } // SetPosition sets the position of the current track. The position should be in seconds. func (i *Player) SetPosition(position float64) error { metadata, err := i.GetMetadata() if err != nil { return err } if metadata == nil || metadata["mpris:trackid"].Value() == nil { return fmt.Errorf("Variant value is nil") } trackId := metadata["mpris:trackid"].Value().(dbus.ObjectPath) i.SetTrackPosition(&trackId, position) return nil } // New connects the the player with the name in the connection conn. func New(conn *dbus.Conn, name string) *Player { obj := conn.Object(name, dbusObjectPath).(*dbus.Object) return &Player{conn, obj, name} } // OnSignal adds a handler to the player's properties change signal. func (i *Player) OnSignal(ch chan<- *dbus.Signal) (err error) { err = i.conn.AddMatchSignal( dbus.WithMatchSender(i.name), dbus.WithMatchObjectPath(i.obj.Path()), dbus.WithMatchInterface("org.freedesktop.DBus.Properties"), ) if err != nil { return } i.conn.Signal(ch) return } go-mpris-1.4.0/mpris_test.go000066400000000000000000000032001375633051600157750ustar00rootroot00000000000000package mpris import ( "testing" "time" "github.com/godbus/dbus/v5" ) func checkVolume(t *testing.T, player *Player) { volume, err := player.GetVolume() if err != nil { t.Error(err) return } t.Logf("Current player volume %f", volume) player.SetVolume(0.5) time.Sleep(1 * time.Second) player.SetVolume(volume) } func checkPlayback(t *testing.T, player *Player) { status, err := player.GetPlaybackStatus() if err != nil { t.Error(err) return } if status != PlaybackPlaying && status != PlaybackStopped && status != PlaybackPaused { t.Errorf("%s is not a valid playback status", status) } else { t.Logf("Player playback status is %s", status) } } func checkLoop(t *testing.T, player *Player) { loopStatus, err := player.GetLoopStatus() if err != nil { t.Error(err) return } if loopStatus != LoopNone && loopStatus != LoopTrack && loopStatus != LoopPlaylist { t.Errorf("%s is not a valid loop status", loopStatus) } else { t.Logf("Players loop status is %s", loopStatus) } err = player.SetLoopStatus(LoopTrack) if err != nil { t.Error(err) return } player.SetLoopStatus(loopStatus) } func TestPlayer(t *testing.T) { conn, err := dbus.SessionBus() if err != nil { t.Error(err) return } names, err := List(conn) if err != nil { t.Error(err) return } if len(names) == 0 { t.Error("No players found") return } name := names[0] t.Logf("Found player %s", name) player := New(conn, name) t.Run("Playback", func(t *testing.T) { checkPlayback(t, player) }) t.Run("Loop", func(t *testing.T) { checkLoop(t, player) }) t.Run("Volume", func(t *testing.T) { checkVolume(t, player) }) }