commit 5ff0f2c
delthas
·
2022-11-23 19:06:42 +0000 UTC
parent 9a0cc2c
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.
4 files changed,
+101,
-0
+94,
-0
1@@ -3,6 +3,7 @@ package senpai
2 import (
3 "errors"
4 "fmt"
5+ "net/url"
6 "sort"
7 "strconv"
8 "strings"
9@@ -11,6 +12,8 @@ import (
10 "git.sr.ht/~taiite/senpai/irc"
11 "git.sr.ht/~taiite/senpai/ui"
12 "github.com/gdamore/tcell/v2"
13+ "github.com/godbus/dbus/v5"
14+ "golang.org/x/net/context"
15 )
16
17 var (
18@@ -57,6 +60,11 @@ func init() {
19 Desc: "send an action (reply to last query if sent from home)",
20 Handle: commandDoMe,
21 },
22+ "NP": {
23+ AllowHome: true,
24+ Desc: "send the current song that is being played on the system",
25+ Handle: commandDoNP,
26+ },
27 "MSG": {
28 AllowHome: true,
29 MinArgs: 2,
30@@ -343,6 +351,14 @@ func commandDoMe(app *App, args []string) (err error) {
31 return nil
32 }
33
34+func commandDoNP(app *App, args []string) (err error) {
35+ song := getSong()
36+ if song == "" {
37+ return fmt.Errorf("no song was detected")
38+ }
39+ return commandDoMe(app, []string{fmt.Sprintf("np: %s", song)})
40+}
41+
42 func commandDoMsg(app *App, args []string) (err error) {
43 target := args[0]
44 content := args[1]
45@@ -775,3 +791,81 @@ func (app *App) handleInput(buffer, content string) error {
46
47 return cmd.Handle(app, args)
48 }
49+
50+func getSong() string {
51+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
52+ defer cancel()
53+
54+ bus, err := dbus.ConnectSessionBus(dbus.WithContext(ctx))
55+ if err != nil {
56+ return ""
57+ }
58+ defer bus.Close()
59+
60+ var names []string
61+ if err := bus.BusObject().CallWithContext(ctx, "org.freedesktop.DBus.ListNames", 0).Store(&names); err != nil {
62+ return ""
63+ }
64+ song := ""
65+ for _, name := range names {
66+ if !strings.HasPrefix(name, "org.mpris.MediaPlayer2.") {
67+ continue
68+ }
69+ var playing bool
70+ o := bus.Object(name, "/org/mpris/MediaPlayer2")
71+ var status string
72+ if err := o.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.mpris.MediaPlayer2.Player", "PlaybackStatus").Store(&status); err != nil {
73+ continue
74+ }
75+ switch status {
76+ case "Playing":
77+ playing = true
78+ case "Paused":
79+ playing = false
80+ default:
81+ continue
82+ }
83+ var metadata map[string]dbus.Variant
84+ if err := o.CallWithContext(ctx, "org.freedesktop.DBus.Properties.Get", 0, "org.mpris.MediaPlayer2.Player", "Metadata").Store(&metadata); err != nil {
85+ continue
86+ }
87+ var trackURL string
88+ var title string
89+ var album string
90+ var artist string
91+ if e, ok := metadata["xesam:title"].Value().(string); ok {
92+ title = e
93+ }
94+ if e, ok := metadata["xesam:album"].Value().(string); ok {
95+ album = e
96+ }
97+ if e, ok := metadata["xesam:url"].Value().(string); ok {
98+ trackURL = e
99+ }
100+ if e, ok := metadata["xesam:artist"].Value().([]string); ok && len(e) > 0 {
101+ artist = e[0]
102+ }
103+ if title == "" {
104+ continue
105+ }
106+ var sb strings.Builder
107+ fmt.Fprintf(&sb, "\x02%s\x02", title)
108+ if artist != "" {
109+ fmt.Fprintf(&sb, " by \x02%s\x02", artist)
110+ }
111+ if album != "" {
112+ fmt.Fprintf(&sb, " from \x02%s\x02", album)
113+ }
114+ if u, err := url.Parse(trackURL); err == nil {
115+ switch u.Scheme {
116+ case "http", "https":
117+ fmt.Fprintf(&sb, " — %s", trackURL)
118+ }
119+ }
120+ song = sb.String()
121+ if playing {
122+ return song
123+ }
124+ }
125+ return song
126+}
+4,
-0
1@@ -165,6 +165,10 @@ _name_ is matched case-insensitively. It can be one of the following:
2 Send a message prefixed with your nick (a user action). If sent from home,
3 reply to the last person who sent a private message.
4
5+*NP*
6+ Send the current song that is being played on the system. Uses DBus/MPRIS
7+ internally.
8+
9 *QUOTE* <raw message>
10 Send _raw message_ verbatim.
11
M
go.mod
+1,
-0
1@@ -6,6 +6,7 @@ require (
2 git.sr.ht/~emersion/go-scfg v0.0.0-20201019143924-142a8aa629fc
3 github.com/delthas/go-localeinfo v0.0.0-20221115102303-5a7785a1acc1
4 github.com/gdamore/tcell/v2 v2.5.4-0.20221017224006-ede1dd5ee680
5+ github.com/godbus/dbus/v5 v5.1.0
6 github.com/mattn/go-runewidth v0.0.14
7 golang.org/x/net v0.0.0-20220722155237-a158d28d115b
8 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
M
go.sum
+2,
-0
1@@ -8,6 +8,8 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk
2 github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
3 github.com/gdamore/tcell/v2 v2.5.4-0.20221017224006-ede1dd5ee680 h1:bCjGvZsZNvhzJZ+gDmXpKdDPyf358nSPqepaTI1AsMQ=
4 github.com/gdamore/tcell/v2 v2.5.4-0.20221017224006-ede1dd5ee680/go.mod h1:XmCynGHvvGG7UFI6az9zzoEHBvZB1PGf5APwOJMFUyE=
5+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
6+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
7 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
8 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
9 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=