Giter VIP home page Giter VIP logo

deckxstream's Introduction

npm version Linux CI

IMPORTANT: This codebase is no longer actively maintained. The package will continue working, but support and changes are no longer provided. I will continue to make security updates so long as I have a device to use.

deckxstream

deckxstream is a controller application for the Elgato Stream Deck. The application was created to allow Linux usage of a Stream Deck. The application relies heavily on the elgato-stream-deck NPM library. You will need to install udev rules and dependencies for this to install. See below

Features

  • Support for multiple image formats including PNG, SVG, and animated GIF
  • Support for hotkeys and text input (via libxdo bindings), application running (via child_process.spawn)
  • Dynamic buttons where any command/icon/text can be replaced via output from a running application
  • Dynamic pages where the buttons are specified via output of a command
  • Sticky buttons available on any page
  • Data URI support for icons so they don't even need to be on disk
  • Screensaver for full panel animations

Preinstall on Linux

Udev on Linux will not allow access to the Stream Deck initially. Create /etc/udev/rules.d/50-elgato.rules with the contents below and reload with sudo udevadm control --reload-rules. NOTE: This setup assumes you are a member of the input group. Use groups on the command-line to see which groups you belong to substitute accordingly with plugdev or similar. See elgato-stream-deck for more information.

SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE:="660", GROUP="input"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE:="660", GROUP="input"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006c", MODE:="660", GROUP="input"
SUBSYSTEM=="usb", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE:="660", GROUP="input"
KERNEL=="hidraw*", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0060", MODE:="660", GROUP="input"
KERNEL=="hidraw*", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="0063", MODE:="660", GROUP="input"
KERNEL=="hidraw*", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006c", MODE:="660", GROUP="input"
KERNEL=="hidraw*", ATTRS{idVendor}=="0fd9", ATTRS{idProduct}=="006d", MODE:="660", GROUP="input"

NOTE: You may need to use SUBSYSTEMS or KERNEL instead of SUBSYSTEM depending on your kernel. If you see permission errors trying to open a device, use udevadm info -a /dev/<device> to see what you should be using.

xdo.h is also a dependency. You can get this file via pacman -S xdotool on Arch or apt-get install libxdo-dev on Ubuntu/Debian

Installation

$ npm install -g deckxstream

Running

$ deckxstream

Usage: deckxstream [options]

Options:
  -V, --version        output the version number
  -c, --config <file>  Configuration file to use. (default: "$HOME/.deckxstream.json")
  -l, --list           Show all detected Stream Decks and exit
  -i, --init [device]  Output an initial JSON file for the specified device if supplied
  -k, --keys [device]  Outputs the keyIndex values to each button on the specified Stream Deck (or first found) and exits
  -h, --help           display help for command

Configuration

deckxstream requires a configuration file. By default, it will attempt to load .deckxstream.json in the HOME directory.

Example

{
    "deckxstream-version": 1,
    "brightness": 70,
    "device": "somename",
    "screensaver": {
        "animation": "tumbler.gif",
        "brightness": 10,
        "timeoutMinutes": 20 
    },
    "sticky": [
        {
            "keyIndex": 0,
            "icon": "/some/dir/home.png",
            "changePage": "default",
            "text": "Home",
            "textSettings": {
                "fillStyle": "blue"
            }
        },
        {
            "keyIndex": 4,
            "icon": "/some/dir/speaker.svg",
            "text": "Mute",
            "command": "amixer set Master toggle"
        }
    ],
    "pages": [
        {
            "pageName": "default",
            "buttons": [
                {
                    "keyIndex": 1,
                    "icon": "/some/dir/retroarch.svg",
                    "changePage": "retroarch"
                },
                {
                    "keyIndex": 3,
                    "dynamic": {
                        "command": "resources/randomButton.js -r",
                        "persistent": true
                    }
                },
                {
                    "keyIndex": 5,
                    "icon": "/some/dir/staticicondyntext.png",
                    "dynamic": {
                        "command": "resources/randomButton.js",
                        "interval": 2000
                    }
                },
                {
                    "keyIndex": 6,
                    "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2NQu1DzHwAFBAJyENnpTwAAAABJRU5ErkJggg=="
                }
                {
                    "keyIndex": 10,
                    "icon": "/some/dir/lockscreen.svg",
                    "sendkey": "super+l"
                },
                {
                    "keyIndex": 13,
                    "icon": "redshift.svg",
                    "changeBrightness": 10,
                    "command": "redshift -x; redshift -O 4000 -b .5"
                },
                {
                    "keyIndex": 14,
                    "icon": "brightness.svg",
                    "changeBrightness": 70,
                    "command": "redshift -x"
                }
            ]
        },
        {
            "pageName": "retroarch",
            "buttons": [
                {
                    "keyIndex": 1,
                    "icon": "/some/dir/retroarch.svg",
                },
                {
                    "keyIndex": 10,
                    "icon": "save.svg",
                    "sendkey": "F2",
                    "text": "Save"
                },
                {
                    "keyIndex": 7,
                    "icon": "plus.svg",
                    "sendkey": "F7"
                },
                {
                    "keyIndex": 12,
                    "icon": "minus.svg",
                    "sendkey": "F6"
                },
                {
                    "keyIndex": 14,
                    "icon": "load.svg",
                    "sendkey": "F4",
                    "text": "Load"
                }
            ]
        },
        {
            "pageName": "dyn",
            "dynamicPage": "resources/randomPage.js -k 15"
        }
    ]
}

