npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

deckxstream

v2.2.2

Published

Elgato Stream Deck controller

Downloads

9

Readme

npm version Linux CI

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.