streamdeck-typescript
Version:
This library will help you build elgato stream deck plugins in typescript
239 lines (195 loc) • 9.6 kB
Markdown
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/network/members)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/stargazers)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/watchers)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/graphs/contributors)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/issues)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/issues?q=is%3Aissue+is%3Aclosed)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/pulls)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/pulls?q=is%3Apr+is%3Aclosed)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/compare)
[](https://sonarcloud.io/dashboard?id=XeroxDev_Stream-Deck-TS-SDK)
[](https://www.npmjs.com/package/streamdeck-typescript)
[](https://github.com/XeroxDev/Stream-Deck-TS-SDK/blob/master/LICENSE)
[](https://shields.io)
# Stream Deck TS-SDK
A library that helps you develop plugins for Elgato's Stream Deck.
## Installation
- Install via [`npm`](https://www.npmjs.com/):
```bash
npm install --save streamdeck-typescript
```
## Decorators
This Plugin adds a few decorators for classes and methods.
### Available decorators
- methods
- `` (event)`` - Listens for specified event in the property inspector context and if
triggered, calls method
- Overhands EventData (\*NameOfEvent\*Event; Example: KeyDownEvent, KeyUpEvent, WillAppearEvent)
- `` (event)`` - Listens for specified event in the action context and if triggered, calls method
- Overhands EventData (\*NameOfEvent\*Event; Example: KeyDownEvent, KeyUpEvent, WillAppearEvent)
## Usage
You can see an example in the [example](https://github.com/XeroxDev/Stream-Deck-TS-SDK/tree/master/example) folder
or look through the [Source docs](https://xeroxdev.github.io/Stream-Deck-TS-SDK/)
### Initializing Plugin
Elgato uses 2 different files. The Action file (which handels all actions), and the Property Inspector file (which is
for settings)
#### counter.ts
```typescript
import {StreamDeckPluginHandler} from '../src';
import {CounterAction} from './actions/counter.action';
export class Counter extends StreamDeckPluginHandler {
constructor() {
super();
new CounterAction(this, 'fun.shiro.counter.action');
}
}
new Counter();
```
#### plugin.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test Plugin</title>
<meta charset="utf-8">
<script src="dist/bundle.js"></script>
</head>
<body>
</body>
</html>
```
Here you can see. After the build you have only one file (bundle.js in this case) and this gets loaded.
#### counter-pi.ts
```typescript
import {DidReceiveSettingsEvent, SDOnPiEvent, StreamDeckPropertyInspectorHandler} from '../src';
import {SettingsInterface} from './interfaces/settings.interface';
class CounterPi extends StreamDeckPropertyInspectorHandler {
private count: HTMLInputElement;
private stepsCount: HTMLInputElement;
constructor() {
super();
}
('documentLoaded')
onDocumentReady() {
this.count = document.getElementById('count') as HTMLInputElement;
this.count.addEventListener('keyup', () =>
this.settingsManager.setContextSettingsAttributes(
this.actionInfo.context, {count: this.count.valueAsNumber}, 500));
this.stepsCount = document.getElementById('steps') as HTMLInputElement;
this.stepsCount.addEventListener('keyup', () =>
this.settingsManager.setContextSettingsAttributes(
this.actionInfo.context, {steps: this.stepsCount.valueAsNumber}, 500));
const settings = this.settingsManager.getContextSettings<SettingsInterface>(this.actionInfo.context);
this.count.value = (settings?.count ?? 0).toString();
this.stepsCount.value = (settings?.steps ?? 1).toString();
}
('didReceiveSettings')
private onSettingsReceived({payload: {settings}}: DidReceiveSettingsEvent<SettingsInterface>) {
if (Object.keys(settings).length <= 0)
return;
this.count.value = settings.count.toString() ?? 0;
this.stepsCount.value = settings.steps.toString() ?? 1;
}
}
new CounterPi();
```
#### property-inspector.html
```html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test Plugin Inspector</title>
<meta charset="utf-8">
<link rel="stylesheet" href="sdpi.css">
<script src="dist/bundle-pi.js"></script>
</head>
<body>
<div class="sdpi-wrapper" id="mainSettings">
<div class="sdpi-item">
<div class="sdpi-item-label">Count</div>
<input class="sdpi-item-value" type="number" id="count" value="0">
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Steps</div>
<input class="sdpi-item-value" type="number" id="steps" value="1">
</div>
</div>
</body>
</html>
```
#### counter.action.ts
```typescript
import {
DidReceiveSettingsEvent,
KeyDownEvent,
KeyUpEvent,
SDOnActionEvent,
StreamDeckAction,
WillAppearEvent
} from '../../src';
import {Counter} from '../counter';
import {SettingsInterface} from '../interfaces/settings.interface';
export class CounterAction extends StreamDeckAction<Counter, CounterAction> {
private keyUpTimer: any;
constructor(private plugin: Counter, private actionName: string) {
super(plugin, actionName);
}
('willAppear')
private onAppear({context, payload: {settings}}: WillAppearEvent<SettingsInterface>) {
this.plugin.setTitle((settings.count ?? 0).toString(), context);
}
('keyUp')
private onKeyUp({context, payload: {settings}}: KeyUpEvent<SettingsInterface>) {
clearTimeout(this.keyUpTimer);
const steps = settings.steps ?? 1;
const count = (settings.count ?? 0) + steps;
this.plugin.setTitle(count.toString(), context);
this.plugin.setSettings<SettingsInterface>({steps, count}, context);
}
('keyDown')
private onKeyDown({context, payload: {settings}}: KeyDownEvent<SettingsInterface>) {
this.keyUpTimer = setTimeout(() => {
const steps = settings.steps ?? 1;
this.plugin.setSettings<SettingsInterface>(
{
steps,
count: steps * -1
}, context
);
this.plugin.setTitle('0', context);
}, 2000);
}
('didReceiveSettings')
private onSettings({context, payload: {settings}}: DidReceiveSettingsEvent<SettingsInterface>) {
this.plugin.setTitle(settings.count.toString() ?? 0, context);
}
}
```
#### settings.interface.ts
```typescript
export interface SettingsInterface {
count: number,
steps: number
}
```
## Building the Plugin
I would suggest you to do it like in the example with browserify, terser, tsify, typescript and for development watchify
See [**package.json**](https://github.com/XeroxDev/Stream-Deck-TS-SDK/blob/master/package.json)
and [**tsconfig.json**](https://github.com/XeroxDev/Stream-Deck-TS-SDK/blob/master/tsconfig.json)
```json
{
"scripts": {
"build": "tsc -p tsconfig.json",
"build-example": "browserify -p tsify example/counter-pi.ts | terser -cm --comments false -o dist/bundle-pi.js && browserify -p tsify example/counter.ts | terser -cm --comments false -o dist/bundle.js",
"watch": "start watchify --debug -p tsify example/counter.ts -o dist/bundle.js && start watchify --debug -p tsify example/counter-pi.ts -o dist/bundle-pi.js",
"documentation": "typedoc src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
```
## How to contribute?
Just fork the repository and create PR's, but we use
[standard-version](https://github.com/conventional-changelog/standard-version) to optimal release the plugin.
standard-version is following the [conventionalcommits](https://www.conventionalcommits.org) specification which follows
the
[angular commit guidelines](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)