Order of Operations

A button can cause multiple actions to occur based on the configuration. The order of them is as follows on a single press:

changeBrightness -> sendkey -> sendtext -> command -> changePage -> startScreensaver

Details

deckxstream-version - Version number for the JSON file schema. Currently only 1.

brightness - Brightness to set to at start of application. Supports 0-100. (Default: 90)

device - The device serial number to use if multiple Stream Decks are in use. (Default: first found)

screensaver - Configuration block for the screensaver (Optional)

Value Required Notes
animation Yes Filename of the GIF to use as a screensaver
brightness No Brightness to change the deck to when screensaver turns on
timeoutMinutes Yes Time in minutes until screensaver kicks in

sticky - Sticky buttons. These buttons are available on EVERY page. If another page tries to load a button in the same location, it will be ignored. Entries follow the button format in an array. (Optional)

pages - Pages for deck. On startup, a default page will be loaded. (Optional)

Value Required Notes
pageName Yes The name for the page. default is loaded on startup. Use changePage to go to a different page.
dynamicPage No (Yes if no buttons) Command to run to generate the page of buttons. Will be run by child_process.spawn when page is switched to. The called application should return {"buttons":[]} with the array filled with buttons. NOTE: Response must be JSON.
buttons No (Yes if not dynamic) Array of buttons to load on the page.

Button Format

Value Required Notes
keyIndex Yes The key to bind to. For example, the standard Stream Deck would have 0-14. Run deckxstream -k to see the numbering for yours.
icon No Either the filename or a Base64 data URI for an image to display in the button. The image will be automatically resized (respecting aspect ratio) to fit.
text No A text label to place at the bottom of the button. If an icon is specified, it will be resized to allow the text to fit.
textSettings No Changes the look of the label text. Use an object with properties for CanvasRenderingContext2D like fillStyle and font.
changePage No On click, change the deck to the named page from the array of pages.
changeBrightness No On click, change the brightness of the deck. Values of 0-100 supported.
command No On click, run the given command using child_process.spawn
sendkey No On click, send the given hotkey. Follows the naming of keys xdotool.
sendtext No On click, send the given string to active window.
startScreensaver No On click, start the screensaver. Value should be true. (Added in 1.0.0)
dynamic No Dynamically sets up the button. Runs a given command to populate any of the other fields in this structure. See the dynamic structure below. NOTE: You CANNOT override keyIndex or dynamic with the results of the command.

Dynamic structure

Value Required Notes
command Yes The command to run via child_process.spawn and listen on standard output. The output must be properly formed JSON. The JSON will overwrite any of the button configuration values until the next output. See below for an example.
persistent No If true, the interval is ignored. Instead, the command is expected to be persistent and continously output JSON whenever a change is wanted. (false by default)
interval No (Yes if not persistent) Time in ms between running the dynamic command. Keep in mind that if the text or icon of the button is changed, this can have an impact on system resources if the timeout is very short.

Example of dynamic overwrite

As an example of dynamic, let's say you have a checkEmail.sh script which opens your mail client and hasEmail.sh which checks to see if you have any new mail.

Given a button config of

{
    "keyIndex": 0,
    "icon": "/dir/mail.png",
    "command": "checkEmail.sh",
    "dynamic": {
        "command": "hasEmail.sh",
        "interval": 60000
    }
}

If hasEmail.sh returns

{
    "icon": "/dir/mailanimated.gif",
    "text": "6 New!"
}

The button will now be

{
    "keyIndex": 0,
    "icon": "/dir/mailanimated.gif",
    "text": "6 New!",
    "command": "checkEmail.sh",
    "dynamic": {
        "command": "hasEmail.sh",
        "interval": 60000
    }
}

