summaryrefslogtreecommitdiff
path: root/commands.go
diff options
context:
space:
mode:
authordelthas <delthas@dille.cc>2022-11-23 20:06:42 +0100
committerdelthas <delthas@dille.cc>2022-11-23 20:11:41 +0100
commit5ff0f2c63b96623c81657a8f0e2dbdc537edf103 (patch)
tree8a9980f2236491cb73debe40aea98b37bead045e /commands.go
parentAdd documentation for /MOTD (diff)
Implement /NP
This queries the system for the current song being played. This uses DBus & MPRIS/xesam. The priority is any player in playing state > any player in paused state. Only players in the playing or paused state, with a valid song title are considered.
Diffstat (limited to 'commands.go')
-rw-r--r--commands.go94
1 files changed, 94 insertions, 0 deletions
diff --git a/commands.go b/commands.go
index 55582a0..5a2c71b 100644
--- a/commands.go
+++ b/commands.go
@@ -3,6 +3,7 @@ package senpai
import (
"errors"
"fmt"
+ "net/url"
"sort"
"strconv"
"strings"
@@ -11,6 +12,8 @@ import (
"git.sr.ht/~taiite/senpai/irc"
"git.sr.ht/~taiite/senpai/ui"
"github.com/gdamore/tcell/v2"
+ "github.com/godbus/dbus/v5"
+ "golang.org/x/net/context"
)
var (
@@ -57,6 +60,11 @@ func init() {
Desc: "send an action (reply to last query if sent from home)",
Handle: commandDoMe,
},
+ "NP": {
+ AllowHome: true,
+ Desc: "send the current song that is being played on the system",
+ Handle: commandDoNP,
+ },
"MSG": {
AllowHome: true,
MinArgs: 2,
@@ -343,6 +351,14 @@ func commandDoMe(app *App, args []string) (err error) {
return nil
}
+func commandDoNP(app *App, args []string) (err error) {
+ song := getSong()
+ if song == "" {
+ return fmt.Errorf("no song was detected")
+ }
+ return commandDoMe(app, []string{fmt.Sprintf("np: %s", song)})
+}
+
func commandDoMsg(app *App, args []string) (err error) {
target := args[0]
content := args[1]
@@ -775,3 +791,81 @@ func (app *App) handleInput(buffer, content string) error {
return cmd.Handle(app, args)
}
+
+func getSong() string {
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+
+ bus, err := dbus.ConnectSessionBus(dbus.WithContext(ctx))
+ if err != nil {
+ return ""
+ }
+ defer bus.Close()
+
+ var names []string
+ if err := bus.BusObject().CallWithContext(ctx, "org.freedesktop.DBus.ListNames", 0).Store(&names); err != nil {
+ return ""
+ }
+ song := ""
+ for _, name := range names {
+ if !strings.HasPrefix(name, "org.mpris.MediaPlayer2.") {
+ continue
+ }
+ var playing bool
+ o := bus.Object(name, "/org/mpris/MediaPlayer2")
+ var status string
+ if err := o.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.mpris.MediaPlayer2.Player", "PlaybackStatus").Store(&status); err != nil {
+ continue
+ }
+ switch status {
+ case "Playing":
+ playing = true
+ case "Paused":
+ playing = false
+ default:
+ continue
+ }
+ var metadata map[string]dbus.Variant
+ if err := o.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.mpris.MediaPlayer2.Player", "Metadata").Store(&metadata); err != nil {
+ continue
+ }
+ var trackURL string
+ var title string
+ var album string
+ var artist string
+ if e, ok := metadata["xesam:title"].Value().(string); ok {
+ title = e
+ }
+ if e, ok := metadata["xesam:album"].Value().(string); ok {
+ album = e
+ }
+ if e, ok := metadata["xesam:url"].Value().(string); ok {
+ trackURL = e
+ }
+ if e, ok := metadata["xesam:artist"].Value().([]string); ok && len(e) > 0 {
+ artist = e[0]
+ }
+ if title == "" {
+ continue
+ }
+ var sb strings.Builder
+ fmt.Fprintf(&sb, "\x02%s\x02", title)
+ if artist != "" {
+ fmt.Fprintf(&sb, " by \x02%s\x02", artist)
+ }
+ if album != "" {
+ fmt.Fprintf(&sb, " from \x02%s\x02", album)
+ }
+ if u, err := url.Parse(trackURL); err == nil {
+ switch u.Scheme {
+ case "http", "https":
+ fmt.Fprintf(&sb, " — %s", trackURL)
+ }
+ }
+ song = sb.String()
+ if playing {
+ return song
+ }
+ }
+ return song
+}