diff options
| -rw-r--r-- | go.mod | 4 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | main.go | 2 | ||||
| -rw-r--r-- | mpris2client/go.mod | 5 | ||||
| -rw-r--r-- | mpris2client/go.sum | 3 | ||||
| -rw-r--r-- | mpris2client/mpris2.go | 365 | ||||
| -rwxr-xr-x | waybar-mpris | bin | 1007036 -> 1007212 bytes | 
7 files changed, 4 insertions, 377 deletions
@@ -2,12 +2,10 @@ module git.hrfee.pw/hrfee/waybar-mpris  go 1.15 -replace git.hrfee.pw/hrfee/waybar-mpris/mpris2client => ./mpris2client -  require ( -	git.hrfee.pw/hrfee/waybar-mpris/mpris2client v0.0.0-00010101000000-000000000000  	github.com/godbus/dbus/v5 v5.0.3  	github.com/hpcloud/tail v1.0.0 +	github.com/hrfee/mpris2client v0.0.0-20210108004725-d2a36745cc4a  	github.com/spf13/pflag v1.0.5  	golang.org/x/sys v0.0.0-20201116194326-cc9327a14d48 // indirect  	gopkg.in/fsnotify.v1 v1.4.7 // indirect @@ -2,6 +2,8 @@ github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=  github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=  github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=  github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/hrfee/mpris2client v0.0.0-20210108004725-d2a36745cc4a h1:3H1awMdF3eJBCg0QPpDtNW+ujQPvUCuLsqlMRoODMA4= +github.com/hrfee/mpris2client v0.0.0-20210108004725-d2a36745cc4a/go.mod h1:tVpzzAlsljmQevNA4mJwUy1onUUiaQcRAa4gdl37okY=  github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=  github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=  golang.org/x/sys v0.0.0-20200928205150-006507a75852 h1:sXxgOAXy8JwHhZnPuItAlUtwIlxrlEqi28mKhUR+zZY= @@ -11,9 +11,9 @@ import (  	"strings"  	"time" -	mpris2 "git.hrfee.pw/hrfee/waybar-mpris/mpris2client"  	"github.com/godbus/dbus/v5"  	"github.com/hpcloud/tail" +	mpris2 "github.com/hrfee/mpris2client"  	flag "github.com/spf13/pflag"  ) diff --git a/mpris2client/go.mod b/mpris2client/go.mod deleted file mode 100644 index 75c202d..0000000 --- a/mpris2client/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module git.hrfee.pw/hrfee/waybar-mpris/mpris2client - -go 1.15 - -require github.com/godbus/dbus/v5 v5.0.3 // indirect diff --git a/mpris2client/go.sum b/mpris2client/go.sum deleted file mode 100644 index 4eefd05..0000000 --- a/mpris2client/go.sum +++ /dev/null @@ -1,3 +0,0 @@ -github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= -github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= diff --git a/mpris2client/mpris2.go b/mpris2client/mpris2.go deleted file mode 100644 index e990283..0000000 --- a/mpris2client/mpris2.go +++ /dev/null @@ -1,365 +0,0 @@ -package mpris2client - -import ( -	"fmt" -	"io/ioutil" -	"sort" -	"strconv" -	"strings" - -	"github.com/godbus/dbus/v5" -) - -// Various paths and values to use elsewhere. -const ( -	INTERFACE = "org.mpris.MediaPlayer2" -	PATH      = "/org/mpris/MediaPlayer2" -	// For the NameOwnerChanged signal. -	MATCH_NOC = "type='signal',path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'" -	// For the PropertiesChanged signal. It doesn't match exactly (couldn't get that to work) so we check it manually. -	MATCH_PC = "type='signal',path='/org/mpris/MediaPlayer2',interface='org.freedesktop.DBus.Properties'" -	Refresh  = "refresh" -) - -var knownPlayers = map[string]string{ -	"plasma-browser-integration": "Browser", -	"noson":                      "Noson", -} - -var knownBrowsers = map[string]string{ -	"mozilla":  "Firefox", -	"chrome":   "Chrome", -	"chromium": "Chromium", -} - -// Player represents an active media player. -type Player struct { -	Player                                            dbus.BusObject -	FullName, Name, Title, Artist, AlbumArtist, Album string -	Position                                          int64 -	pid                                               uint32 -	Playing, Stopped                                  bool -	metadata                                          map[string]dbus.Variant -	conn                                              *dbus.Conn -	poll                                              int -	interpolate                                       bool -} - -// NewPlayer returns a new player object. -func NewPlayer(conn *dbus.Conn, name string, interpolate bool, poll int) (p *Player) { -	playerName := strings.ReplaceAll(name, INTERFACE+".", "") -	var pid uint32 -	conn.BusObject().Call("org.freedesktop.DBus.GetConnectionUnixProcessID", 0, name).Store(&pid) -	for key, val := range knownPlayers { -		if strings.Contains(name, key) { -			playerName = val -			break -		} -	} -	if playerName == "Browser" { -		file, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) -		if err == nil { -			cmd := string(file) -			for key, val := range knownBrowsers { -				if strings.Contains(cmd, key) { -					playerName = val -					break -				} -			} -		} -	} -	p = &Player{ -		Player:      conn.Object(name, PATH), -		conn:        conn, -		Name:        playerName, -		FullName:    name, -		pid:         pid, -		interpolate: interpolate, -		poll:        poll, -	} -	p.Refresh() -	return -} - -func (p *Player) String() string { -	return fmt.Sprintf("Name: %s; Playing: %t; PID: %d", p.FullName, p.Playing, p.pid) -} - -// Refresh grabs playback info. -func (p *Player) Refresh() (err error) { -	val, err := p.Player.GetProperty(INTERFACE + ".Player.PlaybackStatus") -	if err != nil { -		p.Playing = false -		p.Stopped = false -		p.metadata = map[string]dbus.Variant{} -		p.Title = "" -		p.Artist = "" -		p.AlbumArtist = "" -		p.Album = "" -		return -	} -	strVal := val.String() -	if strings.Contains(strVal, "Playing") { -		p.Playing = true -		p.Stopped = false -	} else if strings.Contains(strVal, "Paused") { -		p.Playing = false -		p.Stopped = false -	} else { -		p.Playing = false -		p.Stopped = true -	} -	metadata, err := p.Player.GetProperty(INTERFACE + ".Player.Metadata") -	if err != nil { -		p.metadata = map[string]dbus.Variant{} -		p.Title = "" -		p.Artist = "" -		p.AlbumArtist = "" -		p.Album = "" -		return -	} -	p.metadata = metadata.Value().(map[string]dbus.Variant) -	switch artist := p.metadata["xesam:artist"].Value().(type) { -	case []string: -		p.Artist = strings.Join(artist, ", ") -	case string: -		p.Artist = artist -	default: -		p.Artist = "" -	} -	switch albumArtist := p.metadata["xesam:albumArtist"].Value().(type) { -	case []string: -		p.AlbumArtist = strings.Join(albumArtist, ", ") -	case string: -		p.AlbumArtist = albumArtist -	default: -		p.AlbumArtist = "" -	} -	switch title := p.metadata["xesam:title"].Value().(type) { -	case string: -		p.Title = title -	default: -		p.Title = "" -	} -	switch album := p.metadata["xesam:album"].Value().(type) { -	case string: -		p.Album = album -	default: -		p.Album = "" -	} -	return nil -} - -func µsToString(µs int64) string { -	seconds := int(µs / 1e6) -	minutes := int(seconds / 60) -	seconds -= minutes * 60 -	return fmt.Sprintf("%02d:%02d", minutes, seconds) -} - -// StringPosition figures out the track position in MM:SS/MM:SS, interpolating the value if necessary. -func (p *Player) StringPosition() string { -	// position is in microseconds so we prob need int64 to be safe -	v := p.metadata["mpris:length"].Value() -	var l int64 -	if v != nil { -		l = v.(int64) -	} else { -		return "" -	} -	length := µsToString(l) -	if length == "" { -		return "" -	} -	pos, err := p.Player.GetProperty(INTERFACE + ".Player.Position") -	if err != nil { -		return "" -	} -	position := µsToString(pos.Value().(int64)) -	if position == "" { -		return "" -	} -	if p.interpolate && position == µsToString(p.Position) { -		np := p.Position + int64(p.poll*1e6) -		position = µsToString(np) -	} -	p.Position = pos.Value().(int64) -	return position + "/" + length -} - -// Next requests the next track. -func (p *Player) Next() { p.Player.Call(INTERFACE+".Player.Next", 0) } - -// Previous requests the previous track. -func (p *Player) Previous() { p.Player.Call(INTERFACE+".Player.Previous", 0) } - -// Toggle requests play/pause -func (p *Player) Toggle() { p.Player.Call(INTERFACE+".Player.PlayPause", 0) } - -type Message struct { -	Name, Value string -} - -type PlayerArray []*Player - -func (ls PlayerArray) Len() int { -	return len(ls) -} - -func (ls PlayerArray) Less(i, j int) bool { -	var states [2]uint8 -	for i, p := range []bool{ls[i].Playing, ls[j].Playing} { -		if p { -			states[i] = 1 -		} -	} -	// Reverse order -	return states[0] > states[1] -} - -func (ls PlayerArray) Swap(i, j int) { -	ls[i], ls[j] = ls[j], ls[i] -} - -type Mpris2 struct { -	List        PlayerArray -	Current     uint -	conn        *dbus.Conn -	Messages    chan Message -	interpolate bool -	poll        int -	autofocus   bool -	// playerctld mirrors property changes of other players, so we store its UID here to ignore it. -	playerctldUID string -} - -func NewMpris2(conn *dbus.Conn, interpolate bool, poll int, autofocus bool) *Mpris2 { -	return &Mpris2{ -		List:        PlayerArray{}, -		Current:     0, -		conn:        conn, -		Messages:    make(chan Message), -		interpolate: interpolate, -		poll:        poll, -	} -} - -// Listen should be run as a Goroutine. When players become available or are removed, an mpris2.Message is sent on mpris2.Mpris2.Messages with Name "add"/"remove" and Value as the player name. When a players state changes, a message is sent on mpris2.Mpris2.Messages with Name "refresh". -func (pl *Mpris2) Listen() { -	c := make(chan *dbus.Signal, 10) -	pl.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, MATCH_NOC) -	pl.conn.BusObject().Call("org.freedesktop.DBus.AddMatch", 0, MATCH_PC) -	pl.conn.Signal(c) -	for v := range c { -		if strings.Contains(v.Name, "NameOwnerChanged") { -			switch name := v.Body[0].(type) { -			case string: -				var pid uint32 -				pl.conn.BusObject().Call("org.freedesktop.DBus.GetConnectionUnixProcessID", 0, name).Store(&pid) -				// Ignore playerctld -				if strings.Contains(name, "playerctld") { -					// Store UID so we know to ignore it later -					pl.playerctldUID = v.Sender -				} else if strings.Contains(name, INTERFACE) { -					if pid == 0 { -						pl.Remove(name) -						pl.Messages <- Message{Name: "remove", Value: name} -					} else { -						pl.New(name) -						pl.Messages <- Message{Name: "add", Value: name} -					} -				} -			} -		} else if strings.Contains(v.Name, "PropertiesChanged") && strings.Contains(v.Body[0].(string), INTERFACE+".Player") && v.Sender != pl.playerctldUID { -			pl.Refresh() -		} -	} -} - -func (pl *Mpris2) Remove(fullName string) { -	currentName := pl.List[pl.Current].FullName -	var i int -	found := false -	for ind, p := range pl.List { -		if p.FullName == fullName { -			i = ind -			found = true -			break -		} -	} -	if !found { -		return -	} -	pl.List[0], pl.List[i] = pl.List[i], pl.List[0] -	pl.List = pl.List[1:] -	found = false -	for ind, p := range pl.List { -		if p.FullName == currentName { -			pl.Current = uint(ind) -			found = true -			break -		} -	} -	if !found { -		pl.Current = 0 -		pl.Refresh() -		//fmt.Fprintln(WRITER, pl.JSON()) -	} -} - -func (pl *Mpris2) Reload() error { -	var buses []string -	err := pl.conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&buses) -	if err != nil { -		return err -	} -	for _, name := range buses { -		// Don't add playerctld, it just duplicates other players -		if strings.Contains(name, "playerctld") { -			// Store its UID -			uid := "" -			pl.conn.BusObject().Call("org.freedesktop.DBus.GetNameOwner", 0, name).Store(&uid) -			pl.playerctldUID = uid -		} else if strings.HasPrefix(name, INTERFACE) { -			pl.New(name) -		} -	} -	return nil -} - -func (pl *Mpris2) String() string { -	resp := "" -	pad := 0 -	i := len(pl.List) -	for i != 0 { -		i /= 10 -		pad++ -	} -	for i, p := range pl.List { -		symbol := "" -		if uint(i) == pl.Current { -			symbol = "*" -		} -		resp += fmt.Sprintf("%0"+strconv.Itoa(pad)+"d", i) + symbol + ": " + p.String() + "\n" -	} -	return resp -} - -func (pl *Mpris2) New(name string) { -	pl.List = append(pl.List, NewPlayer(pl.conn, name, pl.interpolate, pl.poll)) -	if pl.autofocus { -		pl.Current = uint(len(pl.List) - 1) -	} -} - -func (pl *Mpris2) Sort() { -	sort.Sort(pl.List) -	pl.Current = 0 -} - -func (pl *Mpris2) Refresh() { -	for i := range pl.List { -		pl.List[i].Refresh() -	} -	pl.Messages <- Message{Name: "refresh", Value: ""} -} diff --git a/waybar-mpris b/waybar-mpris Binary files differindex a5c862d..8a574d7 100755 --- a/waybar-mpris +++ b/waybar-mpris  | 
