diff --git a/config/config.go b/config/config.go index 83921f4..631224b 100644 --- a/config/config.go +++ b/config/config.go @@ -14,6 +14,7 @@ import ( type ConfigS struct { FPSCounter bool + ShowMPRIS bool TargetFPS int32 WindowWidth int32 WindowHeight int32 @@ -29,6 +30,7 @@ type ConfigS struct { var DefaultConfig = ConfigS{ FPSCounter: false, + ShowMPRIS: true, TargetFPS: 60, WindowWidth: 1080, WindowHeight: 1080, @@ -45,6 +47,8 @@ var DefaultConfig = ConfigS{ var Config ConfigS var AccentColor color.RGBA +var FirstColor color.RGBA +var ThirdColor color.RGBA func Init() { configPath := configdir.LocalConfig("ontake", "xyosc") @@ -78,6 +82,8 @@ func Init() { walFile := filepath.Join(walPath, "colors") if _, err = os.Stat(walFile); os.IsNotExist(err) { AccentColor = color.RGBA{255, 0, 0, Config.LineOpacity} + FirstColor = color.RGBA{255, 120, 120, Config.LineOpacity} + ThirdColor = color.RGBA{255, 0, 0, Config.LineOpacity} } else { fh, err := os.Open(walFile) utils.CheckError(err) @@ -86,17 +92,26 @@ func Init() { var line int var rgbaColor color.RGBA for scanner.Scan() { + if line == 0 { + rgbaColor, err = ParseHexColor(scanner.Text()) + utils.CheckError(err) + FirstColor = color.RGBA{rgbaColor.R, rgbaColor.G, rgbaColor.B, Config.LineOpacity} + } if line == 1 { rgbaColor, err = ParseHexColor(scanner.Text()) utils.CheckError(err) + AccentColor = color.RGBA{rgbaColor.R, rgbaColor.G, rgbaColor.B, Config.LineOpacity} + } + if line == 2 { + rgbaColor, err = ParseHexColor(scanner.Text()) + utils.CheckError(err) + ThirdColor = color.RGBA{rgbaColor.R, rgbaColor.G, rgbaColor.B, Config.LineOpacity} break } line++ } - AccentColor = color.RGBA{rgbaColor.R, rgbaColor.G, rgbaColor.B, Config.LineOpacity} } - fmt.Println(AccentColor) } func ParseHexColor(s string) (c color.RGBA, err error) { diff --git a/go.mod b/go.mod index 5bcb02a..a741895 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,17 @@ go 1.23.2 require ( github.com/gen2brain/malgo v0.11.22 github.com/gen2brain/raylib-go/raylib v0.0.0-20241019150900-b7833eeae8d0 + github.com/godbus/dbus v4.1.0+incompatible github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f + github.com/leberKleber/go-mpris v1.1.0 github.com/smallnest/ringbuffer v0.0.0-20240827114233-62e3c686e6c0 + github.com/ztrue/tracerr v0.4.0 gopkg.in/yaml.v2 v2.4.0 ) require ( github.com/ebitengine/purego v0.7.1 // indirect + github.com/godbus/dbus/v5 v5.0.6 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/sys v0.20.0 // indirect ) diff --git a/go.sum b/go.sum index ac0c7a7..ea9d744 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,39 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= github.com/gen2brain/malgo v0.11.22 h1:fRtTbzVI9CDWnfEJGo/GxKxN7pXtCb0NsAeUVUjZk9U= github.com/gen2brain/malgo v0.11.22/go.mod h1:f9TtuN7DVrXMiV/yIceMeWpvanyVzJQMlBecJFVMxww= github.com/gen2brain/raylib-go/raylib v0.0.0-20241019150900-b7833eeae8d0 h1:ssHgKQvc9AIHFSlpkfHr89lJU8nzGBdpKoQJBTPkvnQ= github.com/gen2brain/raylib-go/raylib v0.0.0-20241019150900-b7833eeae8d0/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q= +github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= +github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNqOcFIbuqFjAWPVtP688j5QMgmo6OHU= github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leberKleber/go-mpris v1.1.0 h1:bHAnmUjVoxAs4uMHH9lfQ8bOm284UWtI7JhLvkiF7O8= +github.com/leberKleber/go-mpris v1.1.0/go.mod h1:OwKywFZwFGC0p/8xBUTUXMIFZy0Rq/7C6EayfeASTA0= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/smallnest/ringbuffer v0.0.0-20240827114233-62e3c686e6c0 h1:6wTlHUWggWb8Y5Q4f7xnIBHa3L7DgijNQP8eM6oTEhQ= github.com/smallnest/ringbuffer v0.0.0-20240827114233-62e3c686e6c0/go.mod h1:tAG61zBM1DYRaGIPloumExGvScf08oHuo0kFoOqdbT0= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/ztrue/tracerr v0.4.0 h1:vT5PFxwIGs7rCg9ZgJ/y0NmOpJkPCPFK8x0vVIYzd04= +github.com/ztrue/tracerr v0.4.0/go.mod h1:PaFfYlas0DfmXNpo7Eay4MFhZUONqvXM+T2HyGPpngk= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index cd8c26b..fce7a62 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "xyosc/audio" "xyosc/config" + "xyosc/media" rl "github.com/gen2brain/raylib-go/raylib" ) @@ -12,6 +13,7 @@ func main() { config.Init() audio.Init() go audio.Start() + go media.Start() scale := min(config.Config.WindowWidth, config.Config.WindowHeight) / 2 rl.InitWindow(config.Config.WindowWidth, config.Config.WindowHeight, "xyosc") @@ -44,8 +46,11 @@ func main() { AY = BY } if config.Config.FPSCounter { - rl.DrawFPS(0, 0) + rl.DrawFPS(16, config.Config.WindowHeight) } + rl.DrawText(media.PlayingMediaInfo.Artist+" - "+media.PlayingMediaInfo.Title, 16, 16, 32, config.AccentColor) + rl.DrawText(media.PlayingMediaInfo.Album, 16, 48, 16, config.ThirdColor) + rl.DrawText(media.FmtDuration(media.PlayingMediaInfo.Position)+" / "+media.FmtDuration(media.PlayingMediaInfo.Duration), 16, 64, 32, config.AccentColor) rl.EndDrawing() } diff --git a/media/media.go b/media/media.go new file mode 100644 index 0000000..3a8c60b --- /dev/null +++ b/media/media.go @@ -0,0 +1,90 @@ +package media + +import ( + "fmt" + "math" + "runtime" + "strings" + "time" + "xyosc/utils" + + "github.com/godbus/dbus" + "github.com/leberKleber/go-mpris" + + "github.com/ztrue/tracerr" +) + +func FmtDuration(s float64) string { + mf := int(math.Floor(s / 60)) + sf := int((s/60 - math.Floor(s/60)) * 60) + return fmt.Sprintf("%02d:%02d", mf, sf) +} + +type CurrentPlayingMediaInfo struct { + Title string + Album string + Artist string + Position float64 + Duration float64 +} + +var PlayingMediaInfo CurrentPlayingMediaInfo + +func Start() { + for { + PlayingMediaInfo = GetCurrentPlayingMediaInfo() + time.Sleep(time.Second * 1) + } +} + +func ListPlayers() []string { + conn, err := dbus.SessionBus() + utils.CheckError(tracerr.Wrap(err)) + var names []string + err = conn.BusObject().Call("org.freedesktop.DBus.ListNames", 0).Store(&names) + utils.CheckError(tracerr.Wrap(err)) + + var mprisNames []string + for _, name := range names { + if strings.HasPrefix(name, "org.mpris.MediaPlayer2") { + mprisNames = append(mprisNames, name) + } + } + return mprisNames +} + +func GetCurrentPlayingMediaInfo() CurrentPlayingMediaInfo { + switch runtime.GOOS { + case "linux": + players := ListPlayers() + if len(players) == 0 { + return CurrentPlayingMediaInfo{"No media", "", "", 0, 0} + } + p, err := mpris.NewPlayer(players[0]) + utils.CheckError(tracerr.Wrap(err)) + mediaPositionMicroseconds, err := p.Position() + if err != nil { + mediaPositionMicroseconds = 0 + } + mediaPosition := float64(mediaPositionMicroseconds) / 1000000 + mediaMetadata, err := p.Metadata() + utils.CheckError(tracerr.Wrap(err)) + mediaDurationMicroseconds, err := mediaMetadata.MPRISLength() + utils.CheckError(tracerr.Wrap(err)) + mediaDuration := float64(mediaDurationMicroseconds) / 1000000 + mediaTitle, err := mediaMetadata.XESAMTitle() + utils.CheckError(tracerr.Wrap(err)) + mediaAlbum, err := mediaMetadata.XESAMAlbum() + utils.CheckError(tracerr.Wrap(err)) + mediaArtists, err := mediaMetadata.XESAMArtist() + utils.CheckError(tracerr.Wrap(err)) + mediaArtist := "" + if len(mediaArtists) != 0 { + mediaArtist = mediaArtists[0] + } + utils.CheckError(tracerr.Wrap(err)) + return CurrentPlayingMediaInfo{mediaTitle, mediaAlbum, mediaArtist, mediaPosition, mediaDuration} + default: + return CurrentPlayingMediaInfo{"Platform not supported", "Sorry", "", 0, 0} + } +}