Open9
StreamDeckアプリ
アプリをつくる
これを追加するにはmanifest.jsonでActionsを追加する
{
"Name": "volumio-controller",
"Version": "0.1.0.0",
"Author": "ebina4yaka",
"Actions": [
{
"Name": "Playback",
"UUID": "com.ebina4yaka.volumio-controller.playback",
"Icon": "imgs/actions/player/play_pause",
"Tooltip": "Displays a count, which increments by one on press.",
"PropertyInspectorPath": "ui/increment-counter.html",
"Controllers": ["Keypad"],
"States": [
{
"Image": "imgs/actions/counter/key",
"TitleAlignment": "middle"
}
]
},
{
"Name": "Preview",
"UUID": "com.ebina4yaka.volumio-controller.previous",
"Icon": "imgs/actions/player/skip_previous",
"Tooltip": "Displays a count, which increments by one on press.",
"PropertyInspectorPath": "ui/increment-counter.html",
"Controllers": ["Keypad"],
"States": [
{
"Image": "imgs/actions/counter/key",
"TitleAlignment": "middle"
}
]
},
{
"Name": "Next",
"UUID": "com.ebina4yaka.volumio-controller.next",
"Icon": "imgs/actions/player/skip_next",
"Tooltip": "Displays a count, which increments by one on press.",
"PropertyInspectorPath": "ui/increment-counter.html",
"Controllers": ["Keypad"],
"States": [
{
"Image": "imgs/actions/counter/key",
"TitleAlignment": "middle"
}
]
}
],
"Category": "volumio-controller",
"CategoryIcon": "imgs/plugin/category-icon",
"CodePath": "bin/plugin.js",
"Description": "its volumio contrall app",
"Icon": "imgs/plugin/marketplace",
"SDKVersion": 2,
"Software": {
"MinimumVersion": "6.4"
},
"OS": [
{
"Platform": "mac",
"MinimumVersion": "10.15"
},
{
"Platform": "windows",
"MinimumVersion": "10"
}
],
"Nodejs": {
"Version": "20",
"Debug": "enabled"
},
"UUID": "com.ebina4yaka.volumio-controller"
}
TooltipとPropertyInspectorPathはサンプルのまま(リリースするならちゃんと書いたほうが良さそう)
PropertyInspectorPathはhtmlファイルで定義
以下の設定画面のUI(サンプルのカウンターアプリのもの)
設定がいらないなら未指定でも動く
<!DOCTYPE html>
<html>
<head lang="en">
<title>Increment Counter Settings</title>
<meta charset="utf-8" />
<script src="https://sdpi-components.dev/releases/v3/sdpi-components.js"></script>
</head>
<body>
<!--
Learn more about property inspector components at https://sdpi-components.dev/docs/components
-->
<sdpi-item label="Increment By">
<sdpi-range setting="incrementBy" min="1" max="5" step="1" default="1" showlabels></sdpi-range>
</sdpi-item>
</body>
</html>
実装はsrc/actions/**.tsに書く
import {action, KeyDownEvent, SingletonAction, WillAppearEvent} from "@elgato/streamdeck";
@action({ UUID: "com.ebina4yaka.volumio-controller.playback" })
export class PlaybackToggle extends SingletonAction<CounterSettings> {
/**
* The {@link SingletonAction.onWillAppear} event is useful for setting the visual representation of an action when it becomes visible. This could be due to the Stream Deck first
* starting up, or the user navigating between pages / folders etc.. There is also an inverse of this event in the form of {@link streamDeck.client.onWillDisappear}. In this example,
* we're setting the title to the "count" that is incremented in {@link IncrementCounter.onKeyDown}.
*/
override onWillAppear(ev: WillAppearEvent<CounterSettings>): void | Promise<void> {
return ev.action.setTitle(`${ev.payload.settings.count ?? 0}`);
}
/**
* Listens for the {@link SingletonAction.onKeyDown} event which is emitted by Stream Deck when an action is pressed. Stream Deck provides various events for tracking interaction
* with devices including key down/up, dial rotations, and device connectivity, etc. When triggered, {@link ev} object contains information about the event including any payloads
* and action information where applicable. In this example, our action will display a counter that increments by one each press. We track the current count on the action's persisted
* settings using `setSettings` and `getSettings`.
*/
override async onKeyDown(ev: KeyDownEvent<CounterSettings>): Promise<void> {
const { settings } = ev.payload;
settings.incrementBy ??= 1;
settings.count = (settings.count ?? 0) + settings.incrementBy;
await ev.action.setSettings(settings);
await ev.action.setTitle(`${settings.count}`);
}
}
/**
* Settings for {@link PlaybackToggle}.
*/
type CounterSettings = {
count?: number;
incrementBy?: number;
};
voluimoのRESTAPIを叩く
import {
type KeyDownEvent,
SingletonAction,
type WillAppearEvent,
action,
} from "@elgato/streamdeck";
@action({ UUID: "com.ebina4yaka.volumio-controller.playback" })
export class PlaybackToggle extends SingletonAction {
override onWillAppear(ev: WillAppearEvent): void | Promise<void> {
return ev.action.setTitle("Toggle");
}
override async onKeyDown(ev: KeyDownEvent): Promise<void> {
const res = await fetch(
"http://firefly.local/api/v1/commands/?cmd=toggle",
{
method: "GET",
headers: {
"Content-Type": "application/json",
},
},
);
await ev.action.setTitle(res.ok ? "Success" : "Failed");
}
}
フォルダ構成
├── com.ebina4yaka.volumio-controller.sdPlugin
│ ├── imgs
│ │ ├── actions
│ │ │ └── player
│ │ │ ├── play_pause.png
│ │ │ ├── skip_next.png
│ │ │ └── skip_previous.png
│ │ └── plugin
│ │ ├── category-icon.png
│ │ ├── category-icon@2x.png
│ │ ├── marketplace.png
│ │ └── marketplace@2x.png
│ ├── manifest.json
│ └── ui
│ └── increment-counter.html
├── package-lock.json
├── package.json
├── rollup.config.mjs
├── src
│ ├── actions
│ │ ├── playback-next.ts
│ │ ├── playback-previous.ts
│ │ └── playback-toggle.ts
│ └── plugin.ts
└── tsconfig.json
plugin.tsで使うアクションを読み込む
import streamDeck, { LogLevel } from "@elgato/streamdeck";
import { PlaybackNext } from "./actions/playback-next";
import { PlaybackPrevious } from "./actions/playback-previous";
import { PlaybackToggle } from "./actions/playback-toggle";
// We can enable "trace" logging so that all messages between the Stream Deck, and the plugin are recorded. When storing sensitive information
streamDeck.logger.setLevel(LogLevel.TRACE);
// Register the increment action.
streamDeck.actions.registerAction(new PlaybackToggle());
streamDeck.actions.registerAction(new PlaybackPrevious());
streamDeck.actions.registerAction(new PlaybackNext());
// Finally, connect to the Stream Deck.
streamDeck.connect();
ボタンアイコンに任意の画像を設定することもできるので再生中の曲のジャケット表示もできそう
import { action, KeyDownEvent, SingletonAction } from "@elgato/streamdeck";
/**
* Example action that updates the key action image from a data URL on key press.
*/
@action({ UUID: "com.elgato.hello-world.increment" })
export class IncrementCounter extends SingletonAction {
/**
* Occurs when the user presses the key action.
*/
override onKeyDown(ev: KeyDownEvent) {
ev.action.setImage(
// base64 data URL
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAIAAADajyQQAAAFF2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgeG1wOkNyZWF0ZURhdGU9IjIwMjQtMDgtMTNUMTU6MDA6MTUtMDQwMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjQtMDgtMTNUMTU6MDE6NTMtMDQ6MDAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjQtMDgtMTNUMTU6MDE6NTMtMDQ6MDAiCiAgIHBob3Rvc2hvcDpEYXRlQ3JlYXRlZD0iMjAyNC0wOC0xM1QxNTowMDoxNS0wNDAwIgogICBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIgogICBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiCiAgIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSI3MiIKICAgZXhpZjpQaXhlbFlEaW1lbnNpb249IjcyIgogICBleGlmOkNvbG9yU3BhY2U9IjEiCiAgIHRpZmY6SW1hZ2VXaWR0aD0iNzIiCiAgIHRpZmY6SW1hZ2VMZW5ndGg9IjcyIgogICB0aWZmOlJlc29sdXRpb25Vbml0PSIyIgogICB0aWZmOlhSZXNvbHV0aW9uPSIzMDAvMSIKICAgdGlmZjpZUmVzb2x1dGlvbj0iMzAwLzEiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJwcm9kdWNlZCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWZmaW5pdHkgRGVzaWduZXIgMiAyLjUuMyIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNC0wOC0xM1QxNTowMTo1My0wNDowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+xLBe4AAAAYFpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAACiRdZHLS0JBFIc/tUhKK6pFixYS1sqiB0htgpSwQELMIKuN3nwEPi73KiFtg7ZCQdSm16L+gtoGrYOgKIJo7bqoTcXt3AyMyBnOOd/8Zs5h5gxYIxklqzcMQTZX0MIBn2shuuhqqmDHSYdYa0zR1clQKEjd8XaHxYw3A2at+uf+HS0rCV0Bi114QlG1gvC0cHCtoJq8LdylpGMrwqfCHk0uKHxr6vEqV0xOVfnDZC0S9oO1XdiV+sXxX6yktaywvBx3NlNUfu5jvsSRyM3PSewV60EnTAAfLmaYwo+XYcbFexlghEFZUSd/6Dt/lrzkKuJVSmiskiJNAY+oRamekJgUPSEzQ8ns/9++6snRkWp1hw8anwzjpQ+atuCzbBjvh4bxeQS2R7jI1fLzBzD2Knq5prn3oW0Dzi5rWnwHzjeh+0GNabFvySZmTSbh+QScUei8hualas9+9jm+h8i6fNUV7O5Bv5xvW/4CDa5nvRjbKwoAAAAJcEhZcwAALiMAAC4jAXilP3YAAABvSURBVGiB7c8BDcAgAMAwwBzK0M1VPM+eVsE279njj9bXAW8xVmOsxliNsRpjNcZqjNUYqzFWY6zGWI2xGmM1xmqM1RirMVZjrMZYjbEaYzXGaozVGKsxVmOsxliNsRpjNcZqjNUYqzFWY6zGWM0D2SQCW/zbGkwAAAAASUVORK5CYII=",
);
}
}