{"id":16790163,"url":"https://github.com/matthewpi/streamdeck","last_synced_at":"2025-06-27T16:33:01.702Z","repository":{"id":39989876,"uuid":"449387390","full_name":"matthewpi/streamdeck","owner":"matthewpi","description":"Library for directly interacting and controlling an Elgato Stream Deck on Linux.","archived":false,"fork":false,"pushed_at":"2024-02-26T23:47:27.000Z","size":58,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-10T23:32:42.695Z","etag":null,"topics":["elgato","elgato-stream-deck","golang","streamdeck"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matthewpi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-18T17:45:54.000Z","updated_at":"2024-03-05T09:27:41.000Z","dependencies_parsed_at":"2024-02-27T00:36:34.606Z","dependency_job_id":"418542bf-0b66-41cf-bf53-8a191ae159cf","html_url":"https://github.com/matthewpi/streamdeck","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/matthewpi/streamdeck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewpi%2Fstreamdeck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewpi%2Fstreamdeck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewpi%2Fstreamdeck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewpi%2Fstreamdeck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matthewpi","download_url":"https://codeload.github.com/matthewpi/streamdeck/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewpi%2Fstreamdeck/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262293553,"owners_count":23288763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elgato","elgato-stream-deck","golang","streamdeck"],"created_at":"2024-10-13T08:29:08.600Z","updated_at":"2025-06-27T16:33:01.659Z","avatar_url":"https://github.com/matthewpi.png","language":"Go","readme":"# Stream Deck\n\nLibrary for directly interacting and controlling an Elgato Stream Deck on Linux.\n\nThis library is designed to take exclusive control over a Stream Deck using USB\nHID, if you are an end-user looking for software just to control your Stream\nDeck, this is not what you are looking for. If you are looking to build your own\nsoftware whether it be a CLI or GUI app to control your Stream Deck, you have\ncome to the right place.\n\nThis library was inspired by many of the other Go streamdeck libraries.  I\ncreated this library because all the other libraries I found either didn't work,\ndidn't support the features I wanted, required CGO, or were difficult to use.\n\nThe internal `hid` package was heavily-based on \u003chttps://github.com/zserge/hid\u003e\nwith some improvements from \u003chttps://github.com/rafaelmartins/usbfs\u003e.\n\n## Features\n\n- Native Linux support (No CGO)\n  - Caveat: This library does not support Windows or MacOS, and will not for the conceivable future.\n- Supports GIFs\n  - The most use~~less~~ful feature\n- Easy to use\n- Performant\n\n### Missing\n\n- Tests\n- More in-depth examples and documentation\n- Probably some other things I had no idea existed\n\n## Example\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"embed\"\n\t\"fmt\"\n\t\"image\"\n\t\"image/gif\"\n\t\"log\"\n\t\"os\"\n\t\"os/signal\"\n\t\"path/filepath\"\n\n\t\"golang.org/x/sys/unix\"\n\n\t\"github.com/matthewpi/streamdeck\"\n\t\"github.com/matthewpi/streamdeck/button\"\n\t\"github.com/matthewpi/streamdeck/view\"\n)\n\n//go:embed .embed/*.png .embed/*.gif\nvar embedFs embed.FS\n\nfunc main() {\n\tif err := start(context.Background()); err != nil {\n\t\tpanic(err)\n\t\treturn\n\t}\n}\n\nfunc start(ctx context.Context) error {\n\tctx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tsd, err := streamdeck.New(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to find or connect to a streamdeck: %w\", err)\n\t}\n\tif sd == nil {\n\t\treturn fmt.Errorf(\"no streamdeck devices found: %w\", err)\n\t}\n\tdefer func(ctx context.Context, sd *streamdeck.StreamDeck) {\n\t\tif err := sd.Close(ctx); err != nil {\n\t\t\tlog.Printf(\"an error occurred while closing the streamdeck: %v\\n\")\n\t\t}\n\t}(ctx, sd)\n\n\tif err := sd.SetBrightness(ctx, 25); err != nil {\n\t\treturn fmt.Errorf(\"failed to set streamdeck brightness: %w\", err)\n\t}\n\n\tbuttons, err := view.NewButtons(sd)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create button view: %w\", err)\n\t}\n\n\tsd.SetHandler(func(ctx context.Context, index int) error {\n\t\tswitch index {\n\t\tcase 0:\n\t\t\tfmt.Println(\"you pressed a button!\")\n\t\tcase 1:\n\t\t\tfmt.Println(\"you pressed another button!\")\n\t\t}\n\t\treturn nil\n\t})\n\n\tbuttons.Set(1, button.NewImage(mustGetImage(sd, \"spotify_play.png\")))\n\tbuttons.Set(2, button.NewGIF(sd, mustGetGIF(\"peepoDance.gif\")))\n\n\tctx3, cancel3 := context.WithCancel(ctx)\n\tdefer cancel3()\n\tif err := buttons.Apply(ctx3); err != nil {\n\t\treturn fmt.Errorf(\"failed to update streamdeck buttons: %w\", err)\n\t}\n\n\tch := make(chan os.Signal, 1)\n\tsignal.Notify(ch, os.Interrupt, unix.SIGTERM)\n\t\u003c-ch\n\tlog.Println(\"shutting down\")\n\treturn nil\n}\n\nfunc getImage(sd *streamdeck.StreamDeck, filename string) ([]byte, error) {\n\tf, err := embedFs.Open(filepath.Join(\".embed\", filename))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\timg, _, err := image.Decode(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn sd.ProcessImage(img)\n}\n\nfunc mustGetImage(sd *streamdeck.StreamDeck, filename string) []byte {\n\timg, err := getImage(sd, filename)\n\tif err != nil {\n\t\tpanic(err)\n\t\treturn nil\n\t}\n\treturn img\n}\n\nfunc getGIF(filename string) (*gif.GIF, error) {\n\tf, err := embedFs.Open(filepath.Join(\".embed\", filename))\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer f.Close()\n\tg, err := gif.DecodeAll(f)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn g, nil\n}\n\nfunc mustGetGIF(filename string) *gif.GIF {\n\timg, err := getGIF(filename)\n\tif err != nil {\n\t\tpanic(err)\n\t\treturn nil\n\t}\n\treturn img\n}\n```\n\n## Design\n\n### Device\n\n`Device` is the lowest-level API that is exposed. A Device allows sending raw data as well as\nproviding some convenience functions, it's main purpose is to provide a base that the `StreamDeck`\nstructure interacts with in order to expose a more user-friendly API.\n\n### StreamDeck\n\n`StreamDeck` provides the user-friendly API that most integrations of this library will use, it\nallows the use of [Views](#view) in order to provide an easy way of setting buttons and handling\npress events.\n\n### View\n\nA `View` is used by a [`StreamDeck`](#streamdeck) to set the images for all buttons, a View may optionally\noverride the Stream Deck's default button press handler in order to provide a different API for\nhandling button presses.\n\n###### Example (refer to [`view/buttons.go`](view/buttons.go))\n\n### Button\n\n`Button` is used for buttons with static content, like a solid color or image button. If you need\nto change the content of a static button, you can either just create a new button and update the\n`View`, or implement a custom button that pulls its content from an external source and is capable\nof updating the View itself.\n\n###### Example (refer to [`button/button.go`](button/button.go))\n\n### Button (Animated)\n\n`Animated` is an addon to the `Button` interface that allows a button to determine when it wants to\nupdate itself.  A common example of this would be displaying a GIF which from my knowledge the\nStream Deck does not natively support, meaning we need to wait the time required for each frame and\nkeep updating the image displayed on the Stream Deck. This interface could also be useful for\ndisplaying dynamic content like Spotify Album art for example.\n\n###### Example (refer to [`button/animated.go`](button/animated.go))\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewpi%2Fstreamdeck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatthewpi%2Fstreamdeck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewpi%2Fstreamdeck/lists"}