2020-08-21 13:54:32 +00:00
package main
import (
"fmt"
2020-08-31 19:37:23 +00:00
"io"
2020-08-22 18:01:51 +00:00
"log"
"net"
"os"
2020-09-06 12:13:36 +00:00
"os/signal"
2021-05-17 14:56:23 +00:00
"strconv"
2020-08-22 18:01:51 +00:00
"strings"
2020-08-26 21:10:36 +00:00
"time"
2020-08-25 13:40:56 +00:00
2021-04-24 15:02:39 +00:00
"github.com/fsnotify/fsnotify"
2020-08-25 13:40:56 +00:00
"github.com/godbus/dbus/v5"
2021-01-08 00:54:34 +00:00
mpris2 "github.com/hrfee/mpris2client"
2020-08-25 13:40:56 +00:00
flag "github.com/spf13/pflag"
2020-08-21 13:54:32 +00:00
)
2020-12-15 20:44:03 +00:00
// Various paths and values to use elsewhere.
2020-08-22 13:39:23 +00:00
const (
2021-05-17 14:56:23 +00:00
SOCK = "/tmp/waybar-mpris.sock"
LOGFILE = "/tmp/waybar-mpris.log"
OUTFILE = "/tmp/waybar-mpris.out" // Used for sharing waybar output when args are the same.
DATAFILE = "/tmp/waybar-mpris.data.out" // Used for sharing "\n"-separated player data between instances when args are different.
POLL = 1
2020-08-22 13:39:23 +00:00
)
2020-12-15 20:44:03 +00:00
// Mostly default values for flag options.
2020-08-22 14:40:24 +00:00
var (
2020-12-15 20:44:03 +00:00
PLAY = "▶"
PAUSE = ""
SEP = " - "
ORDER = "SYMBOL:ARTIST:ALBUM:TITLE:POSITION"
AUTOFOCUS = false
// Available commands that can be sent to running instances.
2021-05-17 14:56:23 +00:00
COMMANDS = [ ] string { "player-next" , "player-prev" , "next" , "prev" , "toggle" , "list" }
SHOW_POS = false
INTERPOLATE = false
REPLACE = false
isSharing = false
isDataSharing = false
WRITER io . Writer = os . Stdout
SHAREWRITER , DATAWRITER io . Writer
2020-08-22 14:40:24 +00:00
)
2021-05-17 12:43:56 +00:00
const (
cPlayerNext = "pn"
cPlayerPrev = "pp"
cNext = "mn"
cPrev = "mp"
cToggle = "mt"
cList = "ls"
cShare = "sh"
cPreShare = "ps"
2021-05-17 14:56:23 +00:00
cDataShare = "ds"
2021-05-17 12:43:56 +00:00
rSuccess = "sc"
rInvalidCommand = "iv"
2021-05-17 14:56:23 +00:00
rFailed = "fa"
2021-05-17 12:43:56 +00:00
)
func stringToCmd ( str string ) string {
switch str {
case "player-next" :
return cPlayerNext
case "player-prev" :
return cPlayerPrev
case "next" :
return cNext
case "prev" :
return cPrev
case "toggle" :
return cToggle
case "list" :
return cList
case "share" :
return cShare
2021-05-17 14:56:23 +00:00
case "data-share" :
return cDataShare
2021-05-17 12:43:56 +00:00
case "pre-share" :
return cPreShare
}
return ""
}
2021-05-17 14:56:23 +00:00
// length-µS\nposition-µS\nplaying (0 or 1)\nartist\nalbum\ntitle\nplayer\n
func fromData ( p * player , cmd string ) {
p . Duplicate = true
values := make ( [ ] string , 7 )
prev := 0
current := 0
for i := range cmd {
if current == len ( values ) {
break
}
if cmd [ i ] == '\n' {
values [ current ] = cmd [ prev : i ]
prev = i + 1
current ++
}
}
l , err := strconv . ParseInt ( values [ 0 ] , 10 , 64 )
if err != nil {
l = - 1
}
p . Length = int ( l ) / 1000000
pos , err := strconv . ParseInt ( values [ 1 ] , 10 , 64 )
if err != nil {
pos = - 1
}
p . Position = pos
if values [ 2 ] == "1" {
p . Playing = true
} else {
p . Playing = false
}
p . Artist = values [ 3 ]
p . Album = values [ 4 ]
p . Title = values [ 5 ]
p . Name = values [ 6 ]
}
func toData ( p * player ) ( cmd string ) {
cmd += strconv . FormatInt ( int64 ( p . Length * 1000000 ) , 10 ) + "\n"
cmd += strconv . FormatInt ( p . Position , 10 ) + "\n"
if p . Playing {
cmd += "1"
} else {
cmd += "0"
}
cmd += "\n"
cmd += p . Artist + "\n"
cmd += p . Album + "\n"
cmd += p . Title + "\n"
cmd += p . Name + "\n"
return
}
type player struct {
* mpris2 . Player
Duplicate bool
}
func secondsToString ( seconds int ) string {
minutes := int ( seconds / 60 )
seconds -= int ( minutes * 60 )
return fmt . Sprintf ( "%02d:%02d" , minutes , seconds )
}
2020-12-15 20:44:03 +00:00
// JSON returns json for waybar to consume.
2021-05-17 14:56:23 +00:00
func playerJSON ( p * player ) string {
2020-08-22 14:40:24 +00:00
symbol := PLAY
2021-04-24 15:37:44 +00:00
out := "{\"class\": \""
2021-01-07 16:10:20 +00:00
if p . Playing {
2020-08-22 14:40:24 +00:00
symbol = PAUSE
2021-04-24 15:37:44 +00:00
out += "playing"
} else {
out += "paused"
2020-08-22 14:40:24 +00:00
}
2020-08-26 21:10:36 +00:00
var pos string
if SHOW_POS {
2021-05-17 14:56:23 +00:00
if ! p . Duplicate {
pos = p . StringPosition ( )
if pos != "" {
pos = "(" + pos + ")"
}
} else {
pos = "(" + secondsToString ( int ( p . Position / 1000000 ) ) + "/" + secondsToString ( p . Length ) + ")"
2020-08-26 21:10:36 +00:00
}
}
2020-08-22 13:39:23 +00:00
var items [ ] string
2020-08-22 14:40:24 +00:00
order := strings . Split ( ORDER , ":" )
for _ , v := range order {
2020-12-15 20:44:03 +00:00
switch v {
case "SYMBOL" :
2020-08-22 14:40:24 +00:00
items = append ( items , symbol )
2020-12-15 20:44:03 +00:00
case "ARTIST" :
2021-01-07 16:10:20 +00:00
if p . Artist != "" {
items = append ( items , p . Artist )
2020-08-22 14:40:24 +00:00
}
2020-12-15 20:44:03 +00:00
case "ALBUM" :
2021-01-07 16:10:20 +00:00
if p . Album != "" {
items = append ( items , p . Album )
2020-08-22 14:40:24 +00:00
}
2020-12-15 20:44:03 +00:00
case "TITLE" :
2021-01-07 16:10:20 +00:00
if p . Title != "" {
items = append ( items , p . Title )
2020-08-22 14:40:24 +00:00
}
2020-12-15 20:44:03 +00:00
case "POSITION" :
if pos != "" && SHOW_POS {
2020-08-26 21:10:36 +00:00
items = append ( items , pos )
}
2021-05-16 22:28:23 +00:00
case "PLAYER" :
if p . Name != "" {
items = append ( items , p . Name )
}
2020-08-22 13:39:23 +00:00
}
}
if len ( items ) == 0 {
return "{}"
}
2020-08-22 14:40:24 +00:00
text := ""
for i , v := range items {
right := ""
2020-08-26 21:10:36 +00:00
if ( v == symbol || v == pos ) && i != len ( items ) - 1 {
2020-08-22 14:40:24 +00:00
right = " "
2020-08-26 21:10:36 +00:00
} else if i != len ( items ) - 1 && items [ i + 1 ] != symbol && items [ i + 1 ] != pos {
2020-08-22 14:40:24 +00:00
right = SEP
} else {
right = " "
}
text += v + right
}
2021-04-24 15:37:44 +00:00
out += "\",\"text\":\"" + text + "\","
2021-04-24 17:03:03 +00:00
out += "\"tooltip\":\"" + strings . ReplaceAll ( p . Title , "&" , "&" ) + "\\n"
if p . Artist != "" {
out += "by " + strings . ReplaceAll ( p . Artist , "&" , "&" ) + "\\n"
}
2021-01-07 16:10:20 +00:00
if p . Album != "" {
2021-04-24 15:37:44 +00:00
out += "from " + strings . ReplaceAll ( p . Album , "&" , "&" ) + "\\n"
2020-08-22 13:39:23 +00:00
}
2021-04-24 15:37:44 +00:00
out += "(" + p . Name + ")\"}"
return out
// return fmt.Sprintf("{\"class\":\"%s\",\"text\":\"%s\",\"tooltip\":\"%s\"}", data["class"], data["text"], data["tooltip"])
// out, err := json.Marshal(data)
// if err != nil {
// return "{}"
// }
// return string(out)
2020-08-21 13:54:32 +00:00
}
2021-01-07 16:10:20 +00:00
type players struct {
mpris2 * mpris2 . Mpris2
2020-08-22 13:39:23 +00:00
}
2021-01-07 16:10:20 +00:00
func ( pl * players ) JSON ( ) string {
if len ( pl . mpris2 . List ) != 0 {
2021-05-17 14:56:23 +00:00
return playerJSON ( & player { pl . mpris2 . List [ pl . mpris2 . Current ] , false } )
2020-08-22 13:39:23 +00:00
}
return "{}"
2020-08-21 13:54:32 +00:00
}
2021-01-07 16:10:20 +00:00
func ( pl * players ) Next ( ) { pl . mpris2 . List [ pl . mpris2 . Current ] . Next ( ) }
2020-08-22 18:01:51 +00:00
2021-01-07 16:10:20 +00:00
func ( pl * players ) Prev ( ) { pl . mpris2 . List [ pl . mpris2 . Current ] . Previous ( ) }
2020-08-22 18:01:51 +00:00
2021-01-07 16:10:20 +00:00
func ( pl * players ) Toggle ( ) { pl . mpris2 . List [ pl . mpris2 . Current ] . Toggle ( ) }
2020-08-22 18:01:51 +00:00
2021-04-24 15:02:39 +00:00
func execCommand ( cmd string ) {
conn , err := net . Dial ( "unix" , SOCK )
if err != nil {
log . Fatalln ( "Couldn't dial:" , err )
}
2021-05-17 12:43:56 +00:00
shortCmd := stringToCmd ( cmd )
_ , err = conn . Write ( [ ] byte ( shortCmd ) )
2021-04-24 15:02:39 +00:00
if err != nil {
log . Fatalln ( "Couldn't send command" )
}
fmt . Println ( "Sent." )
if cmd == "list" {
buf := make ( [ ] byte , 512 )
nr , err := conn . Read ( buf )
if err != nil {
log . Fatalln ( "Couldn't read response." )
}
response := string ( buf [ 0 : nr ] )
fmt . Println ( "Response:" )
fmt . Printf ( response )
}
os . Exit ( 0 )
}
2021-05-17 12:43:56 +00:00
func duplicateOutput ( ) error {
2021-04-24 15:02:39 +00:00
// Print to stderr to avoid errors from waybar
os . Stderr . WriteString ( "waybar-mpris is already running. This instance will clone its output." )
2021-05-17 12:43:56 +00:00
conn , err := net . Dial ( "unix" , SOCK )
if err != nil {
return err
}
_ , err = conn . Write ( [ ] byte ( cPreShare ) )
2021-04-24 15:02:39 +00:00
if err != nil {
log . Fatalf ( "Couldn't send command: %v" , err )
2021-05-17 12:43:56 +00:00
return err
2021-04-24 15:02:39 +00:00
}
buf := make ( [ ] byte , 512 )
nr , err := conn . Read ( buf )
if err != nil {
log . Fatalf ( "Couldn't read response: %v" , err )
2021-05-17 12:43:56 +00:00
return err
2021-04-24 15:02:39 +00:00
}
2021-05-17 12:43:56 +00:00
argString := ""
for _ , arg := range os . Args {
argString += arg + "|"
}
2021-05-17 14:56:23 +00:00
conn . Close ( )
conn , err = net . Dial ( "unix" , SOCK )
if err != nil {
return err
}
2021-05-17 12:43:56 +00:00
if string ( buf [ 0 : nr ] ) == argString {
// Tell other instance to share output in OUTFILE
_ , err := conn . Write ( [ ] byte ( cShare ) )
2021-04-24 15:02:39 +00:00
if err != nil {
2021-05-17 12:43:56 +00:00
log . Fatalf ( "Couldn't send command: %v" , err )
2021-04-24 15:02:39 +00:00
}
2021-05-17 14:56:23 +00:00
buf = make ( [ ] byte , 2 )
2021-05-17 12:43:56 +00:00
nr , err := conn . Read ( buf )
2021-04-24 15:02:39 +00:00
if err != nil {
2021-05-17 12:43:56 +00:00
log . Fatalf ( "Couldn't read response: %v" , err )
2021-04-24 15:02:39 +00:00
}
2021-05-17 12:43:56 +00:00
if resp := string ( buf [ 0 : nr ] ) ; resp == rSuccess {
// t, err := tail.TailFile(OUTFILE, tail.Config{
// Follow: true,
// MustExist: true,
// Logger: tail.DiscardingLogger,
// })
// if err == nil {
// for line := range t.Lines {
// fmt.Println(line.Text)
// }
// }
f , err := os . Open ( OUTFILE )
if err != nil {
log . Fatalf ( "Failed to open \"%s\": %v" , OUTFILE , err )
}
watcher , err := fsnotify . NewWatcher ( )
if err != nil {
log . Fatalf ( "Failed to start watcher: %v" , err )
}
defer watcher . Close ( )
err = watcher . Add ( OUTFILE )
if err != nil {
log . Fatalf ( "Failed to watch file: %v" , err )
}
for {
select {
case event , ok := <- watcher . Events :
if ! ok {
log . Printf ( "Watcher failed: %v" , err )
return err
2021-04-24 15:02:39 +00:00
}
2021-05-17 12:43:56 +00:00
if event . Op & fsnotify . Write == fsnotify . Write {
l , err := io . ReadAll ( f )
if err != nil {
log . Printf ( "Failed to read file: %v" , err )
return err
}
str := string ( l )
// Trim extra newline is necessary
if str [ len ( str ) - 2 : ] == "\n\n" {
fmt . Print ( str [ : len ( str ) - 1 ] )
} else {
fmt . Print ( str )
}
f . Seek ( 0 , 0 )
2021-04-24 15:02:39 +00:00
}
}
}
}
2021-05-17 14:56:23 +00:00
} else {
_ , err := conn . Write ( [ ] byte ( cDataShare ) )
if err != nil {
log . Fatalf ( "Couldn't send command: %v" , err )
}
buf = make ( [ ] byte , 2 )
nr , err := conn . Read ( buf )
if err != nil {
log . Fatalf ( "Couldn't read response: %v" , err )
}
if resp := string ( buf [ 0 : nr ] ) ; resp == rSuccess {
f , err := os . Open ( DATAFILE )
if err != nil {
log . Fatalf ( "Failed to open \"%s\": %v" , DATAFILE , err )
}
watcher , err := fsnotify . NewWatcher ( )
if err != nil {
log . Fatalf ( "Failed to start watcher: %v" , err )
}
defer watcher . Close ( )
err = watcher . Add ( DATAFILE )
if err != nil {
log . Fatalf ( "Failed to watch file: %v" , err )
}
p := & player {
& mpris2 . Player { } ,
true ,
}
for {
select {
case event , ok := <- watcher . Events :
if ! ok {
log . Printf ( "Watcher failed: %v" , err )
return err
}
if event . Op & fsnotify . Write == fsnotify . Write {
l , err := io . ReadAll ( f )
if err != nil {
log . Printf ( "Failed to read file: %v" , err )
return err
}
str := string ( l )
fromData ( p , str )
fmt . Fprintln ( WRITER , playerJSON ( p ) )
f . Seek ( 0 , 0 )
}
}
}
}
2021-04-24 15:02:39 +00:00
}
2021-05-17 12:43:56 +00:00
return nil
2021-04-24 15:02:39 +00:00
}
func listenForCommands ( players * players ) {
listener , err := net . Listen ( "unix" , SOCK )
c := make ( chan os . Signal , 1 )
signal . Notify ( c , os . Interrupt )
go func ( ) {
<- c
os . Remove ( OUTFILE )
os . Remove ( SOCK )
os . Exit ( 1 )
} ( )
if err != nil {
log . Fatalf ( "Couldn't establish socket connection at %s (error %s)\n" , SOCK , err )
}
defer func ( ) {
listener . Close ( )
os . Remove ( SOCK )
} ( )
for {
con , err := listener . Accept ( )
if err != nil {
log . Println ( "Couldn't accept:" , err )
continue
}
2021-05-17 12:43:56 +00:00
buf := make ( [ ] byte , 2 )
2021-04-24 15:02:39 +00:00
nr , err := con . Read ( buf )
if err != nil {
log . Println ( "Couldn't read:" , err )
continue
}
command := string ( buf [ 0 : nr ] )
switch command {
2021-05-17 12:43:56 +00:00
case cPlayerNext :
2021-04-24 15:02:39 +00:00
length := len ( players . mpris2 . List )
if length != 1 {
if players . mpris2 . Current < uint ( length - 1 ) {
players . mpris2 . Current ++
} else {
players . mpris2 . Current = 0
}
players . mpris2 . Refresh ( )
}
2021-05-17 12:43:56 +00:00
case cPlayerPrev :
2021-04-24 15:02:39 +00:00
length := len ( players . mpris2 . List )
if length != 1 {
if players . mpris2 . Current != 0 {
players . mpris2 . Current --
} else {
players . mpris2 . Current = uint ( length - 1 )
}
players . mpris2 . Refresh ( )
}
2021-05-17 12:43:56 +00:00
case cNext :
2021-04-24 15:02:39 +00:00
players . Next ( )
2021-05-17 12:43:56 +00:00
case cPrev :
2021-04-24 15:02:39 +00:00
players . Prev ( )
2021-05-17 12:43:56 +00:00
case cToggle :
2021-04-24 15:02:39 +00:00
players . Toggle ( )
2021-05-17 12:43:56 +00:00
case cList :
2021-04-24 15:02:39 +00:00
con . Write ( [ ] byte ( players . mpris2 . String ( ) ) )
2021-05-17 14:56:23 +00:00
case cDataShare :
if ! isDataSharing {
f , err := os . OpenFile ( DATAFILE , os . O_CREATE | os . O_WRONLY | os . O_TRUNC , 0666 )
defer f . Close ( )
if err != nil {
fmt . Fprintf ( con , "Failed: %v" , err )
}
DATAWRITER = dataWrite {
emptyEveryWrite { file : f } ,
players ,
}
if isSharing {
2021-05-21 15:03:33 +00:00
WRITER = io . MultiWriter ( os . Stdout , SHAREWRITER , DATAWRITER )
2021-05-17 14:56:23 +00:00
} else {
2021-05-21 15:03:33 +00:00
WRITER = io . MultiWriter ( os . Stdout , DATAWRITER )
2021-05-17 14:56:23 +00:00
}
isDataSharing = true
}
fmt . Fprint ( con , rSuccess )
2021-05-17 12:43:56 +00:00
case cShare :
2021-04-24 15:02:39 +00:00
if ! isSharing {
f , err := os . OpenFile ( OUTFILE , os . O_CREATE | os . O_WRONLY | os . O_TRUNC , 0666 )
defer f . Close ( )
if err != nil {
fmt . Fprintf ( con , "Failed: %v" , err )
}
2021-05-17 14:56:23 +00:00
SHAREWRITER = emptyEveryWrite { file : f }
if isDataSharing {
WRITER = io . MultiWriter ( SHAREWRITER , DATAWRITER , os . Stdout )
} else {
WRITER = io . MultiWriter ( SHAREWRITER , os . Stdout )
}
2021-04-24 15:02:39 +00:00
isSharing = true
}
2021-05-17 12:43:56 +00:00
fmt . Fprint ( con , rSuccess )
/ * Prior to sharing , the first instance sends its os . Args .
If the second instances args are different , the first sends the raw data ( artist , album , etc . )
If they are the same , the first instance just sends its output and the second prints it . * /
case cPreShare :
out := ""
for _ , arg := range os . Args {
out += arg + "|"
}
con . Write ( [ ] byte ( out ) )
2021-04-24 15:02:39 +00:00
default :
fmt . Println ( "Invalid command" )
}
2021-05-17 12:43:56 +00:00
con . Close ( )
2021-04-24 15:02:39 +00:00
}
}
2021-05-17 14:56:23 +00:00
type dataWrite struct {
emptyEveryWrite
Players * players
}
func ( w dataWrite ) Write ( p [ ] byte ) ( n int , err error ) {
line := toData ( & player { w . Players . mpris2 . List [ w . Players . mpris2 . Current ] , true } )
2021-05-24 13:51:21 +00:00
_ , err = w . emptyEveryWrite . Write ( [ ] byte ( line ) )
n = len ( p )
return
2021-05-17 14:56:23 +00:00
}
2021-04-24 15:02:39 +00:00
type emptyEveryWrite struct {
file * os . File
}
func ( w emptyEveryWrite ) Write ( p [ ] byte ) ( n int , err error ) {
2021-10-29 14:07:56 +00:00
n = len ( p )
// Set new size in case previous data was longer and would leave garbage at the end of the file.
w . file . Truncate ( int64 ( n ) )
2021-04-24 15:02:39 +00:00
offset , err := w . file . Seek ( 0 , 0 )
if err != nil {
return 0 , err
}
2021-05-24 13:51:21 +00:00
_ , err = w . file . WriteAt ( p , offset )
return
2021-04-24 15:02:39 +00:00
}
2020-08-21 13:54:32 +00:00
func main ( ) {
2020-08-31 19:37:23 +00:00
logfile , err := os . OpenFile ( LOGFILE , os . O_CREATE | os . O_APPEND | os . O_RDWR , 0666 )
if err != nil {
log . Fatalf ( "Couldn't open %s for writing: %s" , LOGFILE , err )
}
mw := io . MultiWriter ( logfile , os . Stdout )
log . SetOutput ( mw )
2020-08-22 14:40:24 +00:00
flag . StringVar ( & PLAY , "play" , PLAY , "Play symbol/text to use." )
flag . StringVar ( & PAUSE , "pause" , PAUSE , "Pause symbol/text to use." )
flag . StringVar ( & SEP , "separator" , SEP , "Separator string to use between artist, album, and title." )
2021-05-16 22:28:23 +00:00
flag . StringVar ( & ORDER , "order" , ORDER , "Element order. An extra \"PLAYER\" element is also available." )
2020-08-22 18:01:51 +00:00
flag . BoolVar ( & AUTOFOCUS , "autofocus" , AUTOFOCUS , "Auto switch to currently playing music players." )
2020-08-26 21:10:36 +00:00
flag . BoolVar ( & SHOW_POS , "position" , SHOW_POS , "Show current position between brackets, e.g (04:50/05:00)" )
2020-09-14 15:14:30 +00:00
flag . BoolVar ( & INTERPOLATE , "interpolate" , INTERPOLATE , "Interpolate track position (helpful for players that don't update regularly, e.g mpDris2)" )
2020-09-28 22:48:51 +00:00
flag . BoolVar ( & REPLACE , "replace" , REPLACE , "replace existing waybar-mpris if found. When false, new instance will clone the original instances output." )
2020-08-22 18:01:51 +00:00
var command string
flag . StringVar ( & command , "send" , "" , "send command to already runnning waybar-mpris instance. (options: " + strings . Join ( COMMANDS , "/" ) + ")" )
2020-09-28 22:48:51 +00:00
2020-08-22 14:40:24 +00:00
flag . Parse ( )
2020-11-16 21:59:31 +00:00
os . Stderr = logfile
2020-08-22 14:40:24 +00:00
2020-08-22 18:01:51 +00:00
if command != "" {
2021-04-24 15:02:39 +00:00
execCommand ( command )
2020-08-31 19:14:14 +00:00
}
// fmt.Println("New array", players)
// Start command listener
if _ , err := os . Stat ( SOCK ) ; err == nil {
2020-09-28 22:48:51 +00:00
if REPLACE {
fmt . Printf ( "Socket %s already exists, this could mean waybar-mpris is already running.\nStarting this instance will overwrite the file, possibly stopping other instances from accepting commands.\n" , SOCK )
var input string
ignoreChoice := false
fmt . Printf ( "Continue? [y/n]: " )
go func ( ) {
fmt . Scanln ( & input )
if strings . Contains ( input , "y" ) && ! ignoreChoice {
os . Remove ( SOCK )
}
} ( )
time . Sleep ( 5 * time . Second )
if input == "" {
fmt . Printf ( "\nRemoving due to lack of input.\n" )
ignoreChoice = true
// os.Remove(SOCK)
2020-08-31 19:14:14 +00:00
}
2020-09-28 22:48:51 +00:00
// When waybar-mpris is already running, we attach to its output instead of launching a whole new instance.
2021-05-17 12:43:56 +00:00
} else if err := duplicateOutput ( ) ; err != nil {
os . Stdout . WriteString ( "Couldn't dial socket, deleting instead: " + err . Error ( ) )
2020-08-31 19:14:14 +00:00
os . Remove ( SOCK )
2020-09-28 22:48:51 +00:00
os . Remove ( OUTFILE )
2020-08-22 18:01:51 +00:00
}
2020-08-31 19:14:14 +00:00
}
2021-01-07 16:10:20 +00:00
conn , err := dbus . SessionBus ( )
if err != nil {
log . Fatalln ( "Error connecting to DBus:" , err )
}
players := & players {
mpris2 : mpris2 . NewMpris2 ( conn , INTERPOLATE , POLL , AUTOFOCUS ) ,
}
players . mpris2 . Reload ( )
players . mpris2 . Sort ( )
lastLine := ""
2021-04-24 15:02:39 +00:00
go listenForCommands ( players )
2021-01-07 16:10:20 +00:00
go players . mpris2 . Listen ( )
2020-08-31 19:14:14 +00:00
if SHOW_POS {
go func ( ) {
for {
2020-09-14 15:14:30 +00:00
time . Sleep ( POLL * time . Second )
2021-01-07 16:10:20 +00:00
if len ( players . mpris2 . List ) != 0 {
if players . mpris2 . List [ players . mpris2 . Current ] . Playing {
2020-09-28 22:48:51 +00:00
go fmt . Fprintln ( WRITER , players . JSON ( ) )
2020-09-06 12:13:36 +00:00
}
2020-08-26 21:10:36 +00:00
}
2020-08-31 19:14:14 +00:00
}
} ( )
}
2021-01-07 16:10:20 +00:00
fmt . Fprintln ( WRITER , players . JSON ( ) )
for v := range players . mpris2 . Messages {
if v . Name == "refresh" {
2020-08-31 19:14:14 +00:00
if AUTOFOCUS {
2021-01-07 16:10:20 +00:00
players . mpris2 . Sort ( )
2020-08-31 19:14:14 +00:00
}
if l := players . JSON ( ) ; l != lastLine {
lastLine = l
2020-09-28 22:48:51 +00:00
fmt . Fprintln ( WRITER , l )
2020-08-22 14:40:24 +00:00
}
2020-08-21 14:44:59 +00:00
}
2020-08-21 13:54:32 +00:00
}
2021-01-07 16:10:20 +00:00
players . mpris2 . Refresh ( )
2020-08-21 13:54:32 +00:00
}