From 741e1c0855afbdfde42e885b1235c9410da8dce0 Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Fri, 25 Feb 2022 01:23:37 +0100 Subject: [PATCH 1/7] Added PulseAudioControl Widget (mute only atm) --- README.md | 17 ++++ decks/pulseaudio_control.deck | 17 ++++ widget.go | 3 + widget_pulseaudio_control.go | 148 ++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 decks/pulseaudio_control.deck create mode 100644 widget_pulseaudio_control.go diff --git a/README.md b/README.md index 7c86da7..567fbaa 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,23 @@ corresponding icons with correct names need to be placed in `~/.local/share/deckmaster/themes/[theme]`. The default icons with their respective names can be found [here](https://github.com/muesli/deckmaster/tree/master/assets/weather). +#### Pulseaudio Control + +A widget that can controls a specific pulseaudio input sink (like Rhythmbox, Firefox etc.). + +```toml +[keys.widget] + id = "pulseAudioControl" + [keys.widget.config] + appName = "Application name" # Like "Rhythmbox" + mode = "mute" # Only mute is supported at the moment. + showTitle = true # optional +``` + +This widget is using "pactl" and "pacmd". + +You can use `pacmd list-sink-inputs` to see the current sinks. Use the value of "application.name" for appName. + ### Actions You can hook up any key with several actions. A regular keypress will trigger diff --git a/decks/pulseaudio_control.deck b/decks/pulseaudio_control.deck new file mode 100644 index 0000000..992ee44 --- /dev/null +++ b/decks/pulseaudio_control.deck @@ -0,0 +1,17 @@ +[[keys]] + index = 0 + [keys.widget] + id = "pulseAudioControl" + [keys.widget.config] + appName = "Firefox" + mode = "mute" + showTitle = false + +[[keys]] + index = 1 + [keys.widget] + id = "pulseAudioControl" + [keys.widget.config] + appName = "Rhythmbox" + mode = "mute" + showTitle = true diff --git a/widget.go b/widget.go index 60764b1..bcfe309 100644 --- a/widget.go +++ b/widget.go @@ -124,6 +124,9 @@ func NewWidget(dev *streamdeck.Device, base string, kc KeyConfig, bg image.Image case "weather": return NewWeatherWidget(bw, kc.Widget) + + case "pulseAudioControl": + return NewPulseAudioControlWidget(bw, kc.Widget) } // unknown widget ID diff --git a/widget_pulseaudio_control.go b/widget_pulseaudio_control.go new file mode 100644 index 0000000..4127caa --- /dev/null +++ b/widget_pulseaudio_control.go @@ -0,0 +1,148 @@ +package main + +import ( + "fmt" + "image" + "os" + "os/exec" + "regexp" +) + +const ( + regex = `index: ([0-9]+)[\s\S]*?media.name = \"(.*?)\"[\s\S]*?application.name = \"(.*?)\"` + regexGroupClientId = 1 + regexGroupMediaName = 2 + regexGroupAppName = 3 +) + +// PulseAudioControlWidget is a widget displaying a recently activated window. +type PulseAudioControlWidget struct { + *ButtonWidget + + appName string + mode string + showTitle bool +} + +// NewPulseAudioControlWidget returns a new PulseAudioControlWidget. +func NewPulseAudioControlWidget(bw *BaseWidget, opts WidgetConfig) (*PulseAudioControlWidget, error) { + var appName string + if err := ConfigValue(opts.Config["appName"], &appName); err != nil { + return nil, err + } + + var mode string + if err := ConfigValue(opts.Config["mode"], &mode); err != nil { + return nil, err + } + + var showTitle bool + _ = ConfigValue(opts.Config["showTitle"], &showTitle) + widget, err := NewButtonWidget(bw, opts) + + if err != nil { + return nil, err + } + + return &PulseAudioControlWidget{ + ButtonWidget: widget, + appName: appName, + mode: mode, + showTitle: showTitle, + }, nil +} + +// RequiresUpdate returns true when the widget wants to be repainted. +func (w *PulseAudioControlWidget) RequiresUpdate() bool { + //TODO + + return w.BaseWidget.RequiresUpdate() +} + +// Update renders the widget. +func (w *PulseAudioControlWidget) Update() error { + img := image.NewRGBA(image.Rect(0, 0, int(w.dev.Pixels), int(w.dev.Pixels))) + + if !w.showTitle { + var appName = w.appName + + runes := []rune(appName) + if len(runes) > 10 { + appName = string(runes[:10]) + } + + w.label = appName + return w.ButtonWidget.Update() + } + + var re = regexp.MustCompile(regex) + + output, err := exec.Command("sh", "-c", "pacmd list-sink-inputs").Output() + + if err != nil { + return fmt.Errorf("can't get pulseaudio sinks: %s", err) + } + + var sinkTitle = "" + + matches := re.FindAllStringSubmatch(string(output), -1) + + for match := range matches { + if w.appName == matches[match][regexGroupAppName] { + sinkTitle = matches[match][regexGroupMediaName] + } + } + + if sinkTitle != "" { + + var title = sinkTitle + if w.showTitle { + + runes := []rune(title) + if len(runes) > 10 { + title = string(runes[:10]) + } + } + + w.label = title + + return w.ButtonWidget.Update() + } + + return w.render(w.dev, img) +} + +// TriggerAction gets called when a button is pressed. +func (w *PulseAudioControlWidget) TriggerAction(hold bool) { + + if w.mode != "mute" { + fmt.Fprintln(os.Stderr, "unknown mode:", w.mode) + return + } + + var re = regexp.MustCompile(regex) + + output, err := exec.Command("sh", "-c", "pacmd list-sink-inputs").Output() + + if err != nil { + fmt.Fprintln(os.Stderr, "can't get pulseaudio sinks:", err) + return + } + + var sinkIndex string + + matches := re.FindAllStringSubmatch(string(output), -1) + + for match := range matches { + if w.appName == matches[match][regexGroupAppName] { + sinkIndex = matches[match][regexGroupClientId] + } + } + + output, err = exec.Command("sh", "-c", "pactl set-sink-input-mute "+sinkIndex+" toggle").Output() + + if err != nil { + fmt.Fprintln(os.Stderr, "can't toggle mute for pulseaudio sink index: "+sinkIndex, err) + return + } +} From 8a57cdbbc484a1581b3bc645b465dfe60ae8774d Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Fri, 25 Feb 2022 22:27:15 +0100 Subject: [PATCH 2/7] Refactored PulseAudioControlWidget + some code cleanups. --- widget_pulseaudio_control.go | 113 +++++++++++++++++------------------ 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/widget_pulseaudio_control.go b/widget_pulseaudio_control.go index 4127caa..e1b5f99 100644 --- a/widget_pulseaudio_control.go +++ b/widget_pulseaudio_control.go @@ -2,17 +2,18 @@ package main import ( "fmt" - "image" "os" "os/exec" "regexp" ) const ( - regex = `index: ([0-9]+)[\s\S]*?media.name = \"(.*?)\"[\s\S]*?application.name = \"(.*?)\"` + regexExpression = `index: ([0-9]+)[\s\S]*?media.name = \"(.*?)\"[\s\S]*?application.name = \"(.*?)\"` regexGroupClientId = 1 regexGroupMediaName = 2 regexGroupAppName = 3 + + listInputSinksCommand = "pacmd list-sink-inputs" ) // PulseAudioControlWidget is a widget displaying a recently activated window. @@ -61,88 +62,86 @@ func (w *PulseAudioControlWidget) RequiresUpdate() bool { // Update renders the widget. func (w *PulseAudioControlWidget) Update() error { - img := image.NewRGBA(image.Rect(0, 0, int(w.dev.Pixels), int(w.dev.Pixels))) - - if !w.showTitle { - var appName = w.appName - - runes := []rune(appName) - if len(runes) > 10 { - appName = string(runes[:10]) + if w.showTitle { + sinkTitle, err := getSinkTitleFor(w.appName) + if err != nil { + return err } + + if sinkTitle != "" { + w.label = stripTextTo(10, sinkTitle) + return w.ButtonWidget.Update() + } + } + + w.label = stripTextTo(10, w.appName) + return w.ButtonWidget.Update() +} - w.label = appName - return w.ButtonWidget.Update() +// TriggerAction gets called when a button is pressed. +func (w *PulseAudioControlWidget) TriggerAction(hold bool) { + if w.mode != "mute" { + fmt.Fprintln(os.Stderr, "unknown mode:", w.mode) + return } - var re = regexp.MustCompile(regex) + sinkIndex, err := getSinkIndex(w.appName) + if err != nil { + fmt.Fprintln(os.Stderr, "can't toggle mute for pulseaudio sink index: "+sinkIndex, err) + } - output, err := exec.Command("sh", "-c", "pacmd list-sink-inputs").Output() + toggleMute(sinkIndex) +} +func getSinkIndex(appName string) (string, error) { + output, err := exec.Command("sh", "-c", listInputSinksCommand).Output() if err != nil { - return fmt.Errorf("can't get pulseaudio sinks: %s", err) + return "", fmt.Errorf("can't get pulseaudio sinks. 'pacmd' missing? %s", err) } - var sinkTitle = "" - - matches := re.FindAllStringSubmatch(string(output), -1) + var regex = regexp.MustCompile(regexExpression) + matches := regex.FindAllStringSubmatch(string(output), -1) + var sinkIndex string for match := range matches { - if w.appName == matches[match][regexGroupAppName] { - sinkTitle = matches[match][regexGroupMediaName] + if appName == matches[match][regexGroupAppName] { + sinkIndex = matches[match][regexGroupClientId] } } - if sinkTitle != "" { - - var title = sinkTitle - if w.showTitle { - - runes := []rune(title) - if len(runes) > 10 { - title = string(runes[:10]) - } - } + return sinkIndex, nil +} - w.label = title +func toggleMute(sinkIndex string) { + err := exec.Command("sh", "-c", "pactl set-sink-input-mute "+sinkIndex+" toggle").Run() - return w.ButtonWidget.Update() + if err != nil { + fmt.Fprintln(os.Stderr, "can't toggle mute for pulseaudio sink index: "+sinkIndex, err) } - - return w.render(w.dev, img) } -// TriggerAction gets called when a button is pressed. -func (w *PulseAudioControlWidget) TriggerAction(hold bool) { - - if w.mode != "mute" { - fmt.Fprintln(os.Stderr, "unknown mode:", w.mode) - return +func stripTextTo(maxLength int, text string) string { + runes := []rune(text) + if len(runes) > maxLength { + return string(runes[:10]) } + return text +} - var re = regexp.MustCompile(regex) - - output, err := exec.Command("sh", "-c", "pacmd list-sink-inputs").Output() +func getSinkTitleFor(appName string) (string, error){ + output, err := exec.Command("sh", "-c", listInputSinksCommand).Output() if err != nil { - fmt.Fprintln(os.Stderr, "can't get pulseaudio sinks:", err) - return + return "", fmt.Errorf("can't get pulseaudio sinks. 'pacmd' missing? %s", err) } - var sinkIndex string - - matches := re.FindAllStringSubmatch(string(output), -1) - + var regex = regexp.MustCompile(regexExpression) + matches := regex.FindAllStringSubmatch(string(output), -1) for match := range matches { - if w.appName == matches[match][regexGroupAppName] { - sinkIndex = matches[match][regexGroupClientId] + if appName == matches[match][regexGroupAppName] { + return matches[match][regexGroupMediaName], nil } } - output, err = exec.Command("sh", "-c", "pactl set-sink-input-mute "+sinkIndex+" toggle").Output() - - if err != nil { - fmt.Fprintln(os.Stderr, "can't toggle mute for pulseaudio sink index: "+sinkIndex, err) - return - } + return "", nil } From d3301318a6ecf5421101739edcf6389e04f3ac0b Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Sat, 26 Feb 2022 01:33:29 +0100 Subject: [PATCH 3/7] Adding intervals to the widgets in the pulseaudio_control.deck example. --- decks/pulseaudio_control.deck | 3 +++ 1 file changed, 3 insertions(+) diff --git a/decks/pulseaudio_control.deck b/decks/pulseaudio_control.deck index 992ee44..c680cb0 100644 --- a/decks/pulseaudio_control.deck +++ b/decks/pulseaudio_control.deck @@ -2,6 +2,7 @@ index = 0 [keys.widget] id = "pulseAudioControl" + interval = 1000 [keys.widget.config] appName = "Firefox" mode = "mute" @@ -11,7 +12,9 @@ index = 1 [keys.widget] id = "pulseAudioControl" + interval = 1000 [keys.widget.config] appName = "Rhythmbox" mode = "mute" showTitle = true + From 6b18774e3e60a831e94fb325ed5f598e8a123e97 Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Sat, 26 Feb 2022 01:36:38 +0100 Subject: [PATCH 4/7] Show if a pulseaudio input sink is muted or not --- decks/assets/volume-muted.png | Bin 0 -> 13402 bytes widget_pulseaudio_control.go | 88 ++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 37 deletions(-) create mode 100644 decks/assets/volume-muted.png diff --git a/decks/assets/volume-muted.png b/decks/assets/volume-muted.png new file mode 100644 index 0000000000000000000000000000000000000000..a1f6b799876da0b1b983d3a109a780a65cf578cf GIT binary patch literal 13402 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 Date: Sat, 26 Feb 2022 19:22:06 +0100 Subject: [PATCH 5/7] Format code --- widget_pulseaudio_control.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/widget_pulseaudio_control.go b/widget_pulseaudio_control.go index 8035643..f103f08 100644 --- a/widget_pulseaudio_control.go +++ b/widget_pulseaudio_control.go @@ -67,7 +67,6 @@ func (w *PulseAudioControlWidget) RequiresUpdate() bool { return w.BaseWidget.RequiresUpdate() } - // Update renders the widget. func (w *PulseAudioControlWidget) Update() error { sinkInputData, err := getSinkInputDataForApp(w.appName) @@ -140,16 +139,16 @@ func getSinkInputDataForApp(appName string) (*sinkInputData, error) { matches := regex.FindAllStringSubmatch(string(output), -1) for match := range matches { if appName == matches[match][regexGroupAppName] { - sinkInputData.index = matches[match][regexGroupClientId] - sinkInputData.muted = yesOrNoToBool(matches[match][regexGroupMuted]) - sinkInputData.title = matches[match][regexGroupMediaName] + sinkInputData.index = matches[match][regexGroupClientId] + sinkInputData.muted = yesOrNoToBool(matches[match][regexGroupMuted]) + sinkInputData.title = matches[match][regexGroupMediaName] } } return sinkInputData, nil } -func yesOrNoToBool(yesOrNo string) (bool) { +func yesOrNoToBool(yesOrNo string) bool { switch yesOrNo { case "yes": return true From d9be2c93a71619e75cc7277671d50251932aafe5 Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Sat, 26 Feb 2022 20:42:57 +0100 Subject: [PATCH 6/7] Fix: Using maxLength --- widget_pulseaudio_control.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget_pulseaudio_control.go b/widget_pulseaudio_control.go index f103f08..4754389 100644 --- a/widget_pulseaudio_control.go +++ b/widget_pulseaudio_control.go @@ -123,7 +123,7 @@ func toggleMute(sinkIndex string) { func stripTextTo(maxLength int, text string) string { runes := []rune(text) if len(runes) > maxLength { - return string(runes[:10]) + return string(runes[:maxLength]) } return text } From 96151d7e8d0d5160d7d1dacf315546484d6ea625 Mon Sep 17 00:00:00 2001 From: SomeoneOnEarth Date: Sat, 26 Feb 2022 21:27:44 +0100 Subject: [PATCH 7/7] Show an icon, if a pulseaudio sink is not playing. --- decks/assets/{volume-muted.png => muted.png} | Bin decks/assets/not_muted.png | Bin 0 -> 11945 bytes decks/assets/not_playing.png | Bin 0 -> 15102 bytes widget_pulseaudio_control.go | 41 +++++++++++-------- 4 files changed, 25 insertions(+), 16 deletions(-) rename decks/assets/{volume-muted.png => muted.png} (100%) create mode 100644 decks/assets/not_muted.png create mode 100644 decks/assets/not_playing.png diff --git a/decks/assets/volume-muted.png b/decks/assets/muted.png similarity index 100% rename from decks/assets/volume-muted.png rename to decks/assets/muted.png diff --git a/decks/assets/not_muted.png b/decks/assets/not_muted.png new file mode 100644 index 0000000000000000000000000000000000000000..61535f5a490d40d9599d372ab8aeefb55afc3df9 GIT binary patch literal 11945 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 literal 0 HcmV?d00001 diff --git a/decks/assets/not_playing.png b/decks/assets/not_playing.png new file mode 100644 index 0000000000000000000000000000000000000000..3e8d1436df55505abd035f577a62a88833186ee4 GIT binary patch literal 15102 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 literal 0 HcmV?d00001 diff --git a/widget_pulseaudio_control.go b/widget_pulseaudio_control.go index 4754389..3dd8ac1 100644 --- a/widget_pulseaudio_control.go +++ b/widget_pulseaudio_control.go @@ -75,24 +75,28 @@ func (w *PulseAudioControlWidget) Update() error { } var icon string - if sinkInputData.muted { - icon = "assets/volume-muted.png" + var label string + if sinkInputData != nil { + if sinkInputData.muted { + icon = "assets/muted.png" + } else { + icon = "assets/not_muted.png" + } + if w.showTitle && sinkInputData.title != "" { + label = sinkInputData.title + } else { + label = w.appName + } } else { - icon = "assets/volume-high.png" + icon = "assets/not_playing.png" + label = w.appName } if err := w.LoadImage(icon); err != nil { return err } - if w.showTitle { - if sinkInputData.title != "" { - w.label = stripTextTo(10, sinkInputData.title) - return w.ButtonWidget.Update() - } - } - - w.label = stripTextTo(10, w.appName) + w.label = stripTextTo(10, label) return w.ButtonWidget.Update() } @@ -109,6 +113,10 @@ func (w *PulseAudioControlWidget) TriggerAction(hold bool) { fmt.Fprintln(os.Stderr, "can't toggle mute for pulseaudio app "+w.appName, err) } + if sinkInputData == nil { + fmt.Fprintln(os.Stderr, "No running sink found for pulseaudio app "+w.appName, err) + } + toggleMute(sinkInputData.index) } @@ -129,7 +137,6 @@ func stripTextTo(maxLength int, text string) string { } func getSinkInputDataForApp(appName string) (*sinkInputData, error) { - sinkInputData := &sinkInputData{} output, err := exec.Command("sh", "-c", listInputSinksCommand).Output() if err != nil { return nil, fmt.Errorf("can't get pulseaudio sinks. 'pacmd' missing? %s", err) @@ -137,15 +144,17 @@ func getSinkInputDataForApp(appName string) (*sinkInputData, error) { var regex = regexp.MustCompile(regexExpression) matches := regex.FindAllStringSubmatch(string(output), -1) + var sinkData *sinkInputData for match := range matches { if appName == matches[match][regexGroupAppName] { - sinkInputData.index = matches[match][regexGroupClientId] - sinkInputData.muted = yesOrNoToBool(matches[match][regexGroupMuted]) - sinkInputData.title = matches[match][regexGroupMediaName] + sinkData = &sinkInputData{} + sinkData.index = matches[match][regexGroupClientId] + sinkData.muted = yesOrNoToBool(matches[match][regexGroupMuted]) + sinkData.title = matches[match][regexGroupMediaName] } } - return sinkInputData, nil + return sinkData, nil } func yesOrNoToBool(yesOrNo string) bool {