If it then returns

{
    "text": "0 New"
}

Then the button becomes

{
    "keyIndex": 0,
    "icon": "/dir/mail.png",
    "text": "0 New",
    "command": "checkEmail.sh",
    "dynamic": {
        "command": "hasEmail.sh",
        "interval": 60000
    }
}

The original configuration is used as the base between runs, not the the results of the previous run.

deckxstream's People

Contributors

secretagentken avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

deckxstream's Issues

Add Twitch prediction support

From Reddit: https://www.reddit.com/r/elgato/comments/lgetjv/prediction_ability_for_stream_deck/?utm_source=share&utm_medium=web2x&context=3

"So as it is right now in order to start a prediction, you have to first type in chat /prediction. Then a new window pops open with a text box asking what you want the prediction to be and two options for people to vote on (customizable of course), then under those boxes is a drop down for how long you want the prediction to last (1m, 2m, 5m, etc.). Finally you click start prediction. My idea would be you could have a single button that could be in the stream deck that already has all the needed information filled out and simply starts the prediction. There would then have to be another 2 buttons programmed to let you pick the outcome winner, but it would be a lot easier than using what twitch has.

For example from a recent stream. Streamer wanted to run a prediction on deku tree ocarina of time, is it a stone or medallion? I had to start the prediction, type out what it was, set the options to stone or medallion, set the time, and then finally run it. Had I not been there, he would have had to stop playing, pause his timer, and type all that out. If I it another mod isn't there, it'd be great to just have. Abutting to press ready to go.

I hope this gives more details

A multi action could be programmed to do it (theoretically), but would be way overcomplicated"

API is now available: https://discuss.dev.twitch.tv/t/announcing-apis-and-eventsub-for-polls-and-predictions/31539

  • Provide a method for performing OAuth with Twitch
  • Provide actions for setting predictions and for confirming winner (may need state so other actions still available, ie. set prediction creates new page for results but other pages still available)

Update project to support modern Ubuntu versions (18.04 and newer)

Currently, this does not build cleanly with all correct dependencies on a clean 18.04, 20.04 nor 22.04 Ubuntu release version.

I'm not an expert in node.js, but it shouldn't be a huge uplift to test and verify that it should work on those environments, and make any dependency version adjustments needed to get it working there.

Oh, and screenshots of the UI on this project's main page would be great!

Add support for reloading the configuration file

I constantly have to kill the process and restart in the terminal when editing the configuration file. I would like some combination of:

  • React to configuration file changes to automatically reload
  • React to a USR1 signal to reload the configuration file and/or restart the application

libvips.so.42: undefined symbol

Describe the bug
Deckxstream will no longer load with the error:

deckxstream/node_modules/sharp/lib/sharp.js:34
  throw new Error(help.join('\n'));
  ^

Error: 
Something went wrong installing the "sharp" module

/usr/lib/libvips.so.42: undefined symbol: rsvg_handle_get_intrinsic_size_in_pixels

Possible solutions:
- Install with verbose logging and look for errors: "npm install --ignore-scripts=false --foreground-scripts --verbose sharp"
- Install for the current linux-x64 runtime: "npm install --platform=linux --arch=x64 sharp"
- Consult the installation documentation: https://sharp.pixelplumbing.com/install
    at Object.<anonymous> (/home/user/.asdf/installs/nodejs/18.14.2/lib/node_modules/deckxstream/node_modules/sharp/lib/sharp.js:34:9)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
    at Module.load (node:internal/modules/cjs/loader:1117:32)
    at Module._load (node:internal/modules/cjs/loader:958:12)
    at Module.require (node:internal/modules/cjs/loader:1141:19)
    at require (node:internal/modules/cjs/helpers:110:18)
    at Object.<anonymous> (/home/user/.asdf/installs/nodejs/18.14.2/lib/node_modules/deckxstream/node_modules/sharp/lib/constructor.js:8:1)
    at Module._compile (node:internal/modules/cjs/loader:1254:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)

Node.js v18.14.2

Specify your environment

  • OS: Arch Linux
  • NodeJS Version: v18.14.2
  • NPM Version: [...]
  • Stream Deck Model: Standard
  • Configuration File: N/A

To Reproduce
Steps to reproduce the behavior:

  1. Install deckxstream on an updated Arch Linux system
  2. Try to launch deckxstream
  3. See error

--

I have tried to reinstall the sharp package as suggested by the error. It seems to install just fine but the error persists. libvips was recently updated to 8.14.1-1 and I wonder if that's part of the problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.