From bdbf743008d945788209d2e9883da1919f8f7fc2 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 27 Jul 2020 17:13:03 +0100 Subject: [PATCH 01/50] Updated streamdeck lib dep --- go.mod | 2 +- go.sum | 2 ++ main.go | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 69dfb3b..0f9396c 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,6 @@ require ( github.com/fogleman/gg v1.3.0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/unix-streamdeck/streamdeck-lib v0.0.0-20200720132322-072961fa1fdd + github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 golang.org/x/image v0.0.0-20200119044424-58c23975cae1 ) diff --git a/go.sum b/go.sum index 6b86c75..8c34da6 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ungerik/go-cairo v0.0.0-20191014050614-4a03f432a432 h1:luu+HbKrZKlIjiaclwrldreEEvVPYX/ujRbTGkKz61c= github.com/ungerik/go-cairo v0.0.0-20191014050614-4a03f432a432/go.mod h1:0ErpLiOxxE1oY+R4stiKut6/DbUJHnOp6U+e4d8zcTs= +github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 h1:rLVbYju4iaW8jP64Pafffu9T0wXitOOtu3+qCxzGV1c= +github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2/go.mod h1:Tm8jArLxpQy5vGBbHSreHpNRAIYtDV3J3U3UMGRWTXc= github.com/unix-streamdeck/streamdeck-lib v0.0.0-20200720132322-072961fa1fdd h1:oX6jtZ+/gBcryYn49alkMPbCzqqwyo/7VA17mA4khrQ= github.com/unix-streamdeck/streamdeck-lib v0.0.0-20200720132322-072961fa1fdd/go.mod h1:EPLAk+jRYZ0zGW7S7bJctr3CLc4bc+tgBrJN7+G1bvc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/main.go b/main.go index e0c08d8..95a5c9e 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "encoding/json" "github.com/fogleman/gg" "github.com/nfnt/resize" - "github.com/unix-streamdeck/streamdeck-lib" + "github.com/unix-streamdeck/streamdeck" "golang.org/x/image/font/inconsolata" "image" "image/color" From a19fcd3f1247bf5689e711a87dc5ba4b24f13d80 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 27 Jul 2020 18:22:17 +0100 Subject: [PATCH 02/50] Stopped text clearing image behind text --- main.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.go b/main.go index 95a5c9e..bdc5ba4 100644 --- a/main.go +++ b/main.go @@ -106,8 +106,6 @@ func setPage() { } if currentKey.Text != "" { img := gg.NewContextForImage(currentKey.buff) - img.SetRGB(0, 0, 0) - img.Clear() img.SetRGB(1, 1, 1) img.SetFontFace(inconsolata.Regular8x16) img.DrawStringAnchored(currentKey.Text, 72/2, 72/2, 0.5, 0.5) From 6bafa7ea87241dd41f1475996267a6337d3c39c2 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 30 Jul 2020 16:44:03 +0100 Subject: [PATCH 03/50] WIP --- CounterHandler.go | 36 +++++++++++ GifHandler.go | 37 ++++++++++++ TimeHandler.go | 42 +++++++++++++ config.go | 8 ++- go.mod | 2 +- handler.go | 13 ++++ interface.go | 151 ++++++++++++++++++++++++++++++++++++++++++++++ main.go | 113 +++------------------------------- 8 files changed, 295 insertions(+), 107 deletions(-) create mode 100644 CounterHandler.go create mode 100644 GifHandler.go create mode 100644 TimeHandler.go create mode 100644 handler.go create mode 100644 interface.go diff --git a/CounterHandler.go b/CounterHandler.go new file mode 100644 index 0000000..c4ee032 --- /dev/null +++ b/CounterHandler.go @@ -0,0 +1,36 @@ +package main + +import ( + "github.com/fogleman/gg" + "github.com/unix-streamdeck/streamdeck" + "golang.org/x/image/font/inconsolata" + "strconv" +) + +type CounterIconHandler struct { + count int +} + +func (c *CounterIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { + img := gg.NewContext(72, 72) + img.SetRGB(0, 0, 0) + img.Clear() + img.SetRGB(1, 1, 1) + img.SetFontFace(inconsolata.Regular8x16) + count := strconv.Itoa(c.count) + img.DrawStringAnchored(count, 72/2, 72/2, 0.5, 0.5) + img.Clip() + SetImage(img.Image(), index, page, dev) + key.Buff = img.Image() +} + +type CounterKeyHandler struct{} + +func (CounterKeyHandler) Key(page int, index int, key *Key, dev streamdeck.Device) { + if key.IconHandler != "Counter" { + return + } + handler := key.IconHandlerStruct.(*CounterIconHandler) + handler.count += 1 + handler.Icon(page, index, key, dev) +} diff --git a/GifHandler.go b/GifHandler.go new file mode 100644 index 0000000..0588c3c --- /dev/null +++ b/GifHandler.go @@ -0,0 +1,37 @@ +package main + +import ( + "github.com/unix-streamdeck/streamdeck" + "image/gif" + "log" + "os" + "time" +) + +type GifIconHandler struct{ +} + +func (GifIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { + f, err := os.Open(key.Icon) + if err != nil { + log.Fatal(err) + return + } + gifs, err := gif.DecodeAll(f) + timeDelay := gifs.Delay[0] + gifIndex := 0 + go loop(gifs, gifIndex, timeDelay, page, index, dev, key) +} + +func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *Key) { + for true { + img := ResizeImage(gifs.Image[gifIndex]) + SetImage(img, index, page, dev) + key.Buff = img + gifIndex++ + if gifIndex >= len(gifs.Image) { + gifIndex = 0 + } + time.Sleep(time.Duration(timeDelay * 10000000)) + } +} \ No newline at end of file diff --git a/TimeHandler.go b/TimeHandler.go new file mode 100644 index 0000000..bc76f4a --- /dev/null +++ b/TimeHandler.go @@ -0,0 +1,42 @@ +package main + +import ( + "github.com/fogleman/gg" + "github.com/unix-streamdeck/streamdeck" + "golang.org/x/image/font/inconsolata" + "strconv" + "time" +) + +type TimeIconHandler struct{ +} + +func (TimeIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { + + go timeLoop(page, index, dev, key) +} + +func timeLoop(page int, index int, dev streamdeck.Device, key *Key) { + for true { + img := gg.NewContext(72, 72) + img.SetRGB(0, 0, 0) + img.Clear() + img.SetRGB(1, 1, 1) + img.SetFontFace(inconsolata.Regular8x16) + t := time.Now() + tString := zeroes(t.Hour()) + ":" + zeroes(t.Minute()) + ":" + zeroes(t.Second()) + img.DrawStringAnchored(tString, 72/2, 72/2, 0.5, 0.5) + img.Clip() + SetImage(img.Image(), index, page, dev) + key.Buff = img.Image() + time.Sleep(time.Second) + } +} + +func zeroes(i int) (string) { + if i < 10 { + return "0" + strconv.Itoa(i) + } else { + return strconv.Itoa(i) + } +} \ No newline at end of file diff --git a/config.go b/config.go index d2b9b7c..e8cba64 100644 --- a/config.go +++ b/config.go @@ -16,5 +16,9 @@ type Key struct { Command string `json:"command,omitempty"` Brightness *int `json:"brightness,omitempty"` Url string `json:"url,omitempty"` - buff image.Image -} + IconHandler string `json:"icon_handler,omitempty"` + IconHandlerStruct IconHandler + KeyHandler string `json:"key_handler,omitempty"` + KeyHandlerStruct KeyHandler + Buff image.Image +} \ No newline at end of file diff --git a/go.mod b/go.mod index 0f9396c..018a0ed 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module streamdeckd +module github.com/unix-streamdeck/streamdeckd go 1.14 diff --git a/handler.go b/handler.go new file mode 100644 index 0000000..91516f5 --- /dev/null +++ b/handler.go @@ -0,0 +1,13 @@ +package main + +import ( + "github.com/unix-streamdeck/streamdeck" +) + +type IconHandler interface { + Icon(page int, index int, key *Key, dev streamdeck.Device) +} + +type KeyHandler interface { + Key(page int, index int, key *Key, dev streamdeck.Device) +} diff --git a/interface.go b/interface.go new file mode 100644 index 0000000..72fd2b2 --- /dev/null +++ b/interface.go @@ -0,0 +1,151 @@ +package main + +import ( + "github.com/fogleman/gg" + "github.com/nfnt/resize" + "github.com/unix-streamdeck/streamdeck" + "golang.org/x/image/font/inconsolata" + "image" + "image/color" + "image/draw" + "log" + "os" +) + +var p int + +func LoadImage(path string) (image.Image, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + + img, _, err := image.Decode(f) + if err != nil { + return nil, err + } + + return ResizeImage(img), nil +} + +func ResizeImage(img image.Image) image.Image { + return resize.Resize(72, 72, img, resize.Lanczos3) +} + +func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { + if p == page { + dev.SetImage(uint8(i), img) + } +} + +func SetKey(currentKey *Key, i int) { + if currentKey.Buff == nil { + if currentKey.Icon == "" { + img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) + draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{0, 0, 0, 255}), image.ZP, draw.Src) + currentKey.Buff = img + } else { + img, err := LoadImage(currentKey.Icon) + if err != nil { + log.Fatal(err) + } + currentKey.Buff = img + } + if currentKey.Text != "" { + img := gg.NewContextForImage(currentKey.Buff) + img.SetRGB(1, 1, 1) + img.SetFontFace(inconsolata.Regular8x16) + img.DrawStringAnchored(currentKey.Text, 72/2, 72/2, 0.5, 0.5) + img.Clip() + currentKey.Buff = img.Image() + } + } + SetImage(currentKey.Buff, i, p, dev) +} + +func SetPage(config *Config, page int, dev streamdeck.Device) { + p = page + currentPage := config.Pages[page] + for i := 0; i < 15; i++ { + currentKey := ¤tPage[i] + if currentKey.Buff == nil { + if currentKey.IconHandler == "" { + SetKey(currentKey, i) + + } else if currentKey.IconHandlerStruct == nil { + var handler IconHandler + if currentKey.IconHandler == "Gif" { + handler = GifIconHandler{} + } else if currentKey.IconHandler == "Counter" { + handler = &CounterIconHandler{0} + } else if currentKey.IconHandler == "Time" { + handler = TimeIconHandler{} + } + if handler == nil { + continue + } + handler.Icon(page, i, currentKey, dev) + currentKey.IconHandlerStruct = handler + } + } else { + SetImage(currentKey.Buff, i, p, dev) + } + } +} + +func HandleInput(key *Key, page int, index int, dev streamdeck.Device) { + if key.Command != "" { + runCommand(key.Command) + } + if key.Keybind != "" { + runCommand("xdotool key " + key.Keybind) + } + if key.SwitchPage != nil { + page = (*key.SwitchPage) - 1 + SetPage(config, page, dev) + } + if key.Brightness != nil { + _ = dev.SetBrightness(uint8(*key.Brightness)) + } + if key.Url != "" { + runCommand("xdg-open " + key.Url) + } + if key.KeyHandler != "" { + if key.KeyHandlerStruct == nil { + var handler KeyHandler + if key.KeyHandler == "Counter" { + handler = CounterKeyHandler{} + } + if handler == nil { + return + } + key.KeyHandlerStruct = handler + } + key.KeyHandlerStruct.Key(page, index, key, dev) + } +} + +func Listen() { + kch, err := dev.ReadKeys() + if err != nil { + log.Fatal(err) + } + for { + select { + case k, ok := <-kch: + if !ok { + err = dev.Open() + if err != nil { + log.Fatal(err) + } + continue + } + if k.Pressed == true { + if len(config.Pages)-1 >= p && len(config.Pages[p])-1 >= int(k.Index) { + HandleInput(&config.Pages[p][k.Index], p, int(k.Index), dev) + } + } + } + } +} diff --git a/main.go b/main.go index bdc5ba4..9c002bd 100644 --- a/main.go +++ b/main.go @@ -2,13 +2,7 @@ package main import ( "encoding/json" - "github.com/fogleman/gg" - "github.com/nfnt/resize" "github.com/unix-streamdeck/streamdeck" - "golang.org/x/image/font/inconsolata" - "image" - "image/color" - "image/draw" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -17,13 +11,11 @@ import ( "os" "os/exec" "os/signal" - "strings" "syscall" ) -var page = 0 var dev streamdeck.Device -var config Config +var config *Config func main() { d, err := streamdeck.Devices() @@ -46,114 +38,27 @@ func main() { config.Pages = append(config.Pages, Page{}) } cleanupHook() - setPage() - kch, err := dev.ReadKeys() - if err != nil { - log.Fatal(err) - } - for { - select { - case k, ok := <-kch: - if !ok { - err = dev.Open() - if err != nil { - log.Fatal(err) - } - continue - } - if k.Pressed == true { - if len(config.Pages)-1 >= page && len(config.Pages[page])-1 >= int(k.Index) { - handleInput(config.Pages[page][k.Index]) - } - } - } - } + SetPage(config, 0, dev) + Listen() } -func readConfig() (Config, error) { +func readConfig() (*Config, error) { data, err := ioutil.ReadFile(os.Getenv("HOME") + "/.streamdeck-config.json") if err != nil { - return Config{}, err + return &Config{}, err } var config Config err = json.Unmarshal(data, &config) if err != nil { - return Config{}, err - } - return config, nil -} - -func setImage(img image.Image, i int, p int) { - if p == page { - dev.SetImage(uint8(i), img) - } -} - -func setPage() { - currentPage := config.Pages[page] - for i, currentKey := range currentPage { - if currentKey.buff == nil { - if currentKey.Icon == "" { - img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) - draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{0, 0, 0, 255}), image.ZP, draw.Src) - currentKey.buff = img - } else { - img, err := loadImage(currentKey.Icon) - if err != nil { - log.Fatal(err) - } - currentKey.buff = img - } - if currentKey.Text != "" { - img := gg.NewContextForImage(currentKey.buff) - img.SetRGB(1, 1, 1) - img.SetFontFace(inconsolata.Regular8x16) - img.DrawStringAnchored(currentKey.Text, 72/2, 72/2, 0.5, 0.5) - img.Clip() - currentKey.buff = img.Image() - } - } - setImage(currentKey.buff, i, page) - } -} - -func loadImage(path string) (image.Image, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - - img, _, err := image.Decode(f) - if err != nil { - return nil, err + return &Config{}, err } - - return resize.Resize(72, 72, img, resize.Lanczos3), nil + return &config, nil } -func handleInput(key Key) { - if key.Command != "" { - runCommand(key.Command) - } - if key.Keybind != "" { - runCommand("xdotool key " + key.Keybind) - } - if key.SwitchPage != nil { - page = (*key.SwitchPage) - 1 - setPage() - } - if key.Brightness != nil { - _ = dev.SetBrightness(uint8(*key.Brightness)) - } - if key.Url != "" { - runCommand("xdg-open " + key.Url) - } -} func runCommand(command string) { - args := strings.Split(command, " ") - c := exec.Command(args[0], args[1:]...) + //args := strings.Split(command, " ") + c := exec.Command("/bin/sh", "-c", command) if err := c.Start(); err != nil { panic(err) } From b4af427ccb90af6a07c0f4086b22b557887feceb Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 11 Aug 2020 15:37:36 +0100 Subject: [PATCH 04/50] Added dbus interface --- CounterHandler.go | 27 +++++++----- GifHandler.go | 18 +++++--- TimeHandler.go | 15 ++++--- config.go | 6 +-- dbus.go | 109 ++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 8 +--- handler.go | 1 + interface.go | 6 +-- main.go | 64 +++++++++++++++++++++++++++ 10 files changed, 222 insertions(+), 33 deletions(-) create mode 100644 dbus.go diff --git a/CounterHandler.go b/CounterHandler.go index c4ee032..2fe7509 100644 --- a/CounterHandler.go +++ b/CounterHandler.go @@ -9,19 +9,26 @@ import ( type CounterIconHandler struct { count int + running bool } func (c *CounterIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { - img := gg.NewContext(72, 72) - img.SetRGB(0, 0, 0) - img.Clear() - img.SetRGB(1, 1, 1) - img.SetFontFace(inconsolata.Regular8x16) - count := strconv.Itoa(c.count) - img.DrawStringAnchored(count, 72/2, 72/2, 0.5, 0.5) - img.Clip() - SetImage(img.Image(), index, page, dev) - key.Buff = img.Image() + if c.running { + img := gg.NewContext(72, 72) + img.SetRGB(0, 0, 0) + img.Clear() + img.SetRGB(1, 1, 1) + img.SetFontFace(inconsolata.Regular8x16) + count := strconv.Itoa(c.count) + img.DrawStringAnchored(count, 72/2, 72/2, 0.5, 0.5) + img.Clip() + SetImage(img.Image(), index, page, dev) + key.Buff = img.Image() + } +} + +func (c CounterIconHandler) Stop() { + c.running = false } type CounterKeyHandler struct{} diff --git a/GifHandler.go b/GifHandler.go index 0588c3c..051bed0 100644 --- a/GifHandler.go +++ b/GifHandler.go @@ -8,23 +8,29 @@ import ( "time" ) -type GifIconHandler struct{ +type GifIconHandler struct { + running bool } -func (GifIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { +func (s *GifIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { + s.running = true f, err := os.Open(key.Icon) if err != nil { - log.Fatal(err) + log.Panic(err) return } gifs, err := gif.DecodeAll(f) timeDelay := gifs.Delay[0] gifIndex := 0 - go loop(gifs, gifIndex, timeDelay, page, index, dev, key) + go loop(gifs, gifIndex, timeDelay, page, index, dev, key, s) } -func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *Key) { - for true { +func (s *GifIconHandler) Stop() { + s.running = false +} + +func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *Key, s *GifIconHandler) { + for s.running { img := ResizeImage(gifs.Image[gifIndex]) SetImage(img, index, page, dev) key.Buff = img diff --git a/TimeHandler.go b/TimeHandler.go index bc76f4a..529efb0 100644 --- a/TimeHandler.go +++ b/TimeHandler.go @@ -9,22 +9,27 @@ import ( ) type TimeIconHandler struct{ + running bool } -func (TimeIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { +func (t *TimeIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { + t.running = true + go timeLoop(page, index, dev, key, t) +} - go timeLoop(page, index, dev, key) +func (t *TimeIconHandler) Stop() { + t.running = false } -func timeLoop(page int, index int, dev streamdeck.Device, key *Key) { - for true { +func timeLoop(page int, index int, dev streamdeck.Device, key *Key, handler *TimeIconHandler) { + for handler.running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) img.Clear() img.SetRGB(1, 1, 1) img.SetFontFace(inconsolata.Regular8x16) t := time.Now() - tString := zeroes(t.Hour()) + ":" + zeroes(t.Minute()) + ":" + zeroes(t.Second()) + tString := t.Format("15:04:05") img.DrawStringAnchored(tString, 72/2, 72/2, 0.5, 0.5) img.Clip() SetImage(img.Image(), index, page, dev) diff --git a/config.go b/config.go index e8cba64..0334ec8 100644 --- a/config.go +++ b/config.go @@ -17,8 +17,8 @@ type Key struct { Brightness *int `json:"brightness,omitempty"` Url string `json:"url,omitempty"` IconHandler string `json:"icon_handler,omitempty"` - IconHandlerStruct IconHandler + IconHandlerStruct IconHandler `json:"-"` KeyHandler string `json:"key_handler,omitempty"` - KeyHandlerStruct KeyHandler - Buff image.Image + KeyHandlerStruct KeyHandler `json:"-"` + Buff image.Image `json:"-"` } \ No newline at end of file diff --git a/dbus.go b/dbus.go new file mode 100644 index 0000000..e78a8de --- /dev/null +++ b/dbus.go @@ -0,0 +1,109 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/godbus/dbus/v5" + "github.com/godbus/dbus/v5/introspect" + "log" + "os" +) + +const intro = ` + + + + + + + + + + + + + + + + + + + ` + introspect.IntrospectDataString + ` ` + +type StreamDeckDBus struct { + Cols int `json:"cols,omitempty"` + Rows int `json:"rows,omitempty"` + IconSize uint `json:"icon_size,omitempty"` +} + +func (s StreamDeckDBus) GetDeckInfo() (string, *dbus.Error) { + infoString, err := json.Marshal(s) + if err != nil { + return "", dbus.MakeFailedError(err) + } + return string(infoString), nil +} + +func (StreamDeckDBus) GetConfig() (string, *dbus.Error) { + configString, err := json.Marshal(config) + if err != nil { + return "", dbus.MakeFailedError(err) + } + return string(configString), nil +} + +func (StreamDeckDBus) ReloadConfig() *dbus.Error { + err := ReloadConfig() + if err != nil { + return dbus.MakeFailedError(err) + } + return nil +} + +func (StreamDeckDBus) SetPage(page int) *dbus.Error { + SetPage(config, page, dev) + return nil +} + +func (StreamDeckDBus) SetConfig(configString string) *dbus.Error { + err := SetConfig(configString) + if err != nil { + return dbus.MakeFailedError(err) + } + return nil +} + +func (StreamDeckDBus) CommitConfig() *dbus.Error { + err := SaveConfig() + if err != nil { + return dbus.MakeFailedError(err) + } + return nil +} + +func InitDBUS() { + conn, err := dbus.SessionBus() + if err != nil { + log.Println(err) + } + defer conn.Close() + + s := StreamDeckDBus{ + Cols: int(dev.Columns), + Rows: int(dev.Rows), + IconSize: dev.Pixels, + } + conn.Export(s, "/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd") + conn.Export(introspect.Introspectable(intro), "/com/thejonsey/streamdeckd", + "org.freedesktop.DBus.Introspectable") + reply, err := conn.RequestName("com.thejonsey.streamdeckd", + dbus.NameFlagDoNotQueue) + if err != nil { + panic(err) + } + if reply != dbus.RequestNameReplyPrimaryOwner { + fmt.Fprintln(os.Stderr, "name already taken") + os.Exit(1) + } + select {} +} \ No newline at end of file diff --git a/go.mod b/go.mod index 018a0ed..ac8a774 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( github.com/fogleman/gg v1.3.0 + github.com/godbus/dbus/v5 v5.0.3 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 diff --git a/go.sum b/go.sum index 8c34da6..e9352cf 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= +github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= @@ -40,8 +42,6 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/h2non/bimg v1.1.2 h1:J75W2eM5FT0KjcwsL2aiy1Ilu0Xy0ENb0sU+HHUJAvw= -github.com/h2non/bimg v1.1.2/go.mod h1:R3+UiYwkK4rQl6KVFTOFJHitgLbZXBZNFh2cv3AEbp8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -91,12 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ungerik/go-cairo v0.0.0-20191014050614-4a03f432a432 h1:luu+HbKrZKlIjiaclwrldreEEvVPYX/ujRbTGkKz61c= -github.com/ungerik/go-cairo v0.0.0-20191014050614-4a03f432a432/go.mod h1:0ErpLiOxxE1oY+R4stiKut6/DbUJHnOp6U+e4d8zcTs= github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 h1:rLVbYju4iaW8jP64Pafffu9T0wXitOOtu3+qCxzGV1c= github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2/go.mod h1:Tm8jArLxpQy5vGBbHSreHpNRAIYtDV3J3U3UMGRWTXc= -github.com/unix-streamdeck/streamdeck-lib v0.0.0-20200720132322-072961fa1fdd h1:oX6jtZ+/gBcryYn49alkMPbCzqqwyo/7VA17mA4khrQ= -github.com/unix-streamdeck/streamdeck-lib v0.0.0-20200720132322-072961fa1fdd/go.mod h1:EPLAk+jRYZ0zGW7S7bJctr3CLc4bc+tgBrJN7+G1bvc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= diff --git a/handler.go b/handler.go index 91516f5..ecc35dc 100644 --- a/handler.go +++ b/handler.go @@ -6,6 +6,7 @@ import ( type IconHandler interface { Icon(page int, index int, key *Key, dev streamdeck.Device) + Stop() } type KeyHandler interface { diff --git a/interface.go b/interface.go index 72fd2b2..2f92255 100644 --- a/interface.go +++ b/interface.go @@ -76,11 +76,11 @@ func SetPage(config *Config, page int, dev streamdeck.Device) { } else if currentKey.IconHandlerStruct == nil { var handler IconHandler if currentKey.IconHandler == "Gif" { - handler = GifIconHandler{} + handler = &GifIconHandler{true} } else if currentKey.IconHandler == "Counter" { - handler = &CounterIconHandler{0} + handler = &CounterIconHandler{0, true} } else if currentKey.IconHandler == "Time" { - handler = TimeIconHandler{} + handler = &TimeIconHandler{true} } if handler == nil { continue diff --git a/main.go b/main.go index 9c002bd..5c4a68d 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ func main() { } cleanupHook() SetPage(config, 0, dev) + go InitDBUS() Listen() } @@ -77,3 +78,66 @@ func cleanupHook() { os.Exit(0) }() } + +func SetConfig(configString string) error { + unmountHandlers() + var err error + config = nil + err = json.Unmarshal([]byte(configString), &config) + if err != nil { + return err + } + if len(config.Pages) == 0 { + config.Pages = append(config.Pages, Page{}) + } + SetPage(config, p, dev) + return nil +} + +func ReloadConfig() error { + unmountHandlers() + var err error + config, err = readConfig() + if err != nil && !os.IsNotExist(err) { + return err + } + if len(config.Pages) == 0 { + config.Pages = append(config.Pages, Page{}) + } + SetPage(config, p, dev) + return nil +} + +func SaveConfig() error { + f, err := os.OpenFile(os.Getenv("HOME") + "/.streamdeck-config.json", os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0755) + defer f.Close() + if err != nil { + return err + } + var configString []byte + configString, err = json.Marshal(config) + if err != nil { + return err + } + _, err = f.Write(configString) + if err != nil { + return err + } + err = f.Sync() + if err != nil { + return err + } + return nil +} + +func unmountHandlers() { + for i := range config.Pages { + page := config.Pages[i] + for i2 := range page { + key := page[i2] + if key.IconHandlerStruct != nil { + key.IconHandlerStruct.Stop() + } + } + } +} \ No newline at end of file From 54ba77023caa0855ac3be289a4963e685843c972 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 13 Aug 2020 20:26:22 +0100 Subject: [PATCH 05/50] Added DBus to docs --- README.md | 26 ++++++++++++++++++++ dbus.go | 69 +++++++++++++++++++++++++++++++--------------------- go.mod | 2 +- go.sum | 4 +-- interface.go | 3 ++- 5 files changed, 72 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index e10cafb..b365e90 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,29 @@ The actions you can have on a button are: - `url`: opens a url in your default browser via xdg - `brightness`: set the brightness of the streamdeck as a percentage - `switch_page`: change the active page on the streamdeck + + +### D-Bus + +There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.thejonsey.streamdeck` and `com/thejonsey/streamdeck` respectively, and is made up of the following methods/signals + +#### Methods + +- GetConfig - returns the current running config +- SetConfig - sets the config, without saving to disk, takes in Stringified json, returns an error if anything breaks +- ReloadConfig - reloads the config from disk +- GetDeckInfo - Returns information about the active streamdeck in the format of +```json +{ + "icon_size": 72, + "rows": 3, + "cols": 5, + "page": 0 +} +``` +- SetPage - Set the page on the streamdeck to the number passed to it, returns an error if anything breaks +- CommitConfig - Commits the currently active config to disk, returns an error if anything breaks + +#### Signals + +- Page - sends the number of the page switched to on the StreamDeck diff --git a/dbus.go b/dbus.go index e78a8de..5a92973 100644 --- a/dbus.go +++ b/dbus.go @@ -4,36 +4,40 @@ import ( "encoding/json" "fmt" "github.com/godbus/dbus/v5" - "github.com/godbus/dbus/v5/introspect" "log" "os" ) -const intro = ` - - - - - - - - - - - - - - - - - - - ` + introspect.IntrospectDataString + ` ` +//const intro = ` +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// +// ` + introspect.IntrospectDataString + ` ` + +var conn *dbus.Conn + +var s *StreamDeckDBus type StreamDeckDBus struct { Cols int `json:"cols,omitempty"` Rows int `json:"rows,omitempty"` - IconSize uint `json:"icon_size,omitempty"` + IconSize int `json:"icon_size,omitempty"` + Page int `json:"page"` } func (s StreamDeckDBus) GetDeckInfo() (string, *dbus.Error) { @@ -82,20 +86,20 @@ func (StreamDeckDBus) CommitConfig() *dbus.Error { } func InitDBUS() { - conn, err := dbus.SessionBus() + var err error + conn, err = dbus.SessionBus() if err != nil { log.Println(err) } defer conn.Close() - s := StreamDeckDBus{ + s = &StreamDeckDBus{ Cols: int(dev.Columns), Rows: int(dev.Rows), - IconSize: dev.Pixels, + IconSize: int(dev.Pixels), + Page: p, } - conn.Export(s, "/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd") - conn.Export(introspect.Introspectable(intro), "/com/thejonsey/streamdeckd", - "org.freedesktop.DBus.Introspectable") + conn.ExportAll(s, "/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd") reply, err := conn.RequestName("com.thejonsey.streamdeckd", dbus.NameFlagDoNotQueue) if err != nil { @@ -106,4 +110,13 @@ func InitDBUS() { os.Exit(1) } select {} +} + +func EmitPage(page int) { + if conn != nil { + conn.Emit("/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd.Page", page) + } + if s != nil { + s.Page = page + } } \ No newline at end of file diff --git a/go.mod b/go.mod index ac8a774..5900c63 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/fogleman/gg v1.3.0 - github.com/godbus/dbus/v5 v5.0.3 + github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 diff --git a/go.sum b/go.sum index e9352cf..524c56b 100644 --- a/go.sum +++ b/go.sum @@ -25,8 +25,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca h1:ewc47M3S8MAZgSO1yEnPrbmHjtQz6caAhYWOQzPHBok= +github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= diff --git a/interface.go b/interface.go index 2f92255..dfac0e1 100644 --- a/interface.go +++ b/interface.go @@ -48,7 +48,7 @@ func SetKey(currentKey *Key, i int) { } else { img, err := LoadImage(currentKey.Icon) if err != nil { - log.Fatal(err) + log.Panic(err) } currentKey.Buff = img } @@ -92,6 +92,7 @@ func SetPage(config *Config, page int, dev streamdeck.Device) { SetImage(currentKey.Buff, i, p, dev) } } + EmitPage(p) } func HandleInput(key *Key, page int, index int, dev streamdeck.Device) { From 27e9350ad7d11e5128e6e26b062893c9d2f5b0b8 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 17 Aug 2020 18:45:36 +0100 Subject: [PATCH 06/50] Fixed for new packages, and PR gripes --- CounterHandler.go | 7 +++--- GifHandler.go | 9 ++++---- TimeHandler.go | 7 +++--- config.go | 24 ------------------- dbus.go | 31 ++++--------------------- go.mod | 3 ++- go.sum | 4 ++++ handler.go | 14 ----------- interface.go | 23 +++++++++--------- main.go | 59 +++++++++++++++++++++++++++++++++-------------- 10 files changed, 78 insertions(+), 103 deletions(-) delete mode 100644 config.go delete mode 100644 handler.go diff --git a/CounterHandler.go b/CounterHandler.go index 2fe7509..da7ab23 100644 --- a/CounterHandler.go +++ b/CounterHandler.go @@ -2,7 +2,8 @@ package main import ( "github.com/fogleman/gg" - "github.com/unix-streamdeck/streamdeck" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" "strconv" ) @@ -12,7 +13,7 @@ type CounterIconHandler struct { running bool } -func (c *CounterIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { +func (c *CounterIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { if c.running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) @@ -33,7 +34,7 @@ func (c CounterIconHandler) Stop() { type CounterKeyHandler struct{} -func (CounterKeyHandler) Key(page int, index int, key *Key, dev streamdeck.Device) { +func (CounterKeyHandler) Key(page int, index int, key *api.Key, dev streamdeck.Device) { if key.IconHandler != "Counter" { return } diff --git a/GifHandler.go b/GifHandler.go index 051bed0..820241c 100644 --- a/GifHandler.go +++ b/GifHandler.go @@ -1,7 +1,8 @@ package main import ( - "github.com/unix-streamdeck/streamdeck" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" "image/gif" "log" "os" @@ -12,11 +13,11 @@ type GifIconHandler struct { running bool } -func (s *GifIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { +func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { s.running = true f, err := os.Open(key.Icon) if err != nil { - log.Panic(err) + log.Println(err) return } gifs, err := gif.DecodeAll(f) @@ -29,7 +30,7 @@ func (s *GifIconHandler) Stop() { s.running = false } -func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *Key, s *GifIconHandler) { +func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *api.Key, s *GifIconHandler) { for s.running { img := ResizeImage(gifs.Image[gifIndex]) SetImage(img, index, page, dev) diff --git a/TimeHandler.go b/TimeHandler.go index 529efb0..84d91bd 100644 --- a/TimeHandler.go +++ b/TimeHandler.go @@ -2,7 +2,8 @@ package main import ( "github.com/fogleman/gg" - "github.com/unix-streamdeck/streamdeck" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" "strconv" "time" @@ -12,7 +13,7 @@ type TimeIconHandler struct{ running bool } -func (t *TimeIconHandler) Icon(page int, index int, key *Key, dev streamdeck.Device) { +func (t *TimeIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { t.running = true go timeLoop(page, index, dev, key, t) } @@ -21,7 +22,7 @@ func (t *TimeIconHandler) Stop() { t.running = false } -func timeLoop(page int, index int, dev streamdeck.Device, key *Key, handler *TimeIconHandler) { +func timeLoop(page int, index int, dev streamdeck.Device, key *api.Key, handler *TimeIconHandler) { for handler.running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) diff --git a/config.go b/config.go deleted file mode 100644 index 0334ec8..0000000 --- a/config.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import "image" - -type Page []Key - -type Config struct { - Pages []Page `json:"pages"` -} - -type Key struct { - Icon string `json:"icon,omitempty"` - SwitchPage *int `json:"switch_page,omitempty"` - Text string `json:"text,omitempty"` - Keybind string `json:"keybind,omitempty"` - Command string `json:"command,omitempty"` - Brightness *int `json:"brightness,omitempty"` - Url string `json:"url,omitempty"` - IconHandler string `json:"icon_handler,omitempty"` - IconHandlerStruct IconHandler `json:"-"` - KeyHandler string `json:"key_handler,omitempty"` - KeyHandlerStruct KeyHandler `json:"-"` - Buff image.Image `json:"-"` -} \ No newline at end of file diff --git a/dbus.go b/dbus.go index 5a92973..498e483 100644 --- a/dbus.go +++ b/dbus.go @@ -2,32 +2,11 @@ package main import ( "encoding/json" - "fmt" "github.com/godbus/dbus/v5" "log" "os" ) -//const intro = ` -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// -// ` + introspect.IntrospectDataString + ` ` var conn *dbus.Conn @@ -99,14 +78,14 @@ func InitDBUS() { IconSize: int(dev.Pixels), Page: p, } - conn.ExportAll(s, "/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd") - reply, err := conn.RequestName("com.thejonsey.streamdeckd", + conn.ExportAll(s, "/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd") + reply, err := conn.RequestName("com.unixstreamdeck.streamdeckd", dbus.NameFlagDoNotQueue) if err != nil { - panic(err) + log.Println(err) } if reply != dbus.RequestNameReplyPrimaryOwner { - fmt.Fprintln(os.Stderr, "name already taken") + log.Println("name already taken") os.Exit(1) } select {} @@ -114,7 +93,7 @@ func InitDBUS() { func EmitPage(page int) { if conn != nil { - conn.Emit("/com/thejonsey/streamdeckd", "com.thejonsey.streamdeckd.Page", page) + conn.Emit("/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd.Page", page) } if s != nil { s.Page = page diff --git a/go.mod b/go.mod index 5900c63..bb60bce 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 + github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53 + github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20200119044424-58c23975cae1 ) diff --git a/go.sum b/go.sum index 524c56b..0171bbf 100644 --- a/go.sum +++ b/go.sum @@ -91,6 +91,10 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53 h1:os1SjFbe2h6kfDsGRtzFBtjks1o7kjZqx2siCJkJAlQ= +github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53/go.mod h1:H8KAWZfeqmeUe2aqj882c6w1GzSRZl7kskXK6VS4FMo= +github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= +github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 h1:rLVbYju4iaW8jP64Pafffu9T0wXitOOtu3+qCxzGV1c= github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2/go.mod h1:Tm8jArLxpQy5vGBbHSreHpNRAIYtDV3J3U3UMGRWTXc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/handler.go b/handler.go deleted file mode 100644 index ecc35dc..0000000 --- a/handler.go +++ /dev/null @@ -1,14 +0,0 @@ -package main - -import ( - "github.com/unix-streamdeck/streamdeck" -) - -type IconHandler interface { - Icon(page int, index int, key *Key, dev streamdeck.Device) - Stop() -} - -type KeyHandler interface { - Key(page int, index int, key *Key, dev streamdeck.Device) -} diff --git a/interface.go b/interface.go index dfac0e1..740d91b 100644 --- a/interface.go +++ b/interface.go @@ -3,7 +3,8 @@ package main import ( "github.com/fogleman/gg" "github.com/nfnt/resize" - "github.com/unix-streamdeck/streamdeck" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" "image" "image/color" @@ -30,7 +31,7 @@ func LoadImage(path string) (image.Image, error) { } func ResizeImage(img image.Image) image.Image { - return resize.Resize(72, 72, img, resize.Lanczos3) + return resize.Resize(dev.Pixels, dev.Pixels, img, resize.Lanczos3) } func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { @@ -39,7 +40,7 @@ func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { } } -func SetKey(currentKey *Key, i int) { +func SetKey(currentKey *api.Key, i int) { if currentKey.Buff == nil { if currentKey.Icon == "" { img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) @@ -48,7 +49,7 @@ func SetKey(currentKey *Key, i int) { } else { img, err := LoadImage(currentKey.Icon) if err != nil { - log.Panic(err) + log.Println(err) } currentKey.Buff = img } @@ -64,17 +65,17 @@ func SetKey(currentKey *Key, i int) { SetImage(currentKey.Buff, i, p, dev) } -func SetPage(config *Config, page int, dev streamdeck.Device) { +func SetPage(config *api.Config, page int, dev streamdeck.Device) { p = page currentPage := config.Pages[page] - for i := 0; i < 15; i++ { + for i := 0; i < len(currentPage); i++ { currentKey := ¤tPage[i] if currentKey.Buff == nil { if currentKey.IconHandler == "" { SetKey(currentKey, i) } else if currentKey.IconHandlerStruct == nil { - var handler IconHandler + var handler api.IconHandler if currentKey.IconHandler == "Gif" { handler = &GifIconHandler{true} } else if currentKey.IconHandler == "Counter" { @@ -95,7 +96,7 @@ func SetPage(config *Config, page int, dev streamdeck.Device) { EmitPage(p) } -func HandleInput(key *Key, page int, index int, dev streamdeck.Device) { +func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { if key.Command != "" { runCommand(key.Command) } @@ -114,7 +115,7 @@ func HandleInput(key *Key, page int, index int, dev streamdeck.Device) { } if key.KeyHandler != "" { if key.KeyHandlerStruct == nil { - var handler KeyHandler + var handler api.KeyHandler if key.KeyHandler == "Counter" { handler = CounterKeyHandler{} } @@ -130,7 +131,7 @@ func HandleInput(key *Key, page int, index int, dev streamdeck.Device) { func Listen() { kch, err := dev.ReadKeys() if err != nil { - log.Fatal(err) + log.Println(err) } for { select { @@ -138,7 +139,7 @@ func Listen() { if !ok { err = dev.Open() if err != nil { - log.Fatal(err) + log.Println(err) } continue } diff --git a/main.go b/main.go index 5c4a68d..642cb1b 100644 --- a/main.go +++ b/main.go @@ -2,7 +2,8 @@ package main import ( "encoding/json" - "github.com/unix-streamdeck/streamdeck" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -15,27 +16,51 @@ import ( ) var dev streamdeck.Device -var config *Config +var config *api.Config +var configPath = os.Getenv("HOME") + "/.streamdeck-config.json" + +var basicConfig = api.Config{ + Pages: []api.Page{ + { + api.Key{ + }, + }, + }, +} func main() { d, err := streamdeck.Devices() if err != nil { - log.Fatal(err) + log.Println(err) } if len(d) == 0 { - log.Fatal("No Stream Deck devices found.") + log.Println("No Stream Deck devices found.") } dev = d[0] err = dev.Open() if err != nil { - log.Fatal(err) + log.Println(err) } config, err = readConfig() if err != nil && !os.IsNotExist(err) { - log.Fatal(err) + log.Println(err) + } else if os.IsNotExist(err) { + file, err := os.Create(configPath) + if err != nil { + log.Println(err) + } + err = file.Close() + if err != nil { + log.Println(err) + } + config = &basicConfig + err = SaveConfig() + if err != nil { + log.Println(err) + } } if len(config.Pages) == 0 { - config.Pages = append(config.Pages, Page{}) + config.Pages = append(config.Pages, api.Page{}) } cleanupHook() SetPage(config, 0, dev) @@ -43,15 +68,15 @@ func main() { Listen() } -func readConfig() (*Config, error) { - data, err := ioutil.ReadFile(os.Getenv("HOME") + "/.streamdeck-config.json") +func readConfig() (*api.Config, error) { + data, err := ioutil.ReadFile(configPath) if err != nil { - return &Config{}, err + return &api.Config{}, err } - var config Config + var config api.Config err = json.Unmarshal(data, &config) if err != nil { - return &Config{}, err + return &api.Config{}, err } return &config, nil } @@ -61,7 +86,7 @@ func runCommand(command string) { //args := strings.Split(command, " ") c := exec.Command("/bin/sh", "-c", command) if err := c.Start(); err != nil { - panic(err) + log.Println(err) } err := c.Wait() if err != nil { @@ -88,7 +113,7 @@ func SetConfig(configString string) error { return err } if len(config.Pages) == 0 { - config.Pages = append(config.Pages, Page{}) + config.Pages = append(config.Pages, api.Page{}) } SetPage(config, p, dev) return nil @@ -102,18 +127,18 @@ func ReloadConfig() error { return err } if len(config.Pages) == 0 { - config.Pages = append(config.Pages, Page{}) + config.Pages = append(config.Pages, api.Page{}) } SetPage(config, p, dev) return nil } func SaveConfig() error { - f, err := os.OpenFile(os.Getenv("HOME") + "/.streamdeck-config.json", os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0755) - defer f.Close() + f, err := os.OpenFile(configPath, os.O_TRUNC|os.O_RDWR|os.O_CREATE, 0755) if err != nil { return err } + defer f.Close() var configString []byte configString, err = json.Marshal(config) if err != nil { From c15b932db908b5fc20e5637b9eb53320abb44368 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 18 Aug 2020 19:09:19 +0100 Subject: [PATCH 07/50] Handled removing of pointers from and in config --- interface.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface.go b/interface.go index 740d91b..893eacf 100644 --- a/interface.go +++ b/interface.go @@ -103,12 +103,12 @@ func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { if key.Keybind != "" { runCommand("xdotool key " + key.Keybind) } - if key.SwitchPage != nil { - page = (*key.SwitchPage) - 1 + if key.SwitchPage != 0 { + page = key.SwitchPage - 1 SetPage(config, page, dev) } - if key.Brightness != nil { - _ = dev.SetBrightness(uint8(*key.Brightness)) + if key.Brightness != 0 { + _ = dev.SetBrightness(uint8(key.Brightness)) } if key.Url != "" { runCommand("xdg-open " + key.Url) From a88c0f1a1c5130f44182c7b507dca3f5543bf0f0 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 18 Aug 2020 21:00:05 +0100 Subject: [PATCH 08/50] Fixed build and returning error from dbus --- dbus.go | 8 ++++---- go.mod | 2 +- go.sum | 2 ++ main.go | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/dbus.go b/dbus.go index 498e483..483702e 100644 --- a/dbus.go +++ b/dbus.go @@ -2,9 +2,9 @@ package main import ( "encoding/json" + "errors" "github.com/godbus/dbus/v5" "log" - "os" ) @@ -64,7 +64,7 @@ func (StreamDeckDBus) CommitConfig() *dbus.Error { return nil } -func InitDBUS() { +func InitDBUS() error { var err error conn, err = dbus.SessionBus() if err != nil { @@ -83,10 +83,10 @@ func InitDBUS() { dbus.NameFlagDoNotQueue) if err != nil { log.Println(err) + return err } if reply != dbus.RequestNameReplyPrimaryOwner { - log.Println("name already taken") - os.Exit(1) + return errors.New("DBus: Name already taken") } select {} } diff --git a/go.mod b/go.mod index bb60bce..0d6bdc3 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53 + github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20200119044424-58c23975cae1 ) diff --git a/go.sum b/go.sum index 0171bbf..dd52e25 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1 github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53 h1:os1SjFbe2h6kfDsGRtzFBtjks1o7kjZqx2siCJkJAlQ= github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53/go.mod h1:H8KAWZfeqmeUe2aqj882c6w1GzSRZl7kskXK6VS4FMo= +github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 h1:du+OoTUOp1mf/VRdQ8xQMWdR6JrOGbZvDG1nb9BBxHM= +github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2/go.mod h1:rweAXRgCWdCACCuVhmleidq7HnJEO38zBGDe8uQqZ0w= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 h1:rLVbYju4iaW8jP64Pafffu9T0wXitOOtu3+qCxzGV1c= diff --git a/main.go b/main.go index 642cb1b..6e8a72d 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,8 @@ package main import ( "encoding/json" - "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" + "github.com/unix-streamdeck/api" _ "image/gif" _ "image/jpeg" _ "image/png" From ec30b9d8de5ff610cc5829c51ca76a15211ee7d4 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 18 Aug 2020 21:02:55 +0100 Subject: [PATCH 09/50] removed duplicated deps in go.sum --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index dd52e25..c887392 100644 --- a/go.sum +++ b/go.sum @@ -91,14 +91,10 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53 h1:os1SjFbe2h6kfDsGRtzFBtjks1o7kjZqx2siCJkJAlQ= -github.com/unix-streamdeck/api v0.0.0-20200817173730-eb6b93fc8a53/go.mod h1:H8KAWZfeqmeUe2aqj882c6w1GzSRZl7kskXK6VS4FMo= github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 h1:du+OoTUOp1mf/VRdQ8xQMWdR6JrOGbZvDG1nb9BBxHM= github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2/go.mod h1:rweAXRgCWdCACCuVhmleidq7HnJEO38zBGDe8uQqZ0w= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= -github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2 h1:rLVbYju4iaW8jP64Pafffu9T0wXitOOtu3+qCxzGV1c= -github.com/unix-streamdeck/streamdeck v0.0.0-20200727161137-d2d416a422d2/go.mod h1:Tm8jArLxpQy5vGBbHSreHpNRAIYtDV3J3U3UMGRWTXc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= From a1121265ff47a8a91a7e34c67261aa6826840fbd Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 18 Aug 2020 21:09:20 +0100 Subject: [PATCH 10/50] Fixed returning error in dbus --- dbus.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dbus.go b/dbus.go index 483702e..4efccf6 100644 --- a/dbus.go +++ b/dbus.go @@ -69,6 +69,7 @@ func InitDBUS() error { conn, err = dbus.SessionBus() if err != nil { log.Println(err) + return err } defer conn.Close() From 2eba53d4b21633e5c10194fc89cfe330c5774c07 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 24 Aug 2020 16:12:49 +0100 Subject: [PATCH 11/50] Fixed crash on image failing to open --- interface.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface.go b/interface.go index 893eacf..aae6f5f 100644 --- a/interface.go +++ b/interface.go @@ -50,6 +50,7 @@ func SetKey(currentKey *api.Key, i int) { img, err := LoadImage(currentKey.Icon) if err != nil { log.Println(err) + return } currentKey.Buff = img } @@ -62,7 +63,9 @@ func SetKey(currentKey *api.Key, i int) { currentKey.Buff = img.Image() } } - SetImage(currentKey.Buff, i, p, dev) + if currentKey.Buff != nil { + SetImage(currentKey.Buff, i, p, dev) + } } func SetPage(config *api.Config, page int, dev streamdeck.Device) { From 6ed53fc45d138a16b92ef8367ff06b6b29796a1d Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 24 Aug 2020 17:58:37 +0100 Subject: [PATCH 12/50] WIP: Hotplug support --- dbus.go | 26 +++++++++---------- interface.go | 25 +++++++++++++------ main.go | 70 +++++++++++++++++++++++++++++++++++----------------- 3 files changed, 77 insertions(+), 44 deletions(-) diff --git a/dbus.go b/dbus.go index 4efccf6..d58fe58 100644 --- a/dbus.go +++ b/dbus.go @@ -7,16 +7,15 @@ import ( "log" ) - var conn *dbus.Conn -var s *StreamDeckDBus +var sDbus *StreamDeckDBus type StreamDeckDBus struct { - Cols int `json:"cols,omitempty"` - Rows int `json:"rows,omitempty"` + Cols int `json:"cols,omitempty"` + Rows int `json:"rows,omitempty"` IconSize int `json:"icon_size,omitempty"` - Page int `json:"page"` + Page int `json:"page"` } func (s StreamDeckDBus) GetDeckInfo() (string, *dbus.Error) { @@ -43,7 +42,7 @@ func (StreamDeckDBus) ReloadConfig() *dbus.Error { return nil } -func (StreamDeckDBus) SetPage(page int) *dbus.Error { +func (StreamDeckDBus) SetPage(page int) *dbus.Error { SetPage(config, page, dev) return nil } @@ -73,13 +72,10 @@ func InitDBUS() error { } defer conn.Close() - s = &StreamDeckDBus{ - Cols: int(dev.Columns), - Rows: int(dev.Rows), - IconSize: int(dev.Pixels), + sDbus = &StreamDeckDBus{ Page: p, } - conn.ExportAll(s, "/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd") + conn.ExportAll(sDbus, "/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd") reply, err := conn.RequestName("com.unixstreamdeck.streamdeckd", dbus.NameFlagDoNotQueue) if err != nil { @@ -89,14 +85,14 @@ func InitDBUS() error { if reply != dbus.RequestNameReplyPrimaryOwner { return errors.New("DBus: Name already taken") } - select {} + select {} } func EmitPage(page int) { if conn != nil { conn.Emit("/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd.Page", page) } - if s != nil { - s.Page = page + if sDbus != nil { + sDbus.Page = page } -} \ No newline at end of file +} diff --git a/interface.go b/interface.go index aae6f5f..6f618a3 100644 --- a/interface.go +++ b/interface.go @@ -11,6 +11,7 @@ import ( "image/draw" "log" "os" + "strings" ) var p int @@ -35,8 +36,18 @@ func ResizeImage(img image.Image) image.Image { } func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { - if p == page { - dev.SetImage(uint8(i), img) + if p == page && isOpen { + err := dev.SetImage(uint8(i), img) + if err != nil { + if strings.Contains(err.Error(), "hidapi") { + log.Println("Device disconnected") + _ = dev.Close() + isOpen = false + unmountHandlers() + } else { + log.Println(err) + } + } } } @@ -136,14 +147,14 @@ func Listen() { if err != nil { log.Println(err) } - for { + for isOpen { select { case k, ok := <-kch: if !ok { - err = dev.Open() - if err != nil { - log.Println(err) - } + log.Println("Device disconnected") + _ = dev.Close() + isOpen = false + unmountHandlers() continue } if k.Pressed == true { diff --git a/main.go b/main.go index 6e8a72d..4c1f831 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,10 @@ package main import ( "encoding/json" - "github.com/unix-streamdeck/driver" + "errors" + "fmt" "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -17,30 +19,19 @@ import ( var dev streamdeck.Device var config *api.Config -var configPath = os.Getenv("HOME") + "/.streamdeck-config.json" +var configPath = os.Getenv("HOME") + string(os.PathSeparator) + ".streamdeck-config.json" +var isOpen = false var basicConfig = api.Config{ Pages: []api.Page{ { - api.Key{ - }, + api.Key{}, }, }, } func main() { - d, err := streamdeck.Devices() - if err != nil { - log.Println(err) - } - if len(d) == 0 { - log.Println("No Stream Deck devices found.") - } - dev = d[0] - err = dev.Open() - if err != nil { - log.Println(err) - } + var err error config, err = readConfig() if err != nil && !os.IsNotExist(err) { log.Println(err) @@ -63,9 +54,43 @@ func main() { config.Pages = append(config.Pages, api.Page{}) } cleanupHook() - SetPage(config, 0, dev) go InitDBUS() - Listen() + attemptConnection() +} + +func attemptConnection() { + for { + if !isOpen { + _ = openDevice() + if isOpen { + go Listen() + SetPage(config, p, dev) + if sDbus != nil { + sDbus.IconSize = int(dev.Pixels) + sDbus.Rows = int(dev.Rows) + sDbus.Cols = int(dev.Columns) + } + } + } + } +} + +func openDevice() error { + d, err := streamdeck.Devices() + if err != nil { + return err + } + if len(d) == 0 { + return errors.New("No streamdeck devices found") + } + dev = d[0] + err = dev.Open() + if err != nil { + return err + } + isOpen = true + fmt.Println("Device (" + dev.Serial + ") connected") + return err } func readConfig() (*api.Config, error) { @@ -81,7 +106,6 @@ func readConfig() (*api.Config, error) { return &config, nil } - func runCommand(command string) { //args := strings.Split(command, " ") c := exec.Command("/bin/sh", "-c", command) @@ -158,11 +182,13 @@ func SaveConfig() error { func unmountHandlers() { for i := range config.Pages { page := config.Pages[i] - for i2 := range page { - key := page[i2] + for i2 := 0; i2 < len(page); i2++ { + key := &page[i2] if key.IconHandlerStruct != nil { key.IconHandlerStruct.Stop() + key.IconHandlerStruct = nil + key.Buff = nil } } } -} \ No newline at end of file +} From 8e9f44480c49cf477ae4917b697cd04e64779bc6 Mon Sep 17 00:00:00 2001 From: Louis Jones Date: Tue, 25 Aug 2020 16:11:24 +0100 Subject: [PATCH 13/50] Create LICENSE --- LICENSE | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..742bd2c --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2020, unix-streamdeck +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. From f7d731fbee6a794e8347897e89f2c72c58bf1500 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 25 Aug 2020 16:14:28 +0100 Subject: [PATCH 14/50] Refactored resizing of frames to happen before loop --- GifHandler.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/GifHandler.go b/GifHandler.go index 820241c..eced553 100644 --- a/GifHandler.go +++ b/GifHandler.go @@ -3,6 +3,7 @@ package main import ( "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" + "image" "image/gif" "log" "os" @@ -21,24 +22,32 @@ func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck. return } gifs, err := gif.DecodeAll(f) + if err != nil { + log.Println(err) + return + } timeDelay := gifs.Delay[0] - gifIndex := 0 - go loop(gifs, gifIndex, timeDelay, page, index, dev, key, s) + frames := make([]image.Image, len(gifs.Image)) + for i, frame := range gifs.Image { + frames[i] = ResizeImage(frame) + } + go loop(frames, timeDelay, page, index, dev, key, s) } func (s *GifIconHandler) Stop() { s.running = false } -func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *api.Key, s *GifIconHandler) { +func loop(frames []image.Image, timeDelay int, page int, index int, dev streamdeck.Device, key *api.Key, s *GifIconHandler) { + gifIndex := 0 for s.running { - img := ResizeImage(gifs.Image[gifIndex]) + img := frames[gifIndex] SetImage(img, index, page, dev) key.Buff = img gifIndex++ - if gifIndex >= len(gifs.Image) { + if gifIndex >= len(frames) { gifIndex = 0 } time.Sleep(time.Duration(timeDelay * 10000000)) } -} \ No newline at end of file +} From e3ceae0dcaa8fd311b7b67c44865f7048c390440 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 25 Aug 2020 16:15:35 +0100 Subject: [PATCH 15/50] Added semaphore lock around SetImage to prevent handlers running on other threads interfering with each other --- go.mod | 1 + go.sum | 1 + interface.go | 10 ++++++++++ 3 files changed, 12 insertions(+) diff --git a/go.mod b/go.mod index 0d6bdc3..20ebc75 100644 --- a/go.mod +++ b/go.mod @@ -10,4 +10,5 @@ require ( github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20200119044424-58c23975cae1 + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 ) diff --git a/go.sum b/go.sum index c887392..cf3def9 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/interface.go b/interface.go index aae6f5f..7f4873f 100644 --- a/interface.go +++ b/interface.go @@ -1,11 +1,13 @@ package main import ( + "context" "github.com/fogleman/gg" "github.com/nfnt/resize" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" + "golang.org/x/sync/semaphore" "image" "image/color" "image/draw" @@ -14,6 +16,7 @@ import ( ) var p int +var sem = semaphore.NewWeighted(int64(1)) func LoadImage(path string) (image.Image, error) { f, err := os.Open(path) @@ -35,6 +38,13 @@ func ResizeImage(img image.Image) image.Image { } func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { + ctx := context.Background() + err := sem.Acquire(ctx, 1) + if err != nil { + log.Println(err) + return + } + defer sem.Release(1) if p == page { dev.SetImage(uint8(i), img) } From 40f83f8e6dcfcba58fd9ee5e3a662d10d4d365a9 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 25 Aug 2020 16:16:42 +0100 Subject: [PATCH 16/50] Refactored SetPage so all keys on page are rendered on seperate threads, to reduce page change latency --- interface.go | 51 +++++++++++++++++++++++++++++---------------------- main.go | 2 +- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/interface.go b/interface.go index 7f4873f..937adcb 100644 --- a/interface.go +++ b/interface.go @@ -50,7 +50,7 @@ func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { } } -func SetKey(currentKey *api.Key, i int) { +func SetKeyImage(currentKey *api.Key, i int) { if currentKey.Buff == nil { if currentKey.Icon == "" { img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) @@ -83,30 +83,34 @@ func SetPage(config *api.Config, page int, dev streamdeck.Device) { currentPage := config.Pages[page] for i := 0; i < len(currentPage); i++ { currentKey := ¤tPage[i] - if currentKey.Buff == nil { - if currentKey.IconHandler == "" { - SetKey(currentKey, i) + go SetKey(currentKey, i, page, dev) + } + EmitPage(p) +} - } else if currentKey.IconHandlerStruct == nil { - var handler api.IconHandler - if currentKey.IconHandler == "Gif" { - handler = &GifIconHandler{true} - } else if currentKey.IconHandler == "Counter" { - handler = &CounterIconHandler{0, true} - } else if currentKey.IconHandler == "Time" { - handler = &TimeIconHandler{true} - } - if handler == nil { - continue - } - handler.Icon(page, i, currentKey, dev) - currentKey.IconHandlerStruct = handler +func SetKey(currentKey *api.Key, i int, page int, dev streamdeck.Device) { + if currentKey.Buff == nil { + if currentKey.IconHandler == "" { + SetKeyImage(currentKey, i) + + } else if currentKey.IconHandlerStruct == nil { + var handler api.IconHandler + if currentKey.IconHandler == "Gif" { + handler = &GifIconHandler{true} + } else if currentKey.IconHandler == "Counter" { + handler = &CounterIconHandler{0, true} + } else if currentKey.IconHandler == "Time" { + handler = &TimeIconHandler{true} } - } else { - SetImage(currentKey.Buff, i, p, dev) + if handler == nil { + return + } + handler.Icon(page, i, currentKey, dev) + currentKey.IconHandlerStruct = handler } + } else { + SetImage(currentKey.Buff, i, p, dev) } - EmitPage(p) } func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { @@ -121,7 +125,10 @@ func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { SetPage(config, page, dev) } if key.Brightness != 0 { - _ = dev.SetBrightness(uint8(key.Brightness)) + err := dev.SetBrightness(uint8(key.Brightness)) + if err != nil { + log.Println(err) + } } if key.Url != "" { runCommand("xdg-open " + key.Url) diff --git a/main.go b/main.go index 6e8a72d..642cb1b 100644 --- a/main.go +++ b/main.go @@ -2,8 +2,8 @@ package main import ( "encoding/json" - "github.com/unix-streamdeck/driver" "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/driver" _ "image/gif" _ "image/jpeg" _ "image/png" From c7f9a0f9b8719ec9a4c404f34924244945440ec5 Mon Sep 17 00:00:00 2001 From: Louis Jones Date: Tue, 25 Aug 2020 16:27:25 +0100 Subject: [PATCH 17/50] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b365e90..ca3b178 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The actions you can have on a button are: ### D-Bus -There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.thejonsey.streamdeck` and `com/thejonsey/streamdeck` respectively, and is made up of the following methods/signals +There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.unixstreamdeck.streamdeck` and `com/unixstreamdeck/streamdeck` respectively, and is made up of the following methods/signals #### Methods From ec65c18494993e2854ccbfdbf034daddcc4a6411 Mon Sep 17 00:00:00 2001 From: Louis Jones Date: Tue, 25 Aug 2020 16:27:41 +0100 Subject: [PATCH 18/50] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca3b178..51468f7 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ The actions you can have on a button are: ### D-Bus -There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.unixstreamdeck.streamdeck` and `com/unixstreamdeck/streamdeck` respectively, and is made up of the following methods/signals +There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.unixstreamdeck.streamdeckd` and `com/unixstreamdeck/streamdeckd` respectively, and is made up of the following methods/signals #### Methods From 57294fe121e920976c8c7b4326752c36da4a135c Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Wed, 26 Aug 2020 16:34:17 +0100 Subject: [PATCH 19/50] added semaphores around disconnect and reconnect to prevent crash due to double (dis)connect --- dbus.go | 2 +- go.mod | 1 + go.sum | 1 + interface.go | 26 ++++++++++-------------- main.go | 56 +++++++++++++++++++++++++++++++++++++--------------- 5 files changed, 53 insertions(+), 33 deletions(-) diff --git a/dbus.go b/dbus.go index d58fe58..30c823a 100644 --- a/dbus.go +++ b/dbus.go @@ -43,7 +43,7 @@ func (StreamDeckDBus) ReloadConfig() *dbus.Error { } func (StreamDeckDBus) SetPage(page int) *dbus.Error { - SetPage(config, page, dev) + SetPage(config, page) return nil } diff --git a/go.mod b/go.mod index 0d6bdc3..20ebc75 100644 --- a/go.mod +++ b/go.mod @@ -10,4 +10,5 @@ require ( github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20200119044424-58c23975cae1 + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 ) diff --git a/go.sum b/go.sum index c887392..cf3def9 100644 --- a/go.sum +++ b/go.sum @@ -115,6 +115,7 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/interface.go b/interface.go index 6f618a3..a9a34e4 100644 --- a/interface.go +++ b/interface.go @@ -35,15 +35,12 @@ func ResizeImage(img image.Image) image.Image { return resize.Resize(dev.Pixels, dev.Pixels, img, resize.Lanczos3) } -func SetImage(img image.Image, i int, page int, dev streamdeck.Device) { +func SetImage(img image.Image, i int, page int, _ streamdeck.Device) { if p == page && isOpen { err := dev.SetImage(uint8(i), img) if err != nil { if strings.Contains(err.Error(), "hidapi") { - log.Println("Device disconnected") - _ = dev.Close() - isOpen = false - unmountHandlers() + disconnect() } else { log.Println(err) } @@ -79,7 +76,7 @@ func SetKey(currentKey *api.Key, i int) { } } -func SetPage(config *api.Config, page int, dev streamdeck.Device) { +func SetPage(config *api.Config, page int) { p = page currentPage := config.Pages[page] for i := 0; i < len(currentPage); i++ { @@ -100,7 +97,7 @@ func SetPage(config *api.Config, page int, dev streamdeck.Device) { if handler == nil { continue } - handler.Icon(page, i, currentKey, dev) + handler.Icon(page, i, currentKey, streamdeck.Device{}) currentKey.IconHandlerStruct = handler } } else { @@ -110,7 +107,7 @@ func SetPage(config *api.Config, page int, dev streamdeck.Device) { EmitPage(p) } -func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { +func HandleInput(key *api.Key, page int, index int) { if key.Command != "" { runCommand(key.Command) } @@ -119,7 +116,7 @@ func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { } if key.SwitchPage != 0 { page = key.SwitchPage - 1 - SetPage(config, page, dev) + SetPage(config, page) } if key.Brightness != 0 { _ = dev.SetBrightness(uint8(key.Brightness)) @@ -138,7 +135,7 @@ func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { } key.KeyHandlerStruct = handler } - key.KeyHandlerStruct.Key(page, index, key, dev) + key.KeyHandlerStruct.Key(page, index, key, streamdeck.Device{}) } } @@ -151,15 +148,12 @@ func Listen() { select { case k, ok := <-kch: if !ok { - log.Println("Device disconnected") - _ = dev.Close() - isOpen = false - unmountHandlers() - continue + disconnect() + return } if k.Pressed == true { if len(config.Pages)-1 >= p && len(config.Pages[p])-1 >= int(k.Index) { - HandleInput(&config.Pages[p][k.Index], p, int(k.Index), dev) + HandleInput(&config.Pages[p][k.Index], p, int(k.Index)) } } } diff --git a/main.go b/main.go index 4c1f831..9956d7c 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,13 @@ package main import ( + "context" "encoding/json" "errors" "fmt" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" + "golang.org/x/sync/semaphore" _ "image/gif" _ "image/jpeg" _ "image/png" @@ -21,6 +23,8 @@ var dev streamdeck.Device var config *api.Config var configPath = os.Getenv("HOME") + string(os.PathSeparator) + ".streamdeck-config.json" var isOpen = false +var disconnectSem = semaphore.NewWeighted(1) +var connectSem = semaphore.NewWeighted(1) var basicConfig = api.Config{ Pages: []api.Page{ @@ -59,23 +63,43 @@ func main() { } func attemptConnection() { - for { - if !isOpen { - _ = openDevice() - if isOpen { - go Listen() - SetPage(config, p, dev) - if sDbus != nil { - sDbus.IconSize = int(dev.Pixels) - sDbus.Rows = int(dev.Rows) - sDbus.Cols = int(dev.Columns) - } + for !isOpen { + _ = openDevice() + if isOpen { + SetPage(config, p) + if sDbus != nil { + sDbus.IconSize = int(dev.Pixels) + sDbus.Rows = int(dev.Rows) + sDbus.Cols = int(dev.Columns) } + Listen() } } } +func disconnect() { + ctx := context.Background() + err := disconnectSem.Acquire(ctx, 1) + if err != nil { + return + } + defer disconnectSem.Release(1) + if !isOpen { + return + } + log.Println("Device disconnected") + _ = dev.Close() + isOpen = false + unmountHandlers() +} + func openDevice() error { + ctx := context.Background() + err := connectSem.Acquire(ctx, 1) + if err != nil { + return err + } + defer connectSem.Release(1) d, err := streamdeck.Devices() if err != nil { return err @@ -83,14 +107,14 @@ func openDevice() error { if len(d) == 0 { return errors.New("No streamdeck devices found") } - dev = d[0] - err = dev.Open() + err = d[0].Open() if err != nil { return err } + dev = d[0] isOpen = true fmt.Println("Device (" + dev.Serial + ") connected") - return err + return nil } func readConfig() (*api.Config, error) { @@ -139,7 +163,7 @@ func SetConfig(configString string) error { if len(config.Pages) == 0 { config.Pages = append(config.Pages, api.Page{}) } - SetPage(config, p, dev) + SetPage(config, p) return nil } @@ -153,7 +177,7 @@ func ReloadConfig() error { if len(config.Pages) == 0 { config.Pages = append(config.Pages, api.Page{}) } - SetPage(config, p, dev) + SetPage(config, p) return nil } From 928b48d5ba1145bb764eca0b196bde5b6498bd93 Mon Sep 17 00:00:00 2001 From: Stephen Houston Date: Wed, 26 Aug 2020 19:09:10 -0500 Subject: [PATCH 20/50] Factor handlers out into their own package --- CounterHandler.go => handlers/counter.go | 19 +++++++------------ GifHandler.go => handlers/gif.go | 17 +++++++---------- handlers/handlers.go | 23 +++++++++++++++++++++++ TimeHandler.go => handlers/time.go | 13 +++++-------- interface.go | 9 +++++---- 5 files changed, 47 insertions(+), 34 deletions(-) rename CounterHandler.go => handlers/counter.go (74%) rename GifHandler.go => handlers/gif.go (76%) create mode 100644 handlers/handlers.go rename TimeHandler.go => handlers/time.go (84%) diff --git a/CounterHandler.go b/handlers/counter.go similarity index 74% rename from CounterHandler.go rename to handlers/counter.go index da7ab23..d1e543e 100644 --- a/CounterHandler.go +++ b/handlers/counter.go @@ -1,4 +1,4 @@ -package main +package handlers import ( "github.com/fogleman/gg" @@ -8,28 +8,23 @@ import ( "strconv" ) -type CounterIconHandler struct { - count int - running bool -} - func (c *CounterIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { - if c.running { + if c.Running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) img.Clear() img.SetRGB(1, 1, 1) img.SetFontFace(inconsolata.Regular8x16) - count := strconv.Itoa(c.count) - img.DrawStringAnchored(count, 72/2, 72/2, 0.5, 0.5) + Count := strconv.Itoa(c.Count) + img.DrawStringAnchored(Count, 72/2, 72/2, 0.5, 0.5) img.Clip() - SetImage(img.Image(), index, page, dev) + c.OnSetImage(img.Image(), index, page, dev) key.Buff = img.Image() } } func (c CounterIconHandler) Stop() { - c.running = false + c.Running = false } type CounterKeyHandler struct{} @@ -39,6 +34,6 @@ func (CounterKeyHandler) Key(page int, index int, key *api.Key, dev streamdeck.D return } handler := key.IconHandlerStruct.(*CounterIconHandler) - handler.count += 1 + handler.Count += 1 handler.Icon(page, index, key, dev) } diff --git a/GifHandler.go b/handlers/gif.go similarity index 76% rename from GifHandler.go rename to handlers/gif.go index 820241c..c264fef 100644 --- a/GifHandler.go +++ b/handlers/gif.go @@ -1,20 +1,17 @@ -package main +package handlers import ( "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" + "github.com/nfnt/resize" "image/gif" "log" "os" "time" ) -type GifIconHandler struct { - running bool -} - func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { - s.running = true + s.Running = true f, err := os.Open(key.Icon) if err != nil { log.Println(err) @@ -27,13 +24,13 @@ func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck. } func (s *GifIconHandler) Stop() { - s.running = false + s.Running = false } func loop(gifs *gif.GIF, gifIndex int, timeDelay int, page int, index int, dev streamdeck.Device, key *api.Key, s *GifIconHandler) { - for s.running { - img := ResizeImage(gifs.Image[gifIndex]) - SetImage(img, index, page, dev) + for s.Running { + img := resize.Resize(dev.Pixels, dev.Pixels, gifs.Image[gifIndex], resize.Lanczos3) + s.OnSetImage(img, index, page, dev) key.Buff = img gifIndex++ if gifIndex >= len(gifs.Image) { diff --git a/handlers/handlers.go b/handlers/handlers.go new file mode 100644 index 0000000..567ec13 --- /dev/null +++ b/handlers/handlers.go @@ -0,0 +1,23 @@ +package handlers + +import ( + "image" + "github.com/unix-streamdeck/driver" +) + +type CounterIconHandler struct { + Count int + Running bool + OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) +} + +type GifIconHandler struct { + Running bool + OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) +} + +type TimeIconHandler struct{ + Running bool + OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) +} + diff --git a/TimeHandler.go b/handlers/time.go similarity index 84% rename from TimeHandler.go rename to handlers/time.go index 84d91bd..81e9180 100644 --- a/TimeHandler.go +++ b/handlers/time.go @@ -1,4 +1,4 @@ -package main +package handlers import ( "github.com/fogleman/gg" @@ -9,21 +9,18 @@ import ( "time" ) -type TimeIconHandler struct{ - running bool -} func (t *TimeIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { - t.running = true + t.Running = true go timeLoop(page, index, dev, key, t) } func (t *TimeIconHandler) Stop() { - t.running = false + t.Running = false } func timeLoop(page int, index int, dev streamdeck.Device, key *api.Key, handler *TimeIconHandler) { - for handler.running { + for handler.Running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) img.Clear() @@ -33,7 +30,7 @@ func timeLoop(page int, index int, dev streamdeck.Device, key *api.Key, handler tString := t.Format("15:04:05") img.DrawStringAnchored(tString, 72/2, 72/2, 0.5, 0.5) img.Clip() - SetImage(img.Image(), index, page, dev) + handler.OnSetImage(img.Image(), index, page, dev) key.Buff = img.Image() time.Sleep(time.Second) } diff --git a/interface.go b/interface.go index 893eacf..0de4173 100644 --- a/interface.go +++ b/interface.go @@ -6,6 +6,7 @@ import ( "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" + "github.com/unix-streamdeck/streamdeckd/handlers" "image" "image/color" "image/draw" @@ -77,11 +78,11 @@ func SetPage(config *api.Config, page int, dev streamdeck.Device) { } else if currentKey.IconHandlerStruct == nil { var handler api.IconHandler if currentKey.IconHandler == "Gif" { - handler = &GifIconHandler{true} + handler = &handlers.GifIconHandler{Running:true, OnSetImage: SetImage} } else if currentKey.IconHandler == "Counter" { - handler = &CounterIconHandler{0, true} + handler = &handlers.CounterIconHandler{Count:0, Running: true, OnSetImage: SetImage} } else if currentKey.IconHandler == "Time" { - handler = &TimeIconHandler{true} + handler = &handlers.TimeIconHandler{Running:true, OnSetImage: SetImage} } if handler == nil { continue @@ -117,7 +118,7 @@ func HandleInput(key *api.Key, page int, index int, dev streamdeck.Device) { if key.KeyHandlerStruct == nil { var handler api.KeyHandler if key.KeyHandler == "Counter" { - handler = CounterKeyHandler{} + handler = handlers.CounterKeyHandler{} } if handler == nil { return From e5df054e6eb6d9a98c7d88027c6c11424d4ba7aa Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 27 Aug 2020 15:46:20 +0100 Subject: [PATCH 21/50] Sorted imports --- interface.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface.go b/interface.go index b2d3c9b..645a3e1 100644 --- a/interface.go +++ b/interface.go @@ -5,8 +5,8 @@ import ( "github.com/nfnt/resize" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" - "golang.org/x/image/font/inconsolata" "github.com/unix-streamdeck/streamdeckd/handlers" + "golang.org/x/image/font/inconsolata" "image" "image/color" "image/draw" @@ -98,7 +98,7 @@ func SetPage(config *api.Config, page int) { if handler == nil { continue } - handler.Icon(page, i, currentKey, streamdeck.Device{}) + handler.Icon(page, i, currentKey, dev) currentKey.IconHandlerStruct = handler } } else { From 250a249b09e09bbc77f7a6bd9996ed4420980185 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 27 Aug 2020 16:15:18 +0100 Subject: [PATCH 22/50] Refactored handlers --- dbus.go | 11 +++++------ handlers/counter.go | 17 ++++++++++++----- handlers/gif.go | 11 +++++------ handlers/handlers.go | 9 ++------- handlers/time.go | 23 +++++++---------------- interface.go | 27 ++++++++++++++------------- main.go | 6 +++--- 7 files changed, 48 insertions(+), 56 deletions(-) diff --git a/dbus.go b/dbus.go index 30c823a..4c7da8e 100644 --- a/dbus.go +++ b/dbus.go @@ -4,18 +4,16 @@ import ( "encoding/json" "errors" "github.com/godbus/dbus/v5" + "github.com/unix-streamdeck/api" "log" ) var conn *dbus.Conn var sDbus *StreamDeckDBus +var sDInfo api.StreamDeckInfo type StreamDeckDBus struct { - Cols int `json:"cols,omitempty"` - Rows int `json:"rows,omitempty"` - IconSize int `json:"icon_size,omitempty"` - Page int `json:"page"` } func (s StreamDeckDBus) GetDeckInfo() (string, *dbus.Error) { @@ -72,7 +70,8 @@ func InitDBUS() error { } defer conn.Close() - sDbus = &StreamDeckDBus{ + sDbus = &StreamDeckDBus{} + sDInfo = api.StreamDeckInfo{ Page: p, } conn.ExportAll(sDbus, "/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd") @@ -93,6 +92,6 @@ func EmitPage(page int) { conn.Emit("/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd.Page", page) } if sDbus != nil { - sDbus.Page = page + sDInfo.Page = page } } diff --git a/handlers/counter.go b/handlers/counter.go index d1e543e..f733e06 100644 --- a/handlers/counter.go +++ b/handlers/counter.go @@ -3,12 +3,16 @@ package handlers import ( "github.com/fogleman/gg" "github.com/unix-streamdeck/api" - "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" + "image" "strconv" + "time" ) -func (c *CounterIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { +func (c *CounterIconHandler) Icon(key *api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { + if c.Callback == nil { + c.Callback = callback + } if c.Running { img := gg.NewContext(72, 72) img.SetRGB(0, 0, 0) @@ -18,8 +22,9 @@ func (c *CounterIconHandler) Icon(page int, index int, key *api.Key, dev streamd Count := strconv.Itoa(c.Count) img.DrawStringAnchored(Count, 72/2, 72/2, 0.5, 0.5) img.Clip() - c.OnSetImage(img.Image(), index, page, dev) + callback(img.Image()) key.Buff = img.Image() + time.Sleep(250 * time.Millisecond) } } @@ -29,11 +34,13 @@ func (c CounterIconHandler) Stop() { type CounterKeyHandler struct{} -func (CounterKeyHandler) Key(page int, index int, key *api.Key, dev streamdeck.Device) { +func (CounterKeyHandler) Key(key *api.Key, info api.StreamDeckInfo) { if key.IconHandler != "Counter" { return } handler := key.IconHandlerStruct.(*CounterIconHandler) handler.Count += 1 - handler.Icon(page, index, key, dev) + if handler.Callback != nil { + handler.Icon(key, info, handler.Callback) + } } diff --git a/handlers/gif.go b/handlers/gif.go index 58cbd0c..1224c0b 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -3,7 +3,6 @@ package handlers import ( "github.com/nfnt/resize" "github.com/unix-streamdeck/api" - "github.com/unix-streamdeck/driver" "image" "image/gif" "log" @@ -11,7 +10,7 @@ import ( "time" ) -func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { +func (s *GifIconHandler) Icon(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { s.Running = true f, err := os.Open(key.Icon) if err != nil { @@ -26,20 +25,20 @@ func (s *GifIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck. timeDelay := gifs.Delay[0] frames := make([]image.Image, len(gifs.Image)) for i, frame := range gifs.Image { - frames[i] = resize.Resize(dev.Pixels, dev.Pixels, frame, resize.Lanczos3) + frames[i] = resize.Resize(uint(info.IconSize), uint(info.IconSize), frame, resize.Lanczos3) } - go loop(frames, timeDelay, page, index, dev, key, s) + go loop(frames, timeDelay, callback, key, s) } func (s *GifIconHandler) Stop() { s.Running = false } -func loop(frames []image.Image, timeDelay int, page int, index int, dev streamdeck.Device, key *api.Key, s *GifIconHandler) { +func loop(frames []image.Image, timeDelay int, callback func(image image.Image), key *api.Key, s *GifIconHandler) { gifIndex := 0 for s.Running { img := frames[gifIndex] - s.OnSetImage(img, index, page, dev) + callback(img) key.Buff = img gifIndex++ if gifIndex >= len(frames) { diff --git a/handlers/handlers.go b/handlers/handlers.go index 567ec13..35f3735 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -1,23 +1,18 @@ package handlers -import ( - "image" - "github.com/unix-streamdeck/driver" -) +import "image" type CounterIconHandler struct { Count int Running bool - OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) + Callback func(image image.Image) } type GifIconHandler struct { Running bool - OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) } type TimeIconHandler struct{ Running bool - OnSetImage func(img image.Image, i int, page int, dev streamdeck.Device) } diff --git a/handlers/time.go b/handlers/time.go index 81e9180..7d989cd 100644 --- a/handlers/time.go +++ b/handlers/time.go @@ -3,43 +3,34 @@ package handlers import ( "github.com/fogleman/gg" "github.com/unix-streamdeck/api" - "github.com/unix-streamdeck/driver" "golang.org/x/image/font/inconsolata" - "strconv" + "image" "time" ) -func (t *TimeIconHandler) Icon(page int, index int, key *api.Key, dev streamdeck.Device) { +func (t *TimeIconHandler) Icon(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true - go timeLoop(page, index, dev, key, t) + go timeLoop(key, info, callback, t) } func (t *TimeIconHandler) Stop() { t.Running = false } -func timeLoop(page int, index int, dev streamdeck.Device, key *api.Key, handler *TimeIconHandler) { +func timeLoop(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { for handler.Running { - img := gg.NewContext(72, 72) + img := gg.NewContext(info.IconSize, info.IconSize) img.SetRGB(0, 0, 0) img.Clear() img.SetRGB(1, 1, 1) img.SetFontFace(inconsolata.Regular8x16) t := time.Now() tString := t.Format("15:04:05") - img.DrawStringAnchored(tString, 72/2, 72/2, 0.5, 0.5) + img.DrawStringAnchored(tString, float64(info.IconSize)/2, float64(info.IconSize)/2, 0.5, 0.5) img.Clip() - handler.OnSetImage(img.Image(), index, page, dev) + callback(img.Image()) key.Buff = img.Image() time.Sleep(time.Second) } -} - -func zeroes(i int) (string) { - if i < 10 { - return "0" + strconv.Itoa(i) - } else { - return strconv.Itoa(i) - } } \ No newline at end of file diff --git a/interface.go b/interface.go index 3c79a89..a023af2 100644 --- a/interface.go +++ b/interface.go @@ -5,7 +5,6 @@ import ( "github.com/fogleman/gg" "github.com/nfnt/resize" "github.com/unix-streamdeck/api" - "github.com/unix-streamdeck/driver" "github.com/unix-streamdeck/streamdeckd/handlers" "golang.org/x/image/font/inconsolata" "golang.org/x/sync/semaphore" @@ -39,7 +38,7 @@ func ResizeImage(img image.Image) image.Image { return resize.Resize(dev.Pixels, dev.Pixels, img, resize.Lanczos3) } -func SetImage(img image.Image, i int, page int, _ streamdeck.Device) { +func SetImage(img image.Image, i int, page int) { ctx := context.Background() err := sem.Acquire(ctx, 1) if err != nil { @@ -83,7 +82,7 @@ func SetKeyImage(currentKey *api.Key, i int) { } } if currentKey.Buff != nil { - SetImage(currentKey.Buff, i, p, dev) + SetImage(currentKey.Buff, i, p) } } @@ -92,12 +91,12 @@ func SetPage(config *api.Config, page int) { currentPage := config.Pages[page] for i := 0; i < len(currentPage); i++ { currentKey := ¤tPage[i] - go SetKey(currentKey, i, page, dev) + go SetKey(currentKey, i, page) } EmitPage(p) } -func SetKey(currentKey *api.Key, i int, page int, dev streamdeck.Device) { +func SetKey(currentKey *api.Key, i int, page int) { if currentKey.Buff == nil { if currentKey.IconHandler == "" { SetKeyImage(currentKey, i) @@ -105,24 +104,26 @@ func SetKey(currentKey *api.Key, i int, page int, dev streamdeck.Device) { } else if currentKey.IconHandlerStruct == nil { var handler api.IconHandler if currentKey.IconHandler == "Gif" { - handler = &handlers.GifIconHandler{Running:true, OnSetImage: SetImage} + handler = &handlers.GifIconHandler{Running:true} } else if currentKey.IconHandler == "Counter" { - handler = &handlers.CounterIconHandler{Count:0, Running: true, OnSetImage: SetImage} + handler = &handlers.CounterIconHandler{Count:0, Running: true} } else if currentKey.IconHandler == "Time" { - handler = &handlers.TimeIconHandler{Running:true, OnSetImage: SetImage} + handler = &handlers.TimeIconHandler{Running:true} } if handler == nil { return } - handler.Icon(page, i, currentKey, dev) + handler.Icon(currentKey, sDInfo, func(image image.Image) { + SetImage(image, i, page) + }) currentKey.IconHandlerStruct = handler } } else { - SetImage(currentKey.Buff, i, p, dev) + SetImage(currentKey.Buff, i, p) } } -func HandleInput(key *api.Key, page int, index int) { +func HandleInput(key *api.Key, page int) { if key.Command != "" { runCommand(key.Command) } @@ -153,7 +154,7 @@ func HandleInput(key *api.Key, page int, index int) { } key.KeyHandlerStruct = handler } - key.KeyHandlerStruct.Key(page, index, key, streamdeck.Device{}) + key.KeyHandlerStruct.Key(key, sDInfo) } } @@ -171,7 +172,7 @@ func Listen() { } if k.Pressed == true { if len(config.Pages)-1 >= p && len(config.Pages[p])-1 >= int(k.Index) { - HandleInput(&config.Pages[p][k.Index], p, int(k.Index)) + HandleInput(&config.Pages[p][k.Index], p) } } } diff --git a/main.go b/main.go index 9956d7c..2912a52 100644 --- a/main.go +++ b/main.go @@ -68,9 +68,9 @@ func attemptConnection() { if isOpen { SetPage(config, p) if sDbus != nil { - sDbus.IconSize = int(dev.Pixels) - sDbus.Rows = int(dev.Rows) - sDbus.Cols = int(dev.Columns) + sDInfo.IconSize = int(dev.Pixels) + sDInfo.Rows = int(dev.Rows) + sDInfo.Cols = int(dev.Columns) } Listen() } From d67c5653072436f1d66fe8232ba7a1f7eeade6be Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 27 Aug 2020 17:26:47 +0100 Subject: [PATCH 23/50] Removed key pointer in handlers --- handlers/counter.go | 5 ++--- handlers/gif.go | 7 +++---- handlers/handlers.go | 7 +++---- handlers/time.go | 7 +++---- interface.go | 5 +++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/handlers/counter.go b/handlers/counter.go index f733e06..5a652ce 100644 --- a/handlers/counter.go +++ b/handlers/counter.go @@ -9,7 +9,7 @@ import ( "time" ) -func (c *CounterIconHandler) Icon(key *api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { +func (c *CounterIconHandler) Icon(_ api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { if c.Callback == nil { c.Callback = callback } @@ -23,7 +23,6 @@ func (c *CounterIconHandler) Icon(key *api.Key, _ api.StreamDeckInfo, callback f img.DrawStringAnchored(Count, 72/2, 72/2, 0.5, 0.5) img.Clip() callback(img.Image()) - key.Buff = img.Image() time.Sleep(250 * time.Millisecond) } } @@ -34,7 +33,7 @@ func (c CounterIconHandler) Stop() { type CounterKeyHandler struct{} -func (CounterKeyHandler) Key(key *api.Key, info api.StreamDeckInfo) { +func (CounterKeyHandler) Key(key api.Key, info api.StreamDeckInfo) { if key.IconHandler != "Counter" { return } diff --git a/handlers/gif.go b/handlers/gif.go index 1224c0b..4d3bb3e 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -10,7 +10,7 @@ import ( "time" ) -func (s *GifIconHandler) Icon(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (s *GifIconHandler) Icon(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { s.Running = true f, err := os.Open(key.Icon) if err != nil { @@ -27,19 +27,18 @@ func (s *GifIconHandler) Icon(key *api.Key, info api.StreamDeckInfo, callback fu for i, frame := range gifs.Image { frames[i] = resize.Resize(uint(info.IconSize), uint(info.IconSize), frame, resize.Lanczos3) } - go loop(frames, timeDelay, callback, key, s) + go loop(frames, timeDelay, callback, s) } func (s *GifIconHandler) Stop() { s.Running = false } -func loop(frames []image.Image, timeDelay int, callback func(image image.Image), key *api.Key, s *GifIconHandler) { +func loop(frames []image.Image, timeDelay int, callback func(image image.Image), s *GifIconHandler) { gifIndex := 0 for s.Running { img := frames[gifIndex] callback(img) - key.Buff = img gifIndex++ if gifIndex >= len(frames) { gifIndex = 0 diff --git a/handlers/handlers.go b/handlers/handlers.go index 35f3735..d7a3f22 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -3,8 +3,8 @@ package handlers import "image" type CounterIconHandler struct { - Count int - Running bool + Count int + Running bool Callback func(image image.Image) } @@ -12,7 +12,6 @@ type GifIconHandler struct { Running bool } -type TimeIconHandler struct{ +type TimeIconHandler struct { Running bool } - diff --git a/handlers/time.go b/handlers/time.go index 7d989cd..c1adfee 100644 --- a/handlers/time.go +++ b/handlers/time.go @@ -9,16 +9,16 @@ import ( ) -func (t *TimeIconHandler) Icon(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (t *TimeIconHandler) Icon(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true - go timeLoop(key, info, callback, t) + go timeLoop(info, callback, t) } func (t *TimeIconHandler) Stop() { t.Running = false } -func timeLoop(key *api.Key, info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { +func timeLoop(info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { for handler.Running { img := gg.NewContext(info.IconSize, info.IconSize) img.SetRGB(0, 0, 0) @@ -30,7 +30,6 @@ func timeLoop(key *api.Key, info api.StreamDeckInfo, callback func(image image.I img.DrawStringAnchored(tString, float64(info.IconSize)/2, float64(info.IconSize)/2, 0.5, 0.5) img.Clip() callback(img.Image()) - key.Buff = img.Image() time.Sleep(time.Second) } } \ No newline at end of file diff --git a/interface.go b/interface.go index a023af2..539f7df 100644 --- a/interface.go +++ b/interface.go @@ -113,8 +113,9 @@ func SetKey(currentKey *api.Key, i int, page int) { if handler == nil { return } - handler.Icon(currentKey, sDInfo, func(image image.Image) { + handler.Icon(*currentKey, sDInfo, func(image image.Image) { SetImage(image, i, page) + currentKey.Buff = image }) currentKey.IconHandlerStruct = handler } @@ -154,7 +155,7 @@ func HandleInput(key *api.Key, page int) { } key.KeyHandlerStruct = handler } - key.KeyHandlerStruct.Key(key, sDInfo) + key.KeyHandlerStruct.Key(*key, sDInfo) } } From 7737f2525880b0f33c6f426f4b62d5695fd71e66 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 27 Aug 2020 18:01:35 +0100 Subject: [PATCH 24/50] Refactored remounting handlers --- handlers/counter.go | 12 ++++++++++-- handlers/gif.go | 10 +++++++++- handlers/time.go | 10 +++++++++- interface.go | 9 ++++++++- main.go | 2 -- 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/handlers/counter.go b/handlers/counter.go index 5a652ce..a0c1e59 100644 --- a/handlers/counter.go +++ b/handlers/counter.go @@ -9,7 +9,7 @@ import ( "time" ) -func (c *CounterIconHandler) Icon(_ api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { +func (c *CounterIconHandler) Start(_ api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { if c.Callback == nil { c.Callback = callback } @@ -27,6 +27,14 @@ func (c *CounterIconHandler) Icon(_ api.Key, _ api.StreamDeckInfo, callback func } } +func (c *CounterIconHandler) IsRunning() bool { + return c.Running +} + +func (c *CounterIconHandler) SetRunning(running bool) { + c.Running = running +} + func (c CounterIconHandler) Stop() { c.Running = false } @@ -40,6 +48,6 @@ func (CounterKeyHandler) Key(key api.Key, info api.StreamDeckInfo) { handler := key.IconHandlerStruct.(*CounterIconHandler) handler.Count += 1 if handler.Callback != nil { - handler.Icon(key, info, handler.Callback) + handler.Start(key, info, handler.Callback) } } diff --git a/handlers/gif.go b/handlers/gif.go index 4d3bb3e..d0ff4b4 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -10,7 +10,7 @@ import ( "time" ) -func (s *GifIconHandler) Icon(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { s.Running = true f, err := os.Open(key.Icon) if err != nil { @@ -30,6 +30,14 @@ func (s *GifIconHandler) Icon(key api.Key, info api.StreamDeckInfo, callback fun go loop(frames, timeDelay, callback, s) } +func (s *GifIconHandler) IsRunning() bool { + return s.Running +} + +func (s *GifIconHandler) SetRunning(running bool) { + s.Running = running +} + func (s *GifIconHandler) Stop() { s.Running = false } diff --git a/handlers/time.go b/handlers/time.go index c1adfee..a7595eb 100644 --- a/handlers/time.go +++ b/handlers/time.go @@ -9,11 +9,19 @@ import ( ) -func (t *TimeIconHandler) Icon(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (t *TimeIconHandler) Start(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true go timeLoop(info, callback, t) } +func (t *TimeIconHandler) IsRunning() bool { + return t.Running +} + +func (t *TimeIconHandler) SetRunning(running bool) { + t.Running = running +} + func (t *TimeIconHandler) Stop() { t.Running = false } diff --git a/interface.go b/interface.go index 539f7df..b977f07 100644 --- a/interface.go +++ b/interface.go @@ -113,7 +113,7 @@ func SetKey(currentKey *api.Key, i int, page int) { if handler == nil { return } - handler.Icon(*currentKey, sDInfo, func(image image.Image) { + handler.Start(*currentKey, sDInfo, func(image image.Image) { SetImage(image, i, page) currentKey.Buff = image }) @@ -122,6 +122,13 @@ func SetKey(currentKey *api.Key, i int, page int) { } else { SetImage(currentKey.Buff, i, p) } + if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { + currentKey.IconHandlerStruct.SetRunning(true) + currentKey.IconHandlerStruct.Start(*currentKey, sDInfo, func(image image.Image) { + SetImage(image, i, page) + currentKey.Buff = image + }) + } } func HandleInput(key *api.Key, page int) { diff --git a/main.go b/main.go index 2912a52..54c99da 100644 --- a/main.go +++ b/main.go @@ -210,8 +210,6 @@ func unmountHandlers() { key := &page[i2] if key.IconHandlerStruct != nil { key.IconHandlerStruct.Stop() - key.IconHandlerStruct = nil - key.Buff = nil } } } From 1b17e171ea64fdf1e14d6f54294c04959c93a3da Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Fri, 28 Aug 2020 01:06:27 +0100 Subject: [PATCH 25/50] Updated unix-streamdeck/api version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 20ebc75..b5898cf 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 + github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20200119044424-58c23975cae1 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 diff --git a/go.sum b/go.sum index cf3def9..5dc5f37 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2 h1:du+OoTUOp1mf/VRdQ8xQMWdR6JrOGbZvDG1nb9BBxHM= -github.com/unix-streamdeck/api v0.0.0-20200818180846-6942d99617b2/go.mod h1:rweAXRgCWdCACCuVhmleidq7HnJEO38zBGDe8uQqZ0w= +github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5 h1:8WlgvTJMHvfxqmQYyTbfM9TL/BYIm/WfrbDhyA8ihQo= +github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5/go.mod h1:rweAXRgCWdCACCuVhmleidq7HnJEO38zBGDe8uQqZ0w= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= From 5e9da7db545e187ce25e862029f7d99b2ce437e0 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 31 Aug 2020 17:25:31 +0100 Subject: [PATCH 26/50] Fixed dbus info not being set --- dbus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dbus.go b/dbus.go index 4c7da8e..ad824ad 100644 --- a/dbus.go +++ b/dbus.go @@ -17,7 +17,7 @@ type StreamDeckDBus struct { } func (s StreamDeckDBus) GetDeckInfo() (string, *dbus.Error) { - infoString, err := json.Marshal(s) + infoString, err := json.Marshal(sDInfo) if err != nil { return "", dbus.MakeFailedError(err) } From a254079386ec0b91ec7d0b08c37bb2d0e0e5a904 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sat, 5 Sep 2020 16:10:31 +0100 Subject: [PATCH 27/50] Refactored to use api text methods --- go.mod | 2 +- handlers/counter.go | 24 ++++----- handlers/gif.go | 10 +++- handlers/handlers.go | 4 ++ handlers/spotify.go | 121 +++++++++++++++++++++++++++++++++++++++++++ handlers/time.go | 20 +++---- interface.go | 32 ++++++------ main.go | 65 ++++++++++++----------- 8 files changed, 205 insertions(+), 73 deletions(-) create mode 100644 handlers/spotify.go diff --git a/go.mod b/go.mod index b5898cf..b3e28a6 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/fogleman/gg v1.3.0 github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b diff --git a/handlers/counter.go b/handlers/counter.go index a0c1e59..81aac25 100644 --- a/handlers/counter.go +++ b/handlers/counter.go @@ -1,29 +1,27 @@ package handlers import ( - "github.com/fogleman/gg" "github.com/unix-streamdeck/api" - "golang.org/x/image/font/inconsolata" "image" + "image/draw" + "log" "strconv" - "time" ) -func (c *CounterIconHandler) Start(_ api.Key, _ api.StreamDeckInfo, callback func(image image.Image)) { +func (c *CounterIconHandler) Start(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { if c.Callback == nil { c.Callback = callback } if c.Running { - img := gg.NewContext(72, 72) - img.SetRGB(0, 0, 0) - img.Clear() - img.SetRGB(1, 1, 1) - img.SetFontFace(inconsolata.Regular8x16) + img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) + draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) Count := strconv.Itoa(c.Count) - img.DrawStringAnchored(Count, 72/2, 72/2, 0.5, 0.5) - img.Clip() - callback(img.Image()) - time.Sleep(250 * time.Millisecond) + imgParsed, err := api.DrawText(img, Count) + if err != nil { + log.Println(err) + } else { + callback(imgParsed) + } } } diff --git a/handlers/gif.go b/handlers/gif.go index d0ff4b4..a6baa54 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -1,7 +1,6 @@ package handlers import ( - "github.com/nfnt/resize" "github.com/unix-streamdeck/api" "image" "image/gif" @@ -25,7 +24,14 @@ func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback fu timeDelay := gifs.Delay[0] frames := make([]image.Image, len(gifs.Image)) for i, frame := range gifs.Image { - frames[i] = resize.Resize(uint(info.IconSize), uint(info.IconSize), frame, resize.Lanczos3) + img := api.ResizeImage(frame, info.IconSize) + if key.Text != "" { + img, err = api.DrawText(img, key.Text) + if err != nil { + log.Println(err) + } + } + frames[i] = img } go loop(frames, timeDelay, callback, s) } diff --git a/handlers/handlers.go b/handlers/handlers.go index d7a3f22..0a3cd8d 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -15,3 +15,7 @@ type GifIconHandler struct { type TimeIconHandler struct { Running bool } +type SpotifyIconHandler struct { + Running bool + oldUrl string +} \ No newline at end of file diff --git a/handlers/spotify.go b/handlers/spotify.go new file mode 100644 index 0000000..05b56af --- /dev/null +++ b/handlers/spotify.go @@ -0,0 +1,121 @@ +package handlers + +import ( + "errors" + "github.com/godbus/dbus/v5" + "github.com/unix-streamdeck/api" + "image" + "log" + "net/http" + "strings" + "time" +) + + + +func (s *SpotifyIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { + s.Running = true + c, err := Connect() + if err != nil { + log.Println(err) + return + } + go run(c, s, callback) +} + +func (s *SpotifyIconHandler) IsRunning() bool { + return s.Running +} + +func (s *SpotifyIconHandler) SetRunning(running bool) { + s.Running = running +} + +func (s *SpotifyIconHandler) Stop() { + s.Running = false +} + +func run(c *Connection, s *SpotifyIconHandler, callback func(image image.Image)) { + defer c.Close() + for s.Running { + url, err := c.GetAlbumArtUrl() + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + if url == s.oldUrl { + time.Sleep(time.Second) + continue + } + img, err := getImage(url) + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + callback(img) + s.oldUrl = url + time.Sleep(time.Second) + } +} + +// region DBus +func getImage(url string) (image.Image, error) { + response, err := http.Get(url) + if err != nil { + return nil, err + } + if response.StatusCode != 200 { + return nil, errors.New("Couldn't get Image from URL") + } + defer response.Body.Close() + img, _, err := image.Decode(response.Body) + if err != nil { + return nil, err + } + return img, nil +} + + +type Connection struct { + busobj dbus.BusObject + conn *dbus.Conn +} + +func Connect() (*Connection, error) { + conn, err := dbus.ConnectSessionBus() + if err != nil { + return nil, err + } + return &Connection{ + conn: conn, + busobj: conn.Object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"), + }, nil +} + +func (c *Connection) GetAlbumArtUrl() (string, error) { + variant, err := c.busobj.GetProperty("org.mpris.MediaPlayer2.Player.Metadata") + if err != nil { + return "", err + } + metadataMap := variant.Value().(map[string]dbus.Variant) + var url string + for key, val := range metadataMap { + if key == "mpris:artUrl" { + url = val.String() + } + } + if url == "" { + return "", errors.New("Couldn't get URL from DBus") + } + url = strings.ReplaceAll(url, "\"", "") + url = strings.ReplaceAll(url, "https://open.spotify.com/image/", "https://i.scdn.co/image/") + return url, nil +} + +func (c *Connection) Close() { + c.conn.Close() +} + +// endregion \ No newline at end of file diff --git a/handlers/time.go b/handlers/time.go index a7595eb..e598884 100644 --- a/handlers/time.go +++ b/handlers/time.go @@ -1,10 +1,10 @@ package handlers import ( - "github.com/fogleman/gg" "github.com/unix-streamdeck/api" - "golang.org/x/image/font/inconsolata" "image" + "image/draw" + "log" "time" ) @@ -28,16 +28,16 @@ func (t *TimeIconHandler) Stop() { func timeLoop(info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { for handler.Running { - img := gg.NewContext(info.IconSize, info.IconSize) - img.SetRGB(0, 0, 0) - img.Clear() - img.SetRGB(1, 1, 1) - img.SetFontFace(inconsolata.Regular8x16) + img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) + draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) t := time.Now() tString := t.Format("15:04:05") - img.DrawStringAnchored(tString, float64(info.IconSize)/2, float64(info.IconSize)/2, 0.5, 0.5) - img.Clip() - callback(img.Image()) + imgParsed, err := api.DrawText(img, tString) + if err != nil { + log.Println(err) + } else { + callback(imgParsed) + } time.Sleep(time.Second) } } \ No newline at end of file diff --git a/interface.go b/interface.go index b977f07..912f568 100644 --- a/interface.go +++ b/interface.go @@ -2,14 +2,10 @@ package main import ( "context" - "github.com/fogleman/gg" - "github.com/nfnt/resize" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/streamdeckd/handlers" - "golang.org/x/image/font/inconsolata" "golang.org/x/sync/semaphore" "image" - "image/color" "image/draw" "log" "os" @@ -31,11 +27,7 @@ func LoadImage(path string) (image.Image, error) { return nil, err } - return ResizeImage(img), nil -} - -func ResizeImage(img image.Image) image.Image { - return resize.Resize(dev.Pixels, dev.Pixels, img, resize.Lanczos3) + return api.ResizeImage(img, sDInfo.IconSize), nil } func SetImage(img image.Image, i int, page int) { @@ -62,7 +54,7 @@ func SetKeyImage(currentKey *api.Key, i int) { if currentKey.Buff == nil { if currentKey.Icon == "" { img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) - draw.Draw(img, img.Bounds(), image.NewUniform(color.RGBA{0, 0, 0, 255}), image.ZP, draw.Src) + draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) currentKey.Buff = img } else { img, err := LoadImage(currentKey.Icon) @@ -73,12 +65,12 @@ func SetKeyImage(currentKey *api.Key, i int) { currentKey.Buff = img } if currentKey.Text != "" { - img := gg.NewContextForImage(currentKey.Buff) - img.SetRGB(1, 1, 1) - img.SetFontFace(inconsolata.Regular8x16) - img.DrawStringAnchored(currentKey.Text, 72/2, 72/2, 0.5, 0.5) - img.Clip() - currentKey.Buff = img.Image() + img, err := api.DrawText(currentKey.Buff, currentKey.Text) + if err != nil { + log.Println(err) + } else { + currentKey.Buff = img + } } } if currentKey.Buff != nil { @@ -109,11 +101,16 @@ func SetKey(currentKey *api.Key, i int, page int) { handler = &handlers.CounterIconHandler{Count:0, Running: true} } else if currentKey.IconHandler == "Time" { handler = &handlers.TimeIconHandler{Running:true} + } else if currentKey.IconHandler == "Spotify" { + handler = &handlers.SpotifyIconHandler{Running: true} } if handler == nil { return } handler.Start(*currentKey, sDInfo, func(image image.Image) { + if image.Bounds().Max.X != 72 || image.Bounds().Max.Y != 72 { + image = api.ResizeImage(image, sDInfo.IconSize) + } SetImage(image, i, page) currentKey.Buff = image }) @@ -125,6 +122,9 @@ func SetKey(currentKey *api.Key, i int, page int) { if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { currentKey.IconHandlerStruct.SetRunning(true) currentKey.IconHandlerStruct.Start(*currentKey, sDInfo, func(image image.Image) { + if image.Bounds().Max.X != 72 || image.Bounds().Max.Y != 72 { + image = api.ResizeImage(image, sDInfo.IconSize) + } SetImage(image, i, page) currentKey.Buff = image }) diff --git a/main.go b/main.go index 54c99da..aa37af6 100644 --- a/main.go +++ b/main.go @@ -29,34 +29,11 @@ var connectSem = semaphore.NewWeighted(1) var basicConfig = api.Config{ Pages: []api.Page{ { - api.Key{}, }, }, } func main() { - var err error - config, err = readConfig() - if err != nil && !os.IsNotExist(err) { - log.Println(err) - } else if os.IsNotExist(err) { - file, err := os.Create(configPath) - if err != nil { - log.Println(err) - } - err = file.Close() - if err != nil { - log.Println(err) - } - config = &basicConfig - err = SaveConfig() - if err != nil { - log.Println(err) - } - } - if len(config.Pages) == 0 { - config.Pages = append(config.Pages, api.Page{}) - } cleanupHook() go InitDBUS() attemptConnection() @@ -66,6 +43,9 @@ func attemptConnection() { for !isOpen { _ = openDevice() if isOpen { + if config == nil { + loadConfig() + } SetPage(config, p) if sDbus != nil { sDInfo.IconSize = int(dev.Pixels) @@ -117,6 +97,36 @@ func openDevice() error { return nil } +func loadConfig() { + var err error + config, err = readConfig() + if err != nil && !os.IsNotExist(err) { + log.Println(err) + } else if os.IsNotExist(err) { + file, err := os.Create(configPath) + if err != nil { + log.Println(err) + } + err = file.Close() + if err != nil { + log.Println(err) + } + config = &basicConfig + page := config.Pages[0] + for i := 0; i < int(dev.Rows)*int(dev.Columns); i++ { + page = append(page, api.Key{}) + } + config.Pages[0] = page + err = SaveConfig() + if err != nil { + log.Println(err) + } + } + if len(config.Pages) == 0 { + config.Pages = append(config.Pages, api.Page{}) + } +} + func readConfig() (*api.Config, error) { data, err := ioutil.ReadFile(configPath) if err != nil { @@ -169,14 +179,7 @@ func SetConfig(configString string) error { func ReloadConfig() error { unmountHandlers() - var err error - config, err = readConfig() - if err != nil && !os.IsNotExist(err) { - return err - } - if len(config.Pages) == 0 { - config.Pages = append(config.Pages, api.Page{}) - } + loadConfig() SetPage(config, p) return nil } From d60d045b5ef97246074dad3ba91baeb602156aeb Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 6 Sep 2020 15:13:22 +0100 Subject: [PATCH 28/50] Reverted pushing spotify handler --- handlers/spotify.go | 121 -------------------------------------------- interface.go | 2 - 2 files changed, 123 deletions(-) delete mode 100644 handlers/spotify.go diff --git a/handlers/spotify.go b/handlers/spotify.go deleted file mode 100644 index 05b56af..0000000 --- a/handlers/spotify.go +++ /dev/null @@ -1,121 +0,0 @@ -package handlers - -import ( - "errors" - "github.com/godbus/dbus/v5" - "github.com/unix-streamdeck/api" - "image" - "log" - "net/http" - "strings" - "time" -) - - - -func (s *SpotifyIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { - s.Running = true - c, err := Connect() - if err != nil { - log.Println(err) - return - } - go run(c, s, callback) -} - -func (s *SpotifyIconHandler) IsRunning() bool { - return s.Running -} - -func (s *SpotifyIconHandler) SetRunning(running bool) { - s.Running = running -} - -func (s *SpotifyIconHandler) Stop() { - s.Running = false -} - -func run(c *Connection, s *SpotifyIconHandler, callback func(image image.Image)) { - defer c.Close() - for s.Running { - url, err := c.GetAlbumArtUrl() - if err != nil { - log.Println(err) - time.Sleep(time.Second) - continue - } - if url == s.oldUrl { - time.Sleep(time.Second) - continue - } - img, err := getImage(url) - if err != nil { - log.Println(err) - time.Sleep(time.Second) - continue - } - callback(img) - s.oldUrl = url - time.Sleep(time.Second) - } -} - -// region DBus -func getImage(url string) (image.Image, error) { - response, err := http.Get(url) - if err != nil { - return nil, err - } - if response.StatusCode != 200 { - return nil, errors.New("Couldn't get Image from URL") - } - defer response.Body.Close() - img, _, err := image.Decode(response.Body) - if err != nil { - return nil, err - } - return img, nil -} - - -type Connection struct { - busobj dbus.BusObject - conn *dbus.Conn -} - -func Connect() (*Connection, error) { - conn, err := dbus.ConnectSessionBus() - if err != nil { - return nil, err - } - return &Connection{ - conn: conn, - busobj: conn.Object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"), - }, nil -} - -func (c *Connection) GetAlbumArtUrl() (string, error) { - variant, err := c.busobj.GetProperty("org.mpris.MediaPlayer2.Player.Metadata") - if err != nil { - return "", err - } - metadataMap := variant.Value().(map[string]dbus.Variant) - var url string - for key, val := range metadataMap { - if key == "mpris:artUrl" { - url = val.String() - } - } - if url == "" { - return "", errors.New("Couldn't get URL from DBus") - } - url = strings.ReplaceAll(url, "\"", "") - url = strings.ReplaceAll(url, "https://open.spotify.com/image/", "https://i.scdn.co/image/") - return url, nil -} - -func (c *Connection) Close() { - c.conn.Close() -} - -// endregion \ No newline at end of file diff --git a/interface.go b/interface.go index 912f568..a8af68d 100644 --- a/interface.go +++ b/interface.go @@ -101,8 +101,6 @@ func SetKey(currentKey *api.Key, i int, page int) { handler = &handlers.CounterIconHandler{Count:0, Running: true} } else if currentKey.IconHandler == "Time" { handler = &handlers.TimeIconHandler{Running:true} - } else if currentKey.IconHandler == "Spotify" { - handler = &handlers.SpotifyIconHandler{Running: true} } if handler == nil { return From eea7eecabcdbaa95a9d5ce720ec7caa3014bcb63 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 6 Sep 2020 15:14:22 +0100 Subject: [PATCH 29/50] Reverted pushing spotify handler --- handlers/handlers.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 0a3cd8d..9a10d92 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -14,8 +14,4 @@ type GifIconHandler struct { type TimeIconHandler struct { Running bool -} -type SpotifyIconHandler struct { - Running bool - oldUrl string } \ No newline at end of file From c2ed21aafa74baaab25b68543d1df4c59754e65b Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 7 Sep 2020 19:41:22 +0100 Subject: [PATCH 30/50] Updated unix-streamdeck/api version --- go.mod | 6 +----- go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index b3e28a6..03eb793 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,8 @@ module github.com/unix-streamdeck/streamdeckd go 1.14 require ( - github.com/fogleman/gg v1.3.0 github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 - github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5 + github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b - golang.org/x/image v0.0.0-20200119044424-58c23975cae1 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 ) diff --git a/go.sum b/go.sum index 5dc5f37..219efd5 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5 h1:8WlgvTJMHvfxqmQYyTbfM9TL/BYIm/WfrbDhyA8ihQo= -github.com/unix-streamdeck/api v0.0.0-20200828000516-c734a9f6cec5/go.mod h1:rweAXRgCWdCACCuVhmleidq7HnJEO38zBGDe8uQqZ0w= +github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e h1:/stJJT3mpg42pmda9mJocaeWIPc2RHAYe5no8yNrzz4= +github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -105,6 +105,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw= +golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= From eec457ab157e85c9835711a9ccedaf19a49bccd0 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 1 Oct 2020 23:02:34 +0100 Subject: [PATCH 31/50] Fixed bug with nil config on dbus config upload --- main.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index aa37af6..3bc8ed4 100644 --- a/main.go +++ b/main.go @@ -207,12 +207,14 @@ func SaveConfig() error { } func unmountHandlers() { - for i := range config.Pages { - page := config.Pages[i] - for i2 := 0; i2 < len(page); i2++ { - key := &page[i2] - if key.IconHandlerStruct != nil { - key.IconHandlerStruct.Stop() + if config != nil && len(config.Pages) > 0 { + for i := range config.Pages { + page := config.Pages[i] + for i2 := 0; i2 < len(page); i2++ { + key := &page[i2] + if key.IconHandlerStruct != nil { + key.IconHandlerStruct.Stop() + } } } } From a45e482b0c88007b8ad4cf499539b1d88e7a48dc Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 1 Nov 2020 14:26:05 +0000 Subject: [PATCH 32/50] Fixed bug with duplicated gif handler after suspend --- handlers/gif.go | 7 +++++++ handlers/handlers.go | 6 +++++- interface.go | 3 +-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/handlers/gif.go b/handlers/gif.go index a6baa54..69c36ef 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -1,6 +1,7 @@ package handlers import ( + "context" "github.com/unix-streamdeck/api" "image" "image/gif" @@ -49,6 +50,12 @@ func (s *GifIconHandler) Stop() { } func loop(frames []image.Image, timeDelay int, callback func(image image.Image), s *GifIconHandler) { + ctx := context.Background() + err := s.Lock.Acquire(ctx, 1) + if err != nil { + return + } + defer s.Lock.Release(1) gifIndex := 0 for s.Running { img := frames[gifIndex] diff --git a/handlers/handlers.go b/handlers/handlers.go index 9a10d92..4eb8155 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -1,6 +1,9 @@ package handlers -import "image" +import ( + "golang.org/x/sync/semaphore" + "image" +) type CounterIconHandler struct { Count int @@ -10,6 +13,7 @@ type CounterIconHandler struct { type GifIconHandler struct { Running bool + Lock *semaphore.Weighted } type TimeIconHandler struct { diff --git a/interface.go b/interface.go index a8af68d..4a9b036 100644 --- a/interface.go +++ b/interface.go @@ -96,7 +96,7 @@ func SetKey(currentKey *api.Key, i int, page int) { } else if currentKey.IconHandlerStruct == nil { var handler api.IconHandler if currentKey.IconHandler == "Gif" { - handler = &handlers.GifIconHandler{Running:true} + handler = &handlers.GifIconHandler{Running:true, Lock:semaphore.NewWeighted(1)} } else if currentKey.IconHandler == "Counter" { handler = &handlers.CounterIconHandler{Count:0, Running: true} } else if currentKey.IconHandler == "Time" { @@ -118,7 +118,6 @@ func SetKey(currentKey *api.Key, i int, page int) { SetImage(currentKey.Buff, i, p) } if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { - currentKey.IconHandlerStruct.SetRunning(true) currentKey.IconHandlerStruct.Start(*currentKey, sDInfo, func(image image.Image) { if image.Bounds().Max.X != 72 || image.Bounds().Max.Y != 72 { image = api.ResizeImage(image, sDInfo.IconSize) From 997361a26e0fbda873bad3a697fa3f069fb5e7ec Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sat, 7 Nov 2020 14:58:21 +0000 Subject: [PATCH 33/50] Added text alignment and size override --- go.mod | 2 +- go.sum | 4 ++-- handlers/counter.go | 4 ++-- handlers/gif.go | 2 +- handlers/time.go | 8 ++++---- interface.go | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 03eb793..dff641a 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e + github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 ) diff --git a/go.sum b/go.sum index 219efd5..a3e5a69 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e h1:/stJJT3mpg42pmda9mJocaeWIPc2RHAYe5no8yNrzz4= -github.com/unix-streamdeck/api v0.0.0-20200907181211-2f2cfdad366e/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0 h1:UoAM7fwvW2dkYLINoxVQ7Z403r6mZ9CiQOg6AGn6xMA= +github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/handlers/counter.go b/handlers/counter.go index 81aac25..676344f 100644 --- a/handlers/counter.go +++ b/handlers/counter.go @@ -8,7 +8,7 @@ import ( "strconv" ) -func (c *CounterIconHandler) Start(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (c *CounterIconHandler) Start(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { if c.Callback == nil { c.Callback = callback } @@ -16,7 +16,7 @@ func (c *CounterIconHandler) Start(_ api.Key, info api.StreamDeckInfo, callback img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) Count := strconv.Itoa(c.Count) - imgParsed, err := api.DrawText(img, Count) + imgParsed, err := api.DrawText(img, Count, k.TextSize, k.TextAlignment) if err != nil { log.Println(err) } else { diff --git a/handlers/gif.go b/handlers/gif.go index 69c36ef..618d000 100644 --- a/handlers/gif.go +++ b/handlers/gif.go @@ -27,7 +27,7 @@ func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback fu for i, frame := range gifs.Image { img := api.ResizeImage(frame, info.IconSize) if key.Text != "" { - img, err = api.DrawText(img, key.Text) + img, err = api.DrawText(img, key.Text, key.TextSize, key.TextAlignment) if err != nil { log.Println(err) } diff --git a/handlers/time.go b/handlers/time.go index e598884..4fb7377 100644 --- a/handlers/time.go +++ b/handlers/time.go @@ -9,9 +9,9 @@ import ( ) -func (t *TimeIconHandler) Start(_ api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { +func (t *TimeIconHandler) Start(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true - go timeLoop(info, callback, t) + go timeLoop(k, info, callback, t) } func (t *TimeIconHandler) IsRunning() bool { @@ -26,13 +26,13 @@ func (t *TimeIconHandler) Stop() { t.Running = false } -func timeLoop(info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { +func timeLoop(k api.Key, info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { for handler.Running { img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) t := time.Now() tString := t.Format("15:04:05") - imgParsed, err := api.DrawText(img, tString) + imgParsed, err := api.DrawText(img, tString, k.TextSize, k.TextAlignment) if err != nil { log.Println(err) } else { diff --git a/interface.go b/interface.go index 4a9b036..8880f23 100644 --- a/interface.go +++ b/interface.go @@ -65,7 +65,7 @@ func SetKeyImage(currentKey *api.Key, i int) { currentKey.Buff = img } if currentKey.Text != "" { - img, err := api.DrawText(currentKey.Buff, currentKey.Text) + img, err := api.DrawText(currentKey.Buff, currentKey.Text, currentKey.TextSize, currentKey.TextAlignment) if err != nil { log.Println(err) } else { From e6dbd193205db5f9f3451a680a5b63ade37f3311 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Tue, 10 Nov 2020 19:23:28 +0000 Subject: [PATCH 34/50] Modules loading, and dbus method for module info --- dbus.go | 13 +++ handlers/{ => examples}/counter.go | 17 +++- handlers/{ => examples}/gif.go | 18 +++- handlers/examples/init.go | 10 +++ handlers/examples/spotify.go | 131 +++++++++++++++++++++++++++++ handlers/{ => examples}/time.go | 12 ++- handlers/handlers.go | 57 ++++++++++--- interface.go | 18 ++-- main.go | 9 ++ 9 files changed, 263 insertions(+), 22 deletions(-) rename handlers/{ => examples}/counter.go (72%) rename handlers/{ => examples}/gif.go (76%) create mode 100644 handlers/examples/init.go create mode 100644 handlers/examples/spotify.go rename handlers/{ => examples}/time.go (77%) diff --git a/dbus.go b/dbus.go index ad824ad..c856b67 100644 --- a/dbus.go +++ b/dbus.go @@ -5,6 +5,7 @@ import ( "errors" "github.com/godbus/dbus/v5" "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/streamdeckd/handlers" "log" ) @@ -61,6 +62,18 @@ func (StreamDeckDBus) CommitConfig() *dbus.Error { return nil } +func (StreamDeckDBus) GetModules() (string, *dbus.Error) { + var modules []api.Module + for _, module := range handlers.AvailableModules() { + modules = append(modules, api.Module{Name: module.Name, IconFields: module.IconFields, KeyFields: module.KeyFields, IsIcon: module.NewIcon != nil, IsKey: module.NewKey != nil}) + } + modulesString, err := json.Marshal(modules) + if err != nil { + return "", dbus.MakeFailedError(err) + } + return string(modulesString), nil +} + func InitDBUS() error { var err error conn, err = dbus.SessionBus() diff --git a/handlers/counter.go b/handlers/examples/counter.go similarity index 72% rename from handlers/counter.go rename to handlers/examples/counter.go index 676344f..88dcc41 100644 --- a/handlers/counter.go +++ b/handlers/examples/counter.go @@ -1,13 +1,20 @@ -package handlers +package examples import ( "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/streamdeckd/handlers" "image" "image/draw" "log" "strconv" ) +type CounterIconHandler struct { + Count int + Running bool + Callback func(image image.Image) +} + func (c *CounterIconHandler) Start(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { if c.Callback == nil { c.Callback = callback @@ -49,3 +56,11 @@ func (CounterKeyHandler) Key(key api.Key, info api.StreamDeckInfo) { handler.Start(key, info, handler.Callback) } } + +func RegisterCounter() handlers.Module { + return handlers.Module{NewIcon: func() api.IconHandler { + return &CounterIconHandler{Running: true, Count: 0} + }, NewKey: func() api.KeyHandler { + return &CounterKeyHandler{} + }, Name: "Counter"} +} \ No newline at end of file diff --git a/handlers/gif.go b/handlers/examples/gif.go similarity index 76% rename from handlers/gif.go rename to handlers/examples/gif.go index 618d000..896c0b3 100644 --- a/handlers/gif.go +++ b/handlers/examples/gif.go @@ -1,8 +1,10 @@ -package handlers +package examples import ( "context" "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/streamdeckd/handlers" + "golang.org/x/sync/semaphore" "image" "image/gif" "log" @@ -10,7 +12,15 @@ import ( "time" ) +type GifIconHandler struct { + Running bool + Lock *semaphore.Weighted +} + func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { + if s.Lock == nil { + s.Lock = semaphore.NewWeighted(1) + } s.Running = true f, err := os.Open(key.Icon) if err != nil { @@ -67,3 +77,9 @@ func loop(frames []image.Image, timeDelay int, callback func(image image.Image), time.Sleep(time.Duration(timeDelay * 10000000)) } } + +func RegisterGif() handlers.Module { + return handlers.Module{NewIcon: func() api.IconHandler { + return &GifIconHandler{Running: true, Lock: semaphore.NewWeighted(1)} + }, Name: "Gif"} +} \ No newline at end of file diff --git a/handlers/examples/init.go b/handlers/examples/init.go new file mode 100644 index 0000000..b6783af --- /dev/null +++ b/handlers/examples/init.go @@ -0,0 +1,10 @@ +package examples + +import "github.com/unix-streamdeck/streamdeckd/handlers" + +func RegisterBaseModules() { + handlers.RegisterModule(RegisterGif()) + handlers.RegisterModule(RegisterTime()) + handlers.RegisterModule(RegisterCounter()) + handlers.RegisterModule(RegisterSpotify()) +} diff --git a/handlers/examples/spotify.go b/handlers/examples/spotify.go new file mode 100644 index 0000000..97d2791 --- /dev/null +++ b/handlers/examples/spotify.go @@ -0,0 +1,131 @@ +package examples + +import ( + "errors" + "github.com/godbus/dbus/v5" + "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/streamdeckd/handlers" + "image" + "log" + "net/http" + "strings" + "time" +) + +type SpotifyIconHandler struct { + Running bool + oldUrl string +} + +func (s *SpotifyIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { + s.Running = true + c, err := Connect() + if err != nil { + log.Println(err) + return + } + go run(c, s, callback) +} + +func (s *SpotifyIconHandler) IsRunning() bool { + return s.Running +} + +func (s *SpotifyIconHandler) SetRunning(running bool) { + s.Running = running +} + +func (s *SpotifyIconHandler) Stop() { + s.Running = false +} + +func run(c *Connection, s *SpotifyIconHandler, callback func(image image.Image)) { + defer c.Close() + for s.Running { + url, err := c.GetAlbumArtUrl() + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + if url == s.oldUrl { + time.Sleep(time.Second) + continue + } + img, err := getImage(url) + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + callback(img) + s.oldUrl = url + time.Sleep(time.Second) + } +} + +func RegisterSpotify() handlers.Module { + return handlers.Module{NewIcon: func() api.IconHandler { + return &SpotifyIconHandler{Running: true} + }, Name: "Spotify"} +} + +// region DBus +func getImage(url string) (image.Image, error) { + response, err := http.Get(url) + if err != nil { + return nil, err + } + if response.StatusCode != 200 { + return nil, errors.New("Couldn't get Image from URL") + } + defer response.Body.Close() + img, _, err := image.Decode(response.Body) + if err != nil { + return nil, err + } + return img, nil +} + + +type Connection struct { + busobj dbus.BusObject + conn *dbus.Conn +} + +func Connect() (*Connection, error) { + conn, err := dbus.ConnectSessionBus() + if err != nil { + return nil, err + } + return &Connection{ + conn: conn, + busobj: conn.Object("org.mpris.MediaPlayer2.spotify", "/org/mpris/MediaPlayer2"), + }, nil +} + +func (c *Connection) GetAlbumArtUrl() (string, error) { + variant, err := c.busobj.GetProperty("org.mpris.MediaPlayer2.Player.Metadata") + if err != nil { + return "", err + } + metadataMap := variant.Value().(map[string]dbus.Variant) + var url string + for key, val := range metadataMap { + if key == "mpris:artUrl" { + url = val.String() + } + } + if url == "" { + return "", errors.New("Couldn't get URL from DBus") + } + url = strings.ReplaceAll(url, "\"", "") + url = strings.ReplaceAll(url, "https://open.spotify.com/image/", "https://i.scdn.co/image/") + return url, nil +} + +func (c *Connection) Close() { + c.conn.Close() +} + +// endregion \ No newline at end of file diff --git a/handlers/time.go b/handlers/examples/time.go similarity index 77% rename from handlers/time.go rename to handlers/examples/time.go index 4fb7377..85f25d7 100644 --- a/handlers/time.go +++ b/handlers/examples/time.go @@ -1,13 +1,17 @@ -package handlers +package examples import ( "github.com/unix-streamdeck/api" + "github.com/unix-streamdeck/streamdeckd/handlers" "image" "image/draw" "log" "time" ) +type TimeIconHandler struct { + Running bool +} func (t *TimeIconHandler) Start(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true @@ -40,4 +44,10 @@ func timeLoop(k api.Key, info api.StreamDeckInfo, callback func(image image.Imag } time.Sleep(time.Second) } +} + +func RegisterTime() handlers.Module { + return handlers.Module{NewIcon: func() api.IconHandler { + return &TimeIconHandler{Running: true} + }, Name: "Time"} } \ No newline at end of file diff --git a/handlers/handlers.go b/handlers/handlers.go index 4eb8155..9663fcc 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -1,21 +1,56 @@ package handlers import ( - "golang.org/x/sync/semaphore" - "image" + "github.com/unix-streamdeck/api" + "log" + "plugin" ) -type CounterIconHandler struct { - Count int - Running bool - Callback func(image image.Image) +type Module struct { + Name string + NewIcon func() api.IconHandler + NewKey func() api.KeyHandler + IconFields []api.Field + KeyFields []api.Field } -type GifIconHandler struct { - Running bool - Lock *semaphore.Weighted + + +var modules []Module + + +func AvailableModules() []Module { + return modules +} + +func RegisterModule(m Module) { + for _, module := range modules { + if module.Name == m.Name { + log.Println("Module already loaded: " + m.Name) + return + } + } + log.Println("Loaded module " + m.Name) + modules = append(modules, m) } -type TimeIconHandler struct { - Running bool +func LoadModule(path string) { + plug, err := plugin.Open(path) + if err != nil { + //log.Println("Failed to load module: " + path) + log.Println(err) + return + } + mod, err := plug.Lookup("GetModule") + if err != nil { + log.Println(err) + return + } + var modMethod func() Module + modMethod, ok := mod.(func() Module) + if !ok { + log.Println("Failed to load module: " + path) + return + } + RegisterModule(modMethod()) } \ No newline at end of file diff --git a/interface.go b/interface.go index 8880f23..54c229f 100644 --- a/interface.go +++ b/interface.go @@ -95,12 +95,11 @@ func SetKey(currentKey *api.Key, i int, page int) { } else if currentKey.IconHandlerStruct == nil { var handler api.IconHandler - if currentKey.IconHandler == "Gif" { - handler = &handlers.GifIconHandler{Running:true, Lock:semaphore.NewWeighted(1)} - } else if currentKey.IconHandler == "Counter" { - handler = &handlers.CounterIconHandler{Count:0, Running: true} - } else if currentKey.IconHandler == "Time" { - handler = &handlers.TimeIconHandler{Running:true} + modules := handlers.AvailableModules() + for _, module := range modules { + if module.Name == currentKey.IconHandler { + handler = module.NewIcon() + } } if handler == nil { return @@ -151,8 +150,11 @@ func HandleInput(key *api.Key, page int) { if key.KeyHandler != "" { if key.KeyHandlerStruct == nil { var handler api.KeyHandler - if key.KeyHandler == "Counter" { - handler = handlers.CounterKeyHandler{} + modules := handlers.AvailableModules() + for _, module := range modules { + if module.Name == key.KeyHandler { + handler = module.NewKey() + } } if handler == nil { return diff --git a/main.go b/main.go index 3bc8ed4..3581c49 100644 --- a/main.go +++ b/main.go @@ -7,6 +7,8 @@ import ( "fmt" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" + "github.com/unix-streamdeck/streamdeckd/handlers" + "github.com/unix-streamdeck/streamdeckd/handlers/examples" "golang.org/x/sync/semaphore" _ "image/gif" _ "image/jpeg" @@ -27,6 +29,7 @@ var disconnectSem = semaphore.NewWeighted(1) var connectSem = semaphore.NewWeighted(1) var basicConfig = api.Config{ + Modules: []string{}, Pages: []api.Page{ { }, @@ -36,6 +39,7 @@ var basicConfig = api.Config{ func main() { cleanupHook() go InitDBUS() + examples.RegisterBaseModules() attemptConnection() } @@ -125,6 +129,11 @@ func loadConfig() { if len(config.Pages) == 0 { config.Pages = append(config.Pages, api.Page{}) } + if len(config.Modules) > 0 { + for _, module := range config.Modules { + handlers.LoadModule(module) + } + } } func readConfig() (*api.Config, error) { From 724cea9314bd4cfe488f832ad1e92d42ea77bb2e Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 28 Dec 2020 23:25:31 +0000 Subject: [PATCH 35/50] Fixed const set streamdeckd icon size --- go.mod | 2 +- go.sum | 4 ++-- interface.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index dff641a..afcc8f8 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0 + github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 ) diff --git a/go.sum b/go.sum index a3e5a69..bc9350a 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0 h1:UoAM7fwvW2dkYLINoxVQ7Z403r6mZ9CiQOg6AGn6xMA= -github.com/unix-streamdeck/api v0.0.0-20201107145736-ff1384a414b0/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907 h1:MBWGv1fYvM3upBP2Y9TTMgQxMyE3o+ivfBuQ0vmsZh8= +github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/interface.go b/interface.go index 54c229f..04d4b64 100644 --- a/interface.go +++ b/interface.go @@ -105,7 +105,7 @@ func SetKey(currentKey *api.Key, i int, page int) { return } handler.Start(*currentKey, sDInfo, func(image image.Image) { - if image.Bounds().Max.X != 72 || image.Bounds().Max.Y != 72 { + if image.Bounds().Max.X != sDInfo.IconSize || image.Bounds().Max.Y != sDInfo.IconSize { image = api.ResizeImage(image, sDInfo.IconSize) } SetImage(image, i, page) @@ -118,7 +118,7 @@ func SetKey(currentKey *api.Key, i int, page int) { } if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { currentKey.IconHandlerStruct.Start(*currentKey, sDInfo, func(image image.Image) { - if image.Bounds().Max.X != 72 || image.Bounds().Max.Y != 72 { + if image.Bounds().Max.X != sDInfo.IconSize || image.Bounds().Max.Y != sDInfo.IconSize { image = api.ResizeImage(image, sDInfo.IconSize) } SetImage(image, i, page) From 575e672c26f275d35a016be6406ceb8480ccfff5 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 28 Dec 2020 23:35:27 +0000 Subject: [PATCH 36/50] Updated fields on gif --- handlers/examples/gif.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/handlers/examples/gif.go b/handlers/examples/gif.go index 896c0b3..ab04f35 100644 --- a/handlers/examples/gif.go +++ b/handlers/examples/gif.go @@ -9,12 +9,13 @@ import ( "image/gif" "log" "os" + "strconv" "time" ) type GifIconHandler struct { Running bool - Lock *semaphore.Weighted + Lock *semaphore.Weighted } func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { @@ -22,7 +23,11 @@ func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback fu s.Lock = semaphore.NewWeighted(1) } s.Running = true - f, err := os.Open(key.Icon) + icon, ok := key.IconHandlerFields["icon"] + if !ok { + return + } + f, err := os.Open(icon) if err != nil { log.Println(err) return @@ -36,8 +41,9 @@ func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback fu frames := make([]image.Image, len(gifs.Image)) for i, frame := range gifs.Image { img := api.ResizeImage(frame, info.IconSize) - if key.Text != "" { - img, err = api.DrawText(img, key.Text, key.TextSize, key.TextAlignment) + if key.IconHandlerFields["text"] != "" { + size, _ := strconv.ParseInt(key.IconHandlerFields["text_size"], 10, 0) + img, err = api.DrawText(img, key.IconHandlerFields["text"], int(size), key.IconHandlerFields["text_alignment"]) if err != nil { log.Println(err) } @@ -51,7 +57,7 @@ func (s *GifIconHandler) IsRunning() bool { return s.Running } -func (s *GifIconHandler) SetRunning(running bool) { +func (s *GifIconHandler) SetRunning(running bool) { s.Running = running } @@ -81,5 +87,5 @@ func loop(frames []image.Image, timeDelay int, callback func(image image.Image), func RegisterGif() handlers.Module { return handlers.Module{NewIcon: func() api.IconHandler { return &GifIconHandler{Running: true, Lock: semaphore.NewWeighted(1)} - }, Name: "Gif"} -} \ No newline at end of file + }, Name: "Gif", IconFields: []api.Field{{Title: "Icon", Name: "icon", Type: "File", FileTypes: []string{".gif"}}, {Title: "Text", Name: "text", Type: "Text"}, {Title: "Text Size", Name: "text_size", Type: "Number"}, {Title: "Text Alignment", Name: "text_alignment", Type: "TextAlignment"}}} +} From 334aaca2cdd7a0f0545d74fe86d771c3a9df20b5 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Thu, 13 May 2021 22:49:08 +0100 Subject: [PATCH 37/50] Added support for multiple streamdecks --- dbus.go | 27 +++++--- go.mod | 3 +- go.sum | 4 ++ interface.go | 91 ++++++++++++++----------- main.go | 185 ++++++++++++++++++++++++++++++++++++--------------- 5 files changed, 205 insertions(+), 105 deletions(-) diff --git a/dbus.go b/dbus.go index c856b67..ddbae2b 100644 --- a/dbus.go +++ b/dbus.go @@ -12,7 +12,7 @@ import ( var conn *dbus.Conn var sDbus *StreamDeckDBus -var sDInfo api.StreamDeckInfo +var sDInfo []api.StreamDeckInfo type StreamDeckDBus struct { } @@ -41,9 +41,15 @@ func (StreamDeckDBus) ReloadConfig() *dbus.Error { return nil } -func (StreamDeckDBus) SetPage(page int) *dbus.Error { - SetPage(config, page) - return nil +func (StreamDeckDBus) SetPage(serial string, page int) *dbus.Error { + for s := range devs { + if devs[s].Deck.Serial == serial { + dev := devs[s] + SetPage(dev, page) + return nil + } + } + return dbus.MakeFailedError(errors.New("Device with Serial: " + serial + " could not be found")) } func (StreamDeckDBus) SetConfig(configString string) *dbus.Error { @@ -84,9 +90,6 @@ func InitDBUS() error { defer conn.Close() sDbus = &StreamDeckDBus{} - sDInfo = api.StreamDeckInfo{ - Page: p, - } conn.ExportAll(sDbus, "/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd") reply, err := conn.RequestName("com.unixstreamdeck.streamdeckd", dbus.NameFlagDoNotQueue) @@ -100,11 +103,13 @@ func InitDBUS() error { select {} } -func EmitPage(page int) { +func EmitPage(dev *VirtualDev, page int) { if conn != nil { - conn.Emit("/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd.Page", page) + conn.Emit("/com/unixstreamdeck/streamdeckd", "com.unixstreamdeck.streamdeckd.Page", dev.Deck.Serial, page) } - if sDbus != nil { - sDInfo.Page = page + for i := range sDInfo { + if sDInfo[i].Serial == dev.Deck.Serial { + sDInfo[i].Page = page + } } } diff --git a/go.mod b/go.mod index afcc8f8..fed0d01 100644 --- a/go.mod +++ b/go.mod @@ -6,5 +6,6 @@ require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b - golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 + golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect + golang.org/x/sync v0.0.0-20201207232520-09787c993a3a ) diff --git a/go.sum b/go.sum index bc9350a..ed030f0 100644 --- a/go.sum +++ b/go.sum @@ -107,6 +107,8 @@ golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQg golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw= golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= +golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -119,6 +121,8 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/interface.go b/interface.go index 04d4b64..ff0d825 100644 --- a/interface.go +++ b/interface.go @@ -3,6 +3,7 @@ package main import ( "context" "github.com/unix-streamdeck/api" + _ "github.com/unix-streamdeck/driver" "github.com/unix-streamdeck/streamdeckd/handlers" "golang.org/x/sync/semaphore" "image" @@ -12,10 +13,10 @@ import ( "strings" ) -var p int + var sem = semaphore.NewWeighted(int64(1)) -func LoadImage(path string) (image.Image, error) { +func LoadImage(dev *VirtualDev, path string) (image.Image, error) { f, err := os.Open(path) if err != nil { return nil, err @@ -27,10 +28,10 @@ func LoadImage(path string) (image.Image, error) { return nil, err } - return api.ResizeImage(img, sDInfo.IconSize), nil + return api.ResizeImage(img, int(dev.Deck.Pixels)), nil } -func SetImage(img image.Image, i int, page int) { +func SetImage(dev *VirtualDev, img image.Image, i int, page int) { ctx := context.Background() err := sem.Acquire(ctx, 1) if err != nil { @@ -38,26 +39,28 @@ func SetImage(img image.Image, i int, page int) { return } defer sem.Release(1) - if p == page && isOpen { - err := dev.SetImage(uint8(i), img) + if dev.Page == page && dev.IsOpen { + err := dev.Deck.SetImage(uint8(i), img) if err != nil { if strings.Contains(err.Error(), "hidapi") { - disconnect() - } else { + disconnect(dev) + } else if strings.Contains(err.Error(), "dimensions") { + log.Println(err) + }else { log.Println(err) } } } } -func SetKeyImage(currentKey *api.Key, i int) { +func SetKeyImage(dev *VirtualDev, currentKey *api.Key, i int, page int) { if currentKey.Buff == nil { if currentKey.Icon == "" { - img := image.NewRGBA(image.Rect(0, 0, int(dev.Pixels), int(dev.Pixels))) + img := image.NewRGBA(image.Rect(0, 0, int(dev.Deck.Pixels), int(dev.Deck.Pixels))) draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) currentKey.Buff = img } else { - img, err := LoadImage(currentKey.Icon) + img, err := LoadImage(dev, currentKey.Icon) if err != nil { log.Println(err) return @@ -74,24 +77,30 @@ func SetKeyImage(currentKey *api.Key, i int) { } } if currentKey.Buff != nil { - SetImage(currentKey.Buff, i, p) + SetImage(dev, currentKey.Buff, i, page) } } -func SetPage(config *api.Config, page int) { - p = page - currentPage := config.Pages[page] +func SetPage(dev *VirtualDev, page int) { + dev.Page = page + currentPage := dev.Config[page] for i := 0; i < len(currentPage); i++ { currentKey := ¤tPage[i] - go SetKey(currentKey, i, page) + go SetKey(dev, currentKey, i, page) } - EmitPage(p) + EmitPage(dev, page) } -func SetKey(currentKey *api.Key, i int, page int) { +func SetKey(dev *VirtualDev, currentKey *api.Key, i int, page int) { + var deckInfo api.StreamDeckInfo + for i := range sDInfo { + if sDInfo[i].Serial == dev.Deck.Serial { + deckInfo = sDInfo[i] + } + } if currentKey.Buff == nil { if currentKey.IconHandler == "" { - SetKeyImage(currentKey, i) + SetKeyImage(dev, currentKey, i, page) } else if currentKey.IconHandlerStruct == nil { var handler api.IconHandler @@ -104,30 +113,30 @@ func SetKey(currentKey *api.Key, i int, page int) { if handler == nil { return } - handler.Start(*currentKey, sDInfo, func(image image.Image) { - if image.Bounds().Max.X != sDInfo.IconSize || image.Bounds().Max.Y != sDInfo.IconSize { - image = api.ResizeImage(image, sDInfo.IconSize) + handler.Start(*currentKey, deckInfo, func(image image.Image) { + if image.Bounds().Max.X != int(dev.Deck.Pixels) || image.Bounds().Max.Y != int(dev.Deck.Pixels) { + image = api.ResizeImage(image, int(dev.Deck.Pixels)) } - SetImage(image, i, page) + SetImage(dev, image, i, page) currentKey.Buff = image }) currentKey.IconHandlerStruct = handler } } else { - SetImage(currentKey.Buff, i, p) + SetImage(dev, currentKey.Buff, i, page) } if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { - currentKey.IconHandlerStruct.Start(*currentKey, sDInfo, func(image image.Image) { - if image.Bounds().Max.X != sDInfo.IconSize || image.Bounds().Max.Y != sDInfo.IconSize { - image = api.ResizeImage(image, sDInfo.IconSize) + currentKey.IconHandlerStruct.Start(*currentKey, deckInfo, func(image image.Image) { + if image.Bounds().Max.X != int(dev.Deck.Pixels) || image.Bounds().Max.Y != int(dev.Deck.Pixels) { + image = api.ResizeImage(image, int(dev.Deck.Pixels)) } - SetImage(image, i, page) + SetImage(dev, image, i, page) currentKey.Buff = image }) } } -func HandleInput(key *api.Key, page int) { +func HandleInput(dev *VirtualDev, key *api.Key, page int) { if key.Command != "" { runCommand(key.Command) } @@ -136,10 +145,10 @@ func HandleInput(key *api.Key, page int) { } if key.SwitchPage != 0 { page = key.SwitchPage - 1 - SetPage(config, page) + SetPage(dev, page) } if key.Brightness != 0 { - err := dev.SetBrightness(uint8(key.Brightness)) + err := dev.Deck.SetBrightness(uint8(key.Brightness)) if err != nil { log.Println(err) } @@ -148,6 +157,12 @@ func HandleInput(key *api.Key, page int) { runCommand("xdg-open " + key.Url) } if key.KeyHandler != "" { + var deckInfo api.StreamDeckInfo + for i := range sDInfo { + if sDInfo[i].Serial == dev.Deck.Serial { + deckInfo = sDInfo[i] + } + } if key.KeyHandlerStruct == nil { var handler api.KeyHandler modules := handlers.AvailableModules() @@ -161,25 +176,25 @@ func HandleInput(key *api.Key, page int) { } key.KeyHandlerStruct = handler } - key.KeyHandlerStruct.Key(*key, sDInfo) + key.KeyHandlerStruct.Key(*key, deckInfo) } } -func Listen() { - kch, err := dev.ReadKeys() +func Listen(dev *VirtualDev) { + kch, err := dev.Deck.ReadKeys() if err != nil { log.Println(err) } - for isOpen { + for dev.IsOpen { select { case k, ok := <-kch: if !ok { - disconnect() + disconnect(dev) return } if k.Pressed == true { - if len(config.Pages)-1 >= p && len(config.Pages[p])-1 >= int(k.Index) { - HandleInput(&config.Pages[p][k.Index], p) + if len(dev.Config)-1 >= dev.Page && len(dev.Config[dev.Page])-1 >= int(k.Index) { + HandleInput(dev, &dev.Config[dev.Page][k.Index], dev.Page) } } } diff --git a/main.go b/main.go index 3581c49..a50419e 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "errors" - "fmt" + "flag" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" "github.com/unix-streamdeck/streamdeckd/handlers" @@ -21,84 +21,137 @@ import ( "syscall" ) -var dev streamdeck.Device +type VirtualDev struct { + Deck streamdeck.Device + Page int + IsOpen bool + Config []api.Page +} + +var devs map[string]*VirtualDev var config *api.Config var configPath = os.Getenv("HOME") + string(os.PathSeparator) + ".streamdeck-config.json" -var isOpen = false var disconnectSem = semaphore.NewWeighted(1) var connectSem = semaphore.NewWeighted(1) - var basicConfig = api.Config{ Modules: []string{}, - Pages: []api.Page{ + Decks: []api.Deck{ { }, }, } +var isRunning = true func main() { + configPtr := flag.String("config", configPath, "Path to config file") + flag.Parse() + if *configPtr != "" { + configPath = *configPtr + } cleanupHook() go InitDBUS() examples.RegisterBaseModules() + loadConfig() + devs = make(map[string]*VirtualDev) attemptConnection() } func attemptConnection() { - for !isOpen { - _ = openDevice() - if isOpen { - if config == nil { - loadConfig() + for isRunning { + dev := &VirtualDev{} + dev, _ = openDevice() + if dev.IsOpen { + SetPage(dev, 0) + found := false + for i := range sDInfo { + if sDInfo[i].Serial == dev.Deck.Serial { + found = true + } } - SetPage(config, p) - if sDbus != nil { - sDInfo.IconSize = int(dev.Pixels) - sDInfo.Rows = int(dev.Rows) - sDInfo.Cols = int(dev.Columns) + if !found { + sDInfo = append(sDInfo, api.StreamDeckInfo{ + Cols: int(dev.Deck.Columns), + Rows: int(dev.Deck.Rows), + IconSize: int(dev.Deck.Pixels), + Page: 0, + Serial: dev.Deck.Serial, + }) } - Listen() + go Listen(dev) } } } -func disconnect() { +func disconnect(dev *VirtualDev) { ctx := context.Background() err := disconnectSem.Acquire(ctx, 1) if err != nil { return } defer disconnectSem.Release(1) - if !isOpen { + if !dev.IsOpen { return } - log.Println("Device disconnected") - _ = dev.Close() - isOpen = false - unmountHandlers() + log.Println("Device (" + dev.Deck.Serial + ") disconnected") + _ = dev.Deck.Close() + dev.IsOpen = false + unmountDevHandlers(dev) } -func openDevice() error { +func openDevice() (*VirtualDev, error) { ctx := context.Background() err := connectSem.Acquire(ctx, 1) if err != nil { - return err + return &VirtualDev{}, err } defer connectSem.Release(1) d, err := streamdeck.Devices() if err != nil { - return err + return &VirtualDev{}, err } if len(d) == 0 { - return errors.New("No streamdeck devices found") + return &VirtualDev{}, errors.New("No streamdeck devices found") } - err = d[0].Open() + device := streamdeck.Device{Serial: ""} + for i := range d { + found := false + for s := range devs { + if d[i].ID == devs[s].Deck.ID && devs[s].IsOpen { + found = true + break + } + } + if !found { + device = d[i] + } + } + if len(device.Serial) != 12 { + return &VirtualDev{}, errors.New("No streamdeck devices found") + } + err = device.Open() if err != nil { - return err + return &VirtualDev{}, err } - dev = d[0] - isOpen = true - fmt.Println("Device (" + dev.Serial + ") connected") - return nil + devNo := -1 + for i := range config.Decks { + if config.Decks[i].Serial == device.Serial { + devNo = i + } + } + if devNo == -1 { + var pages []api.Page + page := api.Page{} + for i := 0; i < int(device.Rows)*int(device.Columns); i++ { + page = append(page, api.Key{}) + } + pages = append(pages, page) + config.Decks = append(config.Decks, api.Deck{Serial: device.Serial, Pages: pages}) + devNo = len(config.Decks) -1 + } + dev := &VirtualDev{Deck: device, Page: 0, IsOpen: true, Config: config.Decks[devNo].Pages} + devs[device.Serial] = dev + log.Println("Device (" + device.Serial + ") connected") + return dev, nil } func loadConfig() { @@ -116,19 +169,11 @@ func loadConfig() { log.Println(err) } config = &basicConfig - page := config.Pages[0] - for i := 0; i < int(dev.Rows)*int(dev.Columns); i++ { - page = append(page, api.Key{}) - } - config.Pages[0] = page err = SaveConfig() if err != nil { log.Println(err) } } - if len(config.Pages) == 0 { - config.Pages = append(config.Pages, api.Page{}) - } if len(config.Modules) > 0 { for _, module := range config.Modules { handlers.LoadModule(module) @@ -166,8 +211,21 @@ func cleanupHook() { signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1, syscall.SIGUSR2) go func() { <-sigs - _ = dev.Reset() - os.Exit(0) + isRunning = false + unmountHandlers() + var err error + for s := range devs { + if devs[s].IsOpen { + err = devs[s].Deck.Reset() + if err != nil { + log.Println(err) + } + err = devs[s].Deck.Close() + if err != nil { + log.Println(err) + } + } + } }() } @@ -179,17 +237,30 @@ func SetConfig(configString string) error { if err != nil { return err } - if len(config.Pages) == 0 { - config.Pages = append(config.Pages, api.Page{}) + for s := range devs { + dev := devs[s] + for i := range config.Decks { + if dev.Deck.Serial == config.Decks[i].Serial { + dev.Config = config.Decks[i].Pages + } + } + SetPage(dev, devs[s].Page) } - SetPage(config, p) return nil } func ReloadConfig() error { unmountHandlers() loadConfig() - SetPage(config, p) + for s := range devs { + dev := devs[s] + for i := range config.Decks { + if dev.Deck.Serial == config.Decks[i].Serial { + dev.Config = config.Decks[i].Pages + } + } + SetPage(dev, devs[s].Page) + } return nil } @@ -214,16 +285,20 @@ func SaveConfig() error { } return nil } - func unmountHandlers() { - if config != nil && len(config.Pages) > 0 { - for i := range config.Pages { - page := config.Pages[i] - for i2 := 0; i2 < len(page); i2++ { - key := &page[i2] - if key.IconHandlerStruct != nil { - key.IconHandlerStruct.Stop() - } + for s := range devs { + dev := devs[s] + unmountDevHandlers(dev) + } +} + +func unmountDevHandlers(dev *VirtualDev) { + for i := range dev.Config { + page := dev.Config[i] + for i2 := 0; i2 < len(page); i2++ { + key := &page[i2] + if key.IconHandlerStruct != nil { + key.IconHandlerStruct.Stop() } } } From b89d29e4859afa8ccdef733669a6ea27711cb65c Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sat, 15 May 2021 18:30:17 +0100 Subject: [PATCH 38/50] Added config auto migrator --- main.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index a50419e..2e99885 100644 --- a/main.go +++ b/main.go @@ -30,6 +30,7 @@ type VirtualDev struct { var devs map[string]*VirtualDev var config *api.Config +var migrateConfig = false var configPath = os.Getenv("HOME") + string(os.PathSeparator) + ".streamdeck-config.json" var disconnectSem = semaphore.NewWeighted(1) var connectSem = semaphore.NewWeighted(1) @@ -133,6 +134,11 @@ func openDevice() (*VirtualDev, error) { return &VirtualDev{}, err } devNo := -1 + if migrateConfig { + config.Decks[0].Serial = device.Serial + _ = SaveConfig() + migrateConfig = false + } for i := range config.Decks { if config.Decks[i].Serial == device.Serial { devNo = i @@ -188,8 +194,14 @@ func readConfig() (*api.Config, error) { } var config api.Config err = json.Unmarshal(data, &config) - if err != nil { - return &api.Config{}, err + if err != nil || config.Decks == nil { + var deprecatedConfig api.DepracatedConfig + err = json.Unmarshal(data, &deprecatedConfig) + if err != nil { + return &api.Config{}, err + } + config = api.Config{Modules: deprecatedConfig.Modules, Decks: []api.Deck{{Pages: deprecatedConfig.Pages, Serial: ""}}} + migrateConfig = true } return &config, nil } From fc899dff820fc90140a2399b464f59fdf4194bd9 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 17 May 2021 11:59:36 +0100 Subject: [PATCH 39/50] Fixed api version in go.mod --- README.md | 10 ++++++++++ go.mod | 2 +- go.sum | 7 ++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 51468f7..ef44a26 100644 --- a/README.md +++ b/README.md @@ -80,3 +80,13 @@ There is a D-Bus interface built into the daemon, the service name and interface #### Signals - Page - sends the number of the page switched to on the StreamDeck + + +### Custom Handlers + + + +#### Button Press Handler + + +#### Icon Handler \ No newline at end of file diff --git a/go.mod b/go.mod index fed0d01..7ba844e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907 + github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a diff --git a/go.sum b/go.sum index ed030f0..2902d3a 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907 h1:MBWGv1fYvM3upBP2Y9TTMgQxMyE3o+ivfBuQ0vmsZh8= -github.com/unix-streamdeck/api v0.0.0-20201228201207-ca404527f907/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91 h1:YVr3Fdr92LM1eFXdkkuWfYXmFUj6n8v5lS9oOJMCQUs= +github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -103,9 +103,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg= golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw= golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6 h1:nfeHNc1nAqecKCy2FCy4HY+soOOe5sDLJ/gZLbx6GYI= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -119,7 +117,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= From 3a7b55c17b6ea95bc1230425c5afb53654b91deb Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 30 May 2021 01:22:35 +0100 Subject: [PATCH 40/50] Added time delay in attemptConnection --- main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/main.go b/main.go index 2e99885..cddc498 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "os/exec" "os/signal" "syscall" + "time" ) type VirtualDev struct { @@ -80,6 +81,7 @@ func attemptConnection() { } go Listen(dev) } + time.Sleep(250 * time.Millisecond) } } From d51855c7688b5513c0e61340bf7dee18c91c27d4 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Wed, 21 Jul 2021 19:19:03 +0100 Subject: [PATCH 41/50] Stopped child processes being killed when streamdeckd is stopped/restarted --- main.go | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/main.go b/main.go index cddc498..84ff10c 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "encoding/json" "errors" "flag" + "fmt" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/driver" "github.com/unix-streamdeck/streamdeckd/handlers" @@ -23,8 +24,8 @@ import ( ) type VirtualDev struct { - Deck streamdeck.Device - Page int + Deck streamdeck.Device + Page int IsOpen bool Config []api.Page } @@ -154,7 +155,7 @@ func openDevice() (*VirtualDev, error) { } pages = append(pages, page) config.Decks = append(config.Decks, api.Deck{Serial: device.Serial, Pages: pages}) - devNo = len(config.Decks) -1 + devNo = len(config.Decks) - 1 } dev := &VirtualDev{Deck: device, Page: 0, IsOpen: true, Config: config.Decks[devNo].Pages} devs[device.Serial] = dev @@ -209,22 +210,30 @@ func readConfig() (*api.Config, error) { } func runCommand(command string) { - //args := strings.Split(command, " ") - c := exec.Command("/bin/sh", "-c", command) - if err := c.Start(); err != nil { - log.Println(err) - } - err := c.Wait() - if err != nil { - log.Printf("command failed: %s", err) - } + go func() { + cmd := exec.Command("/bin/sh", "-c", "/usr/bin/nohup "+command) + + cmd.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + Pgid: 0, + Pdeathsig: syscall.SIGHUP, + } + if err := cmd.Start(); err != nil { + fmt.Println("There was a problem running ", command, ":", err) + } else { + pid := cmd.Process.Pid + cmd.Process.Release() + fmt.Println(command, " has been started with pid", pid) + } + }() } func cleanupHook() { sigs := make(chan os.Signal, 1) - signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGUSR1, syscall.SIGUSR2) + signal.Notify(sigs, syscall.SIGSTOP, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGINT) go func() { <-sigs + log.Println("Cleaning up") isRunning = false unmountHandlers() var err error @@ -240,6 +249,7 @@ func cleanupHook() { } } } + os.Exit(0) }() } From 3432a18947dc4a92860cec5832019cd24ca36aca Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Wed, 21 Jul 2021 20:38:10 +0100 Subject: [PATCH 42/50] Updated api --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ba844e..7cdbe6d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91 + github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a diff --git a/go.sum b/go.sum index 2902d3a..8819f37 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91 h1:YVr3Fdr92LM1eFXdkkuWfYXmFUj6n8v5lS9oOJMCQUs= -github.com/unix-streamdeck/api v0.0.0-20210515173054-b84ad539ac91/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f h1:JZ7w6kwybh4/+lBod9SITHk2gTQo/EEV5QGVsDlRZjc= +github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= From 35d8bfc9548ffd159518746cf35ed9c7f4115f12 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Mon, 23 Aug 2021 20:27:29 +0100 Subject: [PATCH 43/50] Enabled module stopping between pages --- handlers/examples/gif.go | 28 +++++++++++++------- handlers/examples/spotify.go | 50 +++++++++++++++++++++--------------- handlers/examples/time.go | 36 ++++++++++++++++---------- interface.go | 3 +++ main.go | 17 ++++++++---- 5 files changed, 87 insertions(+), 47 deletions(-) diff --git a/handlers/examples/gif.go b/handlers/examples/gif.go index ab04f35..fad76e1 100644 --- a/handlers/examples/gif.go +++ b/handlers/examples/gif.go @@ -16,9 +16,13 @@ import ( type GifIconHandler struct { Running bool Lock *semaphore.Weighted + Quit chan bool } func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { + if s.Quit == nil { + s.Quit = make(chan bool) + } if s.Lock == nil { s.Lock = semaphore.NewWeighted(1) } @@ -50,7 +54,7 @@ func (s *GifIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback fu } frames[i] = img } - go loop(frames, timeDelay, callback, s) + go s.loop(frames, timeDelay, callback) } func (s *GifIconHandler) IsRunning() bool { @@ -63,9 +67,10 @@ func (s *GifIconHandler) SetRunning(running bool) { func (s *GifIconHandler) Stop() { s.Running = false + s.Quit <- true } -func loop(frames []image.Image, timeDelay int, callback func(image image.Image), s *GifIconHandler) { +func (s *GifIconHandler) loop(frames []image.Image, timeDelay int, callback func(image image.Image)) { ctx := context.Background() err := s.Lock.Acquire(ctx, 1) if err != nil { @@ -73,14 +78,19 @@ func loop(frames []image.Image, timeDelay int, callback func(image image.Image), } defer s.Lock.Release(1) gifIndex := 0 - for s.Running { - img := frames[gifIndex] - callback(img) - gifIndex++ - if gifIndex >= len(frames) { - gifIndex = 0 + for { + select { + case <-s.Quit: + return + default: + img := frames[gifIndex] + callback(img) + gifIndex++ + if gifIndex >= len(frames) { + gifIndex = 0 + } + time.Sleep(time.Duration(timeDelay * 10000000)) } - time.Sleep(time.Duration(timeDelay * 10000000)) } } diff --git a/handlers/examples/spotify.go b/handlers/examples/spotify.go index 97d2791..c9ae281 100644 --- a/handlers/examples/spotify.go +++ b/handlers/examples/spotify.go @@ -15,16 +15,20 @@ import ( type SpotifyIconHandler struct { Running bool oldUrl string + Quit chan bool } func (s *SpotifyIconHandler) Start(key api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { s.Running = true + if s.Quit == nil { + s.Quit = make(chan bool) + } c, err := Connect() if err != nil { log.Println(err) return } - go run(c, s, callback) + go s.run(c, callback) } func (s *SpotifyIconHandler) IsRunning() bool { @@ -37,30 +41,36 @@ func (s *SpotifyIconHandler) SetRunning(running bool) { func (s *SpotifyIconHandler) Stop() { s.Running = false + s.Quit <- true } -func run(c *Connection, s *SpotifyIconHandler, callback func(image image.Image)) { +func (s *SpotifyIconHandler) run(c *Connection, callback func(image image.Image)) { defer c.Close() - for s.Running { - url, err := c.GetAlbumArtUrl() - if err != nil { - log.Println(err) - time.Sleep(time.Second) - continue - } - if url == s.oldUrl { - time.Sleep(time.Second) - continue - } - img, err := getImage(url) - if err != nil { - log.Println(err) + for { + select { + case <-s.Quit: + return + default: + url, err := c.GetAlbumArtUrl() + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + if url == s.oldUrl { + time.Sleep(time.Second) + continue + } + img, err := getImage(url) + if err != nil { + log.Println(err) + time.Sleep(time.Second) + continue + } + callback(img) + s.oldUrl = url time.Sleep(time.Second) - continue } - callback(img) - s.oldUrl = url - time.Sleep(time.Second) } } diff --git a/handlers/examples/time.go b/handlers/examples/time.go index 85f25d7..3c55370 100644 --- a/handlers/examples/time.go +++ b/handlers/examples/time.go @@ -11,11 +11,15 @@ import ( type TimeIconHandler struct { Running bool + Quit chan bool } func (t *TimeIconHandler) Start(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { t.Running = true - go timeLoop(k, info, callback, t) + if t.Quit == nil { + t.Quit = make(chan bool) + } + go t.timeLoop(k, info, callback) } func (t *TimeIconHandler) IsRunning() bool { @@ -28,21 +32,27 @@ func (t *TimeIconHandler) SetRunning(running bool) { func (t *TimeIconHandler) Stop() { t.Running = false + t.Quit <- true } -func timeLoop(k api.Key, info api.StreamDeckInfo, callback func(image image.Image), handler *TimeIconHandler) { - for handler.Running { - img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) - draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) - t := time.Now() - tString := t.Format("15:04:05") - imgParsed, err := api.DrawText(img, tString, k.TextSize, k.TextAlignment) - if err != nil { - log.Println(err) - } else { - callback(imgParsed) +func (t *TimeIconHandler) timeLoop(k api.Key, info api.StreamDeckInfo, callback func(image image.Image)) { + for { + select { + case <- t.Quit: + return + default: + img := image.NewRGBA(image.Rect(0, 0, info.IconSize, info.IconSize)) + draw.Draw(img, img.Bounds(), image.Black, image.ZP, draw.Src) + t := time.Now() + tString := t.Format("15:04:05") + imgParsed, err := api.DrawText(img, tString, k.TextSize, k.TextAlignment) + if err != nil { + log.Println(err) + } else { + callback(imgParsed) + } + time.Sleep(time.Second) } - time.Sleep(time.Second) } } diff --git a/interface.go b/interface.go index ff0d825..fca3756 100644 --- a/interface.go +++ b/interface.go @@ -82,6 +82,7 @@ func SetKeyImage(dev *VirtualDev, currentKey *api.Key, i int, page int) { } func SetPage(dev *VirtualDev, page int) { + unmountPageHandlers(dev.Config[dev.Page]) dev.Page = page currentPage := dev.Config[page] for i := 0; i < len(currentPage); i++ { @@ -113,6 +114,7 @@ func SetKey(dev *VirtualDev, currentKey *api.Key, i int, page int) { if handler == nil { return } + log.Printf("Created & Started %s\n", currentKey.IconHandler) handler.Start(*currentKey, deckInfo, func(image image.Image) { if image.Bounds().Max.X != int(dev.Deck.Pixels) || image.Bounds().Max.Y != int(dev.Deck.Pixels) { image = api.ResizeImage(image, int(dev.Deck.Pixels)) @@ -126,6 +128,7 @@ func SetKey(dev *VirtualDev, currentKey *api.Key, i int, page int) { SetImage(dev, currentKey.Buff, i, page) } if currentKey.IconHandlerStruct != nil && !currentKey.IconHandlerStruct.IsRunning() { + log.Printf("Started %s\n", currentKey.IconHandler) currentKey.IconHandlerStruct.Start(*currentKey, deckInfo, func(image image.Image) { if image.Bounds().Max.X != int(dev.Deck.Pixels) || image.Bounds().Max.Y != int(dev.Deck.Pixels) { image = api.ResizeImage(image, int(dev.Deck.Pixels)) diff --git a/main.go b/main.go index 84ff10c..0438acf 100644 --- a/main.go +++ b/main.go @@ -318,12 +318,19 @@ func unmountHandlers() { func unmountDevHandlers(dev *VirtualDev) { for i := range dev.Config { - page := dev.Config[i] - for i2 := 0; i2 < len(page); i2++ { - key := &page[i2] - if key.IconHandlerStruct != nil { + unmountPageHandlers(dev.Config[i]) + } +} + +func unmountPageHandlers(page api.Page) { + for i2 := 0; i2 < len(page); i2++ { + key := &page[i2] + if key.IconHandlerStruct != nil { + log.Printf("Stopping %s\n", key.IconHandler) + go func() { key.IconHandlerStruct.Stop() - } + log.Printf("Stopped %s\n", key.IconHandler) + }() } } } From 54656a4891737f18aa6bc0dfb18916d9030dfd7f Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 29 Aug 2021 16:06:13 +0100 Subject: [PATCH 44/50] Fixed handlers on home page not restarting after disconnect on page other than home page --- interface.go | 4 +++- main.go | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/interface.go b/interface.go index fca3756..9b8cf00 100644 --- a/interface.go +++ b/interface.go @@ -82,7 +82,9 @@ func SetKeyImage(dev *VirtualDev, currentKey *api.Key, i int, page int) { } func SetPage(dev *VirtualDev, page int) { - unmountPageHandlers(dev.Config[dev.Page]) + if page != dev.Page { + unmountPageHandlers(dev.Config[dev.Page]) + } dev.Page = page currentPage := dev.Config[page] for i := 0; i < len(currentPage); i++ { diff --git a/main.go b/main.go index 0438acf..701ab33 100644 --- a/main.go +++ b/main.go @@ -64,7 +64,7 @@ func attemptConnection() { dev := &VirtualDev{} dev, _ = openDevice() if dev.IsOpen { - SetPage(dev, 0) + SetPage(dev, dev.Page) found := false for i := range sDInfo { if sDInfo[i].Serial == dev.Deck.Serial { @@ -123,6 +123,14 @@ func openDevice() (*VirtualDev, error) { if d[i].ID == devs[s].Deck.ID && devs[s].IsOpen { found = true break + } else if d[i].Serial == s && !devs[s].IsOpen { + err = d[i].Open() + if err != nil { + return &VirtualDev{}, err + } + devs[s].Deck = d[i] + devs[s].IsOpen = true + return devs[s], nil } } if !found { @@ -327,10 +335,12 @@ func unmountPageHandlers(page api.Page) { key := &page[i2] if key.IconHandlerStruct != nil { log.Printf("Stopping %s\n", key.IconHandler) - go func() { - key.IconHandlerStruct.Stop() - log.Printf("Stopped %s\n", key.IconHandler) - }() + if key.IconHandlerStruct.IsRunning() { + go func() { + key.IconHandlerStruct.Stop() + log.Printf("Stopped %s\n", key.IconHandler) + }() + } } } } From 81fb06368041f82296581acc5a9481e8a40c94b7 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Fri, 10 Sep 2021 19:07:16 +0100 Subject: [PATCH 45/50] Added 'press button' dbus method' --- dbus.go | 9 +++++++++ go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/dbus.go b/dbus.go index ddbae2b..072ee14 100644 --- a/dbus.go +++ b/dbus.go @@ -80,6 +80,15 @@ func (StreamDeckDBus) GetModules() (string, *dbus.Error) { return string(modulesString), nil } +func (StreamDeckDBus) PressButton(serial string, keyIndex int) *dbus.Error { + dev, ok := devs[serial] + if !ok || !dev.IsOpen{ + return dbus.MakeFailedError(errors.New("Can't find connected device: " + serial)) + } + HandleInput(dev, &dev.Config[dev.Page][keyIndex], dev.Page) + return nil +} + func InitDBUS() error { var err error conn, err = dbus.SessionBus() diff --git a/go.mod b/go.mod index 7cdbe6d..b677343 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f + github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a diff --git a/go.sum b/go.sum index 8819f37..387e539 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f h1:JZ7w6kwybh4/+lBod9SITHk2gTQo/EEV5QGVsDlRZjc= -github.com/unix-streamdeck/api v0.0.0-20210721193311-76065a74bf1f/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7 h1:vhl0mnDkG8H7i/Xl2U0fAZuf8pO07C49UZIum/M53mk= +github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= From 92e36a9e37b17b22881890476f0e2704adc5cc45 Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Fri, 10 Sep 2021 20:56:42 +0100 Subject: [PATCH 46/50] Updated README --- README.md | 121 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index ef44a26..ca73366 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ -# Streamdeckd +# Streamdeckd + +### Installation + +- create the file `/etc/udev/rules.d/50-elgato.rules` with the following config -### Installation - -- create the file `/etc/udev/rules.d/50-elgato.rules` with the following config ``` SUBSYSTEM=="input", GROUP="input", MODE="0666" SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE:="666", GROUP="plugdev" @@ -10,19 +11,18 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE:="666" SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006c", MODE:="666", GROUP="plugdev" SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE:="666", GROUP="plugdev" ``` - -- run `sudo udevadm control --reload-rules` to reload the udev rules - -Then xdotool will be required to simulate keypresses, to install this run: - -#### Arch - -`sudo pacman -S xdotool` - -#### Debian based - -`sudo apt install xdotool` +- run `sudo udevadm control --reload-rules` to reload the udev rules + +Then xdotool will be required to simulate keypresses, to install this run: + +#### Arch + +`sudo pacman -S xdotool` + +#### Debian based + +`sudo apt install xdotool` ### Configuration @@ -34,18 +34,30 @@ An example config would be something like: ```json { - "pages": [ - [ - { - "switch_page": 1, - "icon": "~/icon.png" - } - ] + "modules": [ + "/home/user/module.so" + ], + "decks": [ + { + "serial": "AB12C3D45678", + "pages": [ + [ + { + "switch_page": 1, + "icon": "~/icon.png" + } + ] + ] + } ] } ``` -The outer array is the list of pages, the inner array is the list of button on that page, with the buttons going in a right to left order. +At the top is the list of custom modules, these are go plugins in the .so format, following that is the list of deck +objects, each represents a different streamdeck device, and contains its serial, and its list of pages + +The outer array in a deck is the list of pages, the inner array is the list of button on that page, with the buttons +going in a right to left order. The actions you can have on a button are: @@ -55,38 +67,67 @@ The actions you can have on a button are: - `brightness`: set the brightness of the streamdeck as a percentage - `switch_page`: change the active page on the streamdeck - ### D-Bus -There is a D-Bus interface built into the daemon, the service name and interface for D-Bus are `com.unixstreamdeck.streamdeckd` and `com/unixstreamdeck/streamdeckd` respectively, and is made up of the following methods/signals +There is a D-Bus interface built into the daemon, the service name and interface for D-Bus +are `com.unixstreamdeck.streamdeckd` and `com/unixstreamdeck/streamdeckd` respectively, and is made up of the following +methods/signals #### Methods -- GetConfig - returns the current running config -- SetConfig - sets the config, without saving to disk, takes in Stringified json, returns an error if anything breaks -- ReloadConfig - reloads the config from disk -- GetDeckInfo - Returns information about the active streamdeck in the format of +- GetConfig - returns the current running config +- SetConfig - sets the config, without saving to disk, takes in Stringified json, returns an error if anything breaks +- ReloadConfig - reloads the config from disk +- GetDeckInfo - Returns information about all the active streamdecks in the format of + ```json -{ - "icon_size": 72, - "rows": 3, - "cols": 5, - "page": 0 -} +[ + { + "icon_size": 72, + "rows": 3, + "cols": 5, + "page": 0, + "serial": "AB12C3D45678" + } +] ``` + - SetPage - Set the page on the streamdeck to the number passed to it, returns an error if anything breaks -- CommitConfig - Commits the currently active config to disk, returns an error if anything breaks +- CommitConfig - Commits the currently active config to disk, returns an error if anything breaks +- GetModules - Get the list of loaded modules, and the config fields those modules use +- PressButton - Simulates a button press on the streamdeck device, consumes a device serial, and a key index + #### Signals - Page - sends the number of the page switched to on the StreamDeck +### Custom Modules -### Custom Handlers +To create custom modules, I suggest looking at the gif, counter, and time modules in the example handlers package in streamdeckd, they should be in a file with the GetModule method as shown below +#### Loading Modules into streamdeckd +Modules require a method on them in the main package called "GetModule" that returns an instance of [handler.Module](https://github.com/unix-streamdeck/streamdeckd/blob/575e672c26f275d35a016be6406ceb8480ccfff5/handlers/handlers.go#L9) e.g -#### Button Press Handler +```go +package main +func GetModule() handlers.Module { + return handlers.Module{ + Name: "CustomModule", // the name that will be used in the icon_handler/key_handler field in the config, and that will be shown in the handler dropdown in streamdeckui + NewIcon: func() api.IconHandler { return &CustomerIconHandler{}}, // Method to create a new instance of the Icon handler, if left empty, streamdeckui will not include it in the icon handler fields + NewKey: func() api.KeyHandler { return &CustomerKeyHandler{}}, // Method to create a new instance of the Key Handler, if left empty, streamdeckui will not include it in the key handler fields + IconFields: []api.Field{ // list of fields to be shown in streamdeckui when the icon handler is selected + { + Title: "Icon", // name of field to show in UI + Name: "icon", // name of field that will be included in the iconHandlerFields map + Type: "File" // type of input to show on streamdeckui, options are Text, File, TextAlignment, and Number + FileTypes: []string{".png", ".jpg"} // Allowed file types if a File input type is used + } + }, + KeyFields: []api.Field{}, // Same as IconFields + } +} -#### Icon Handler \ No newline at end of file +``` \ No newline at end of file From 051e5142d6e2be0550267befc09b2182cddee4ac Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Fri, 10 Sep 2021 20:58:00 +0100 Subject: [PATCH 47/50] Updated README --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index ca73366..79f5c27 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,16 @@ Modules require a method on them in the main package called "GetModule" that ret ```go package main +type CustomIconHandler struct { + +} +... + +type CustomKeyHandler struct { + +} +... + func GetModule() handlers.Module { return handlers.Module{ Name: "CustomModule", // the name that will be used in the icon_handler/key_handler field in the config, and that will be shown in the handler dropdown in streamdeckui From acfb945bb1ebfbbfdc10eb2fac9d5aa2939e652e Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 12 Sep 2021 15:52:52 +0100 Subject: [PATCH 48/50] Updated api version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b677343..644eb94 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.14 require ( github.com/godbus/dbus/v5 v5.0.4-0.20200513180336-df5ef3eb7cca - github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7 + github.com/unix-streamdeck/api v1.0.0 github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b golang.org/x/image v0.0.0-20201208152932-35266b937fa6 // indirect golang.org/x/sync v0.0.0-20201207232520-09787c993a3a diff --git a/go.sum b/go.sum index 387e539..9dc5a71 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7 h1:vhl0mnDkG8H7i/Xl2U0fAZuf8pO07C49UZIum/M53mk= -github.com/unix-streamdeck/api v0.0.0-20210910180508-71e2499b27a7/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= +github.com/unix-streamdeck/api v1.0.0 h1:GZIslyThiZgcZ/GIR0O/DWnciL6bijSdIA+TSnKzHsI= +github.com/unix-streamdeck/api v1.0.0/go.mod h1:Z8bzDHQnWv/2hx9wQXp0/qw6Fp4ty5pFRsgaBG5WYAI= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b h1:27gVti9+OevmBC2BnWlKC0dQ0eiIHh7PvYTWxt4vb6A= github.com/unix-streamdeck/driver v0.0.0-20200817173808-cdaf123c076b/go.mod h1:i3Eg6kJBslgUk2VIPJ3Cclta2fpV1KJrOnOnR8gnVKY= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= From 9868442a415a80096f26b331d3523aece1ae281a Mon Sep 17 00:00:00 2001 From: The-Jonsey Date: Sun, 12 Sep 2021 17:39:59 +0100 Subject: [PATCH 49/50] Prevented crash if deck not found on HandleInput --- interface.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/interface.go b/interface.go index 9b8cf00..05caedf 100644 --- a/interface.go +++ b/interface.go @@ -163,11 +163,16 @@ func HandleInput(dev *VirtualDev, key *api.Key, page int) { } if key.KeyHandler != "" { var deckInfo api.StreamDeckInfo + found := false for i := range sDInfo { if sDInfo[i].Serial == dev.Deck.Serial { deckInfo = sDInfo[i] + found = true } } + if !found { + return + } if key.KeyHandlerStruct == nil { var handler api.KeyHandler modules := handlers.AvailableModules() From f9761e93d6605c6db27a8edf5238a79028a8a680 Mon Sep 17 00:00:00 2001 From: Louis Jones Date: Sat, 9 Oct 2021 11:18:36 +0100 Subject: [PATCH 50/50] Added dbus method for getting handler thumbnail --- dbus.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/dbus.go b/dbus.go index 072ee14..b077407 100644 --- a/dbus.go +++ b/dbus.go @@ -1,12 +1,17 @@ package main import ( + "bytes" + "encoding/base64" "encoding/json" "errors" "github.com/godbus/dbus/v5" "github.com/unix-streamdeck/api" "github.com/unix-streamdeck/streamdeckd/handlers" + "image" + "image/png" "log" + "time" ) var conn *dbus.Conn @@ -89,6 +94,68 @@ func (StreamDeckDBus) PressButton(serial string, keyIndex int) *dbus.Error { return nil } +func (StreamDeckDBus) GetHandlerExample(serial string, keyString string) (string, *dbus.Error) { + var key *api.Key + err := json.Unmarshal([]byte(keyString), &key) + if err != nil { + return "", dbus.MakeFailedError(err) + } + if key.IconHandler == "" || key.IconHandler == "Default" { + return "", dbus.MakeFailedError(errors.New("Invalid icon handler")) + } + var handler api.IconHandler + modules := handlers.AvailableModules() + for _, module := range modules { + if module.Name == key.IconHandler { + handler = module.NewIcon() + break + } + } + if handler == nil { + return "", dbus.MakeFailedError(errors.New("Invalid icon handler")) + } + var dev api.StreamDeckInfo + for _, info := range sDInfo { + if info.Serial == serial { + dev = info + break + } + } + if dev.Serial != serial { + return "", dbus.MakeFailedError(errors.New("could not find device")) + } + var img image.Image + log.Println("Created and running " + key.IconHandler + " for dbus") + handler.Start(*key, dev, func(image image.Image) { + if image.Bounds().Max.X != dev.IconSize || image.Bounds().Max.Y != dev.IconSize { + image = api.ResizeImage(image, dev.IconSize) + } + img = image + log.Println("Stopping " + key.IconHandler + " for dbus") + handler.Stop() + log.Println("Stopped " + key.IconHandler + " for dbus") + }) + timer := time.NewTimer(5 * time.Second) + go func() { + <-timer.C + if handler.IsRunning() { + log.Println("Handler still running") + handler.Stop() + } else { + log.Println("Handler had stopped") + } + }() + for handler.IsRunning() { + } + if img == nil { + return "", dbus.MakeFailedError(errors.New("Handler did not respond in a timely fashion")) + } + buf := new(bytes.Buffer) + err = png.Encode(buf, img) + imageBits := buf.Bytes() + return "data:image/png;base64," + base64.StdEncoding.EncodeToString(imageBits), nil +} + func InitDBUS() error { var err error conn, err = dbus.SessionBus()