iobroker.volumio
Version:
Volumio Adapter for ioBroker - Control Volumio music players via WebSocket or REST API
846 lines (845 loc) • 29.5 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var utils = __toESM(require("@iobroker/adapter-core"));
var import_axios = __toESM(require("axios"));
var import_body_parser = __toESM(require("body-parser"));
var import_express = __toESM(require("express"));
var os = __toESM(require("os"));
var import_volumioClientFactory = require("./lib/volumioClientFactory");
class Volumio extends utils.Adapter {
volumioClient = null;
axiosInstance = null;
// Only for push notification endpoints (deprecated)
checkConnectionInterval = null;
httpServer;
httpServerInstance;
constructor(options = {}) {
super({
...options,
name: "volumio"
});
this.on("ready", this.onReady.bind(this));
this.on("stateChange", this.onStateChange.bind(this));
this.on("unload", this.onUnload.bind(this));
this.httpServer = (0, import_express.default)();
this.httpServer.use(import_body_parser.default.urlencoded({ extended: false }));
this.httpServer.use(import_body_parser.default.json());
}
/**
* Get local IP address for push notifications
*/
getLocalIp() {
const interfaces = os.networkInterfaces();
for (const name of Object.keys(interfaces)) {
const iface = interfaces[name];
if (iface) {
for (const alias of iface) {
if (alias.family === "IPv4" && !alias.internal) {
return alias.address;
}
}
}
}
return "127.0.0.1";
}
/**
* Handle state changes from Volumio client
*
* @param state
*/
handleStateChange(state) {
this.log.debug(`State change received: ${JSON.stringify(state)}`);
this.updatePlayerState(state);
}
/**
* Handle connection state changes from Volumio client
*
* @param connected
*/
async handleConnectionChange(connected) {
this.log.info(
`Connection to Volumio ${connected ? "established" : "lost"}`
);
await this.setStateAsync("info.connection", connected, true);
}
/**
* Connect to Volumio instance
*/
async connectToVolumio() {
var _a;
this.log.debug("Connecting to Volumio ...");
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.connect());
this.log.info("Successfully connected to Volumio");
return true;
} catch (error) {
this.log.error(`Failed to connect to Volumio: ${error}`);
return false;
}
}
/**
* Is called when databases are connected and adapter received configuration.
*/
async onReady() {
const apiMode = this.config.apiMode || "websocket";
const port = 3e3;
this.log.info(
`Initializing Volumio client in ${apiMode.toUpperCase()} mode (host: ${this.config.host || "volumio.local"}:${port})`
);
this.volumioClient = import_volumioClientFactory.VolumioClientFactory.create({
apiMode,
host: this.config.host || "volumio.local",
port,
pollInterval: (this.config.pollInterval || 2) * 1e3,
// Convert to ms
reconnectAttempts: this.config.reconnectAttempts || 5,
reconnectDelay: (this.config.reconnectDelay || 2) * 1e3,
// Convert to ms
logger: this.log
// Pass ioBroker logger to client
});
if (apiMode === "rest" && this.config.subscribeToStateChanges) {
this.axiosInstance = import_axios.default.create({
baseURL: `http://${this.config.host}/api/v1/`,
timeout: 5e3
});
}
this.volumioClient.onStateChange(this.handleStateChange.bind(this));
this.volumioClient.onConnectionChange(
this.handleConnectionChange.bind(this)
);
await this.setObjectNotExistsAsync("info.connection", {
type: "state",
common: {
role: "indicator.connected",
name: "Connection state to Volumio instance",
type: "boolean",
read: true,
write: false,
def: false
},
native: {}
});
await this.setStateAsync("info.connection", false, true);
this.subscribeStates("*");
const connectionSuccess = await this.connectToVolumio();
if (this.config.checkConnection) {
let interval = this.config.checkConnectionInterval;
if (!interval || !isNumber(interval)) {
this.log.error(
`Invalid connection check interval setting. Will be set to 60s`
);
interval = 60;
}
this.checkConnectionInterval = setInterval(
this.checkConnection,
interval * 1e3,
this
);
}
if (connectionSuccess) {
this.getSystemInfo();
this.getPlayerState();
}
if (this.config.subscribeToStateChanges && this.config.subscriptionPort && connectionSuccess) {
this.log.debug(
`Starting server on ${this.config.subscriptionPort} for subscription mode ...`
);
try {
this.httpServerInstance = this.httpServer.listen(this.config.subscriptionPort).on("error", (error) => {
if (error.code === "EADDRINUSE") {
this.log.error(
`Port ${this.config.subscriptionPort} is already in use. Please choose another one. Subscription mode will not be available.`
);
this.config.subscribeToStateChanges = false;
} else {
this.log.error(
`Starting server on ${this.config.subscriptionPort} for subscription mode failed: ${error}`
);
}
});
this.log.debug(
`Server is listening on ${this.getLocalIp()}:${this.config.subscriptionPort}`
);
this.subscribeToVolumioNotifications();
} catch (error) {
this.log.error(
`Starting server on ${this.config.subscriptionPort} for subscription mode failed: ${error}. Subscription mode will not be available.`
);
this.config.subscribeToStateChanges = false;
}
} else if (this.config.subscribeToStateChanges && !this.config.subscriptionPort) {
this.log.error(
"Subscription mode is activated, but port is not configured."
);
} else if (!this.config.subscribeToStateChanges && connectionSuccess) {
this.unsubscribeFromVolumioNotifications();
}
this.httpServer.post("/volumiostatus", (req, res) => {
this.onVolumioStateChange(req.body);
res.sendStatus(200);
});
}
/**
* Is called when adapter shuts down - callback has to be called under any circumstances!
*
* @param callback
*/
async onUnload(callback) {
try {
if (this.volumioClient) {
await this.volumioClient.disconnect();
this.volumioClient = null;
}
if (this.config.subscribeToStateChanges && this.config.apiMode === "rest") {
this.unsubscribeFromVolumioNotifications();
}
if (this.checkConnectionInterval) {
clearInterval(this.checkConnectionInterval);
this.checkConnectionInterval = null;
}
if (this.httpServerInstance) {
this.httpServerInstance.close();
}
callback();
} catch (_e) {
callback();
}
}
// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
// /**
// * Is called if a subscribed object changes
// */
// private onObjectChange(id: string, obj: ioBroker.Object | null | undefined): void {
// if (obj) {
// // The object was changed
// this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);
// } else {
// // The object was deleted
// this.log.info(`object ${id} deleted`);
// }
// }
/**
* Is called if a subscribed state changes
*
* @param id
* @param state
*/
onStateChange(id, state) {
if (!state) {
this.log.info(`state ${id} deleted`);
return;
}
if (state.ack) {
this.log.silly(
`State change of ${id} to "${state.val}" was already acknowledged. No need for further actions`
);
return;
}
this.log.debug(`state ${id} changed to ${state == null ? void 0 : state.val}`);
const stateId = id.replace(new RegExp(`^volumio.\\d+\\.`), "");
switch (stateId) {
case "getPlaybackInfo":
this.getPlayerState();
break;
case "player.mute":
this.volumeMute();
break;
case "player.unmute":
this.volumeUnmute();
break;
case "player.next":
this.nextTrack();
break;
case "player.prev":
this.previousTrack();
break;
case "player.pause":
this.playbackPause();
break;
case "player.play":
this.playbackPlay();
break;
case "player.playN":
this.playbackPlay(state.val);
break;
case "player.stop":
this.playbackStop();
break;
case "player.toggle":
this.playbackToggle();
break;
case "playbackInfo.volume":
case "player.volume":
this.volumeSetTo(state.val);
break;
case "player.volume.down":
this.volumeDown();
break;
case "player.volume.up":
this.volumeUp();
break;
case "queue.clearQueue":
this.clearQueue();
break;
case "queue.repeatTrack":
this.getStateAsync(
"playbackInfo.repeatSingle",
(err, state2) => {
if (state2) {
this.setRepeatTrack(!state2.val);
}
}
);
break;
case "playbackInfo.random":
case "queue.random":
this.setRandomPlayback(state.val);
break;
case "queue.shuffleMode":
if (!isNumber(state.val)) {
this.log.warn(
"queue.shuffleMode state change. Invalid state value passed"
);
break;
}
if (state.val === 0) {
this.setRandomPlayback(false);
} else if (state.val === 1) {
this.setRandomPlayback(true);
} else if (state.val === 2) {
this.log.warn("queue.shuffleMode 2 not implemented yet");
} else {
this.log.warn("Invalid value to queue.shuffleMode passed");
}
break;
case "queue.repeatTrackState":
this.setRepeatTrack(state.val);
break;
}
}
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
// /**
// * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
// * Using this method requires "common.messagebox" property to be set to true in io-package.json
// */
// private onMessage(obj: ioBroker.Message): void {
// if (typeof obj === "object" && obj.message) {
// if (obj.command === "send") {
// // e.g. send email or pushover or whatever
// this.log.info("send command");
// // Send response in callback if required
// if (obj.callback) this.sendTo(obj.from, obj.command, "Message received", obj.callback);
// }
// }
// }
onVolumioStateChange(msg) {
this.log.debug(`State change message received: ${JSON.stringify(msg)}`);
if (!msg || !msg.item) {
this.log.warn(
`Unprocessable state change message received: ${JSON.stringify(msg)}`
);
return;
}
if (msg.item === "state") {
this.updatePlayerState(msg.data);
} else if (msg.item === "queue") {
} else {
this.log.warn(`Unknown state change event: '${msg.data}'`);
}
}
async subscribeToVolumioNotifications() {
var _a;
this.log.debug("Checking subscrition urls ...");
const urls = await this.getPushNotificationUrls();
if (!urls) {
return;
}
this.setStateAsync("info.connection", true, true);
if (urls.includes(`${this.getLocalIp()}:${this.config.subscriptionPort}`)) {
this.log.debug("Already subscribed to volumio push notifications");
return;
}
const data = {
url: `http://${this.getLocalIp()}:${this.config.subscriptionPort}/volumiostatus`
};
(_a = this.axiosInstance) == null ? void 0 : _a.post("pushNotificationUrls", data).then((response) => {
var _a2;
if ((_a2 = response.data) == null ? void 0 : _a2.success) {
this.log.debug(
"Subscription to volumio push notifications successful"
);
} else {
this.log.error(
`Subscription to volumio push notifications failed: ${JSON.stringify(response == null ? void 0 : response.data)}`
);
}
}).catch((err) => {
this.log.error(
`Subscription to volumio push notifications failed: ${err.message}`
);
this.setStateAsync("info.connection", false, true);
});
}
async getPushNotificationUrls() {
var _a;
return JSON.stringify(
await ((_a = this.axiosInstance) == null ? void 0 : _a.get("pushNotificationUrls").then((response) => {
return response.data;
}).catch((err) => {
this.setStateAsync("info.connection", false, true);
this.log.error(
`Error receiving pushNotificationUrls: ${err.message}`
);
return null;
}))
);
}
async unsubscribeFromVolumioNotifications() {
var _a;
this.log.debug("Unsubscribing from volumio push notifications ...");
const urls = await this.getPushNotificationUrls();
if (!urls) {
return;
}
if (!urls.includes(`${this.getLocalIp()}:${this.config.subscriptionPort}`)) {
this.log.debug("Subscription was not active. No need to unsubscribe");
return;
}
const data = {
url: `http://${this.getLocalIp()}:${this.config.subscriptionPort}/volumiostatus`
};
(_a = this.axiosInstance) == null ? void 0 : _a.delete("pushNotificationUrls", data).then((response) => {
var _a2;
if ((_a2 = response.data) == null ? void 0 : _a2.success) {
this.log.debug(
"Unsubscription from volumio push notifications successful"
);
} else {
this.log.error(
`Unsubscription from volumio push notifications failed: ${JSON.stringify(response == null ? void 0 : response.data)}`
);
}
}).catch((err) => {
this.log.error(
`Unsubscription from volumio push notifications failed: ${err.message}`
);
this.setStateAsync("info.connection", false, true);
});
}
async pingVolumio() {
var _a;
this.log.debug("Pinging volumio ...");
try {
const result = await ((_a = this.volumioClient) == null ? void 0 : _a.ping());
if (result) {
this.log.debug("Volumio ping success");
this.setState("info.connection", true, true);
return true;
}
this.setState("info.connection", false, true);
return false;
} catch (error) {
this.log.error(
`Connection to Volumio host (${this.config.host}) failed: ${error}`
);
this.setState("info.connection", false, true);
return false;
}
}
checkConnection(context) {
context.log.debug("Checking connection to Volumio ...");
if (context.config.subscribeToStateChanges) {
context.subscribeToVolumioNotifications();
} else {
context.pingVolumio();
}
}
async getSystemInfo() {
var _a;
try {
const info = await ((_a = this.volumioClient) == null ? void 0 : _a.getSystemInfo());
this.log.debug(`getSystemInfo response: ${JSON.stringify(info)}`);
if (info) {
this.updateSystemInfo(info);
}
} catch (error) {
this.log.error(`Error getting system info: ${error}`);
}
}
async getPlayerState() {
var _a;
try {
const state = await ((_a = this.volumioClient) == null ? void 0 : _a.getState());
this.log.debug(`getState response: ${JSON.stringify(state)}`);
if (state) {
this.updatePlayerState(state);
}
} catch (error) {
this.log.error(`Error getting player state: ${error}`);
}
}
updatePlayerState(state) {
if (state.status !== void 0) {
this.setStateAsync("playbackInfo.status", state.status, true);
}
if (state.position !== void 0) {
this.setStateAsync("playbackInfo.position", String(state.position), true);
}
if (state.title !== void 0 && state.track !== void 0) {
if (state.title !== state.track) {
this.log.warn(
`Title and track attibutes are both set but differ. Title will be set to ${state.title}`
);
this.setStateAsync("playbackInfo.title", state.title, true);
}
this.setStateAsync("playbackInfo.title", state.title, true);
} else if (state.title !== void 0) {
this.setStateAsync("playbackInfo.title", state.title, true);
} else if (state.track !== void 0) {
this.setStateAsync("playbackInfo.title", state.track, true);
}
if (state.artist !== void 0) {
this.setStateAsync("playbackInfo.artist", state.artist, true);
}
if (state.album !== void 0) {
this.setStateAsync("playbackInfo.album", state.album, true);
}
if (state.albumart !== void 0) {
this.setStateAsync("playbackInfo.albumart", state.albumart, true);
}
if (state.uri !== void 0) {
this.setStateAsync("playbackInfo.uri", state.uri, true);
}
if (state.trackType !== void 0) {
this.setStateAsync("playbackInfo.trackType", state.trackType, true);
}
if (state.codec !== void 0) {
this.setStateAsync("playbackInfo.codec", state.codec, true);
}
if (state.seek !== void 0) {
const seek = typeof state.seek === "string" ? parseInt(state.seek, 10) : state.seek;
this.setStateAsync("playbackInfo.seek", seek, true);
}
if (state.duration !== void 0) {
const duration = typeof state.duration === "string" ? parseInt(state.duration, 10) : state.duration;
this.setStateAsync("playbackInfo.duration", duration, true);
}
if (state.samplerate !== void 0) {
this.setStateAsync("playbackInfo.samplerate", state.samplerate, true);
}
if (state.bitdepth !== void 0) {
this.setStateAsync("playbackInfo.bitdepth", state.bitdepth, true);
}
if (state.channels !== void 0) {
const channels = typeof state.channels === "string" ? parseInt(state.channels, 10) : state.channels;
this.setStateAsync("playbackInfo.channels", channels, true);
}
if (state.random !== void 0) {
this.setStateAsync("playbackInfo.random", state.random, true);
}
if (state.repeat !== void 0) {
this.setStateAsync("playbackInfo.repeat", state.repeat, true);
}
if (state.repeatSingle !== void 0) {
this.setStateAsync("playbackInfo.repeatSingle", state.repeatSingle, true);
}
if (state.consume !== void 0) {
this.setStateAsync("playbackInfo.consume", state.consume, true);
}
if (state.volume !== void 0) {
const volume = typeof state.volume === "string" ? parseInt(state.volume, 10) : state.volume;
this.setStateAsync("playbackInfo.volume", volume, true);
this.setStateAsync("player.volume", volume, true);
}
if (state.dbVolume !== void 0) {
const dbVolume = typeof state.dbVolume === "string" ? parseFloat(state.dbVolume) : state.dbVolume;
this.setStateAsync("playbackInfo.dbVolume", dbVolume, true);
}
if (state.disableVolumeControl !== void 0) {
this.setStateAsync(
"playbackInfo.disableVolumeControl",
state.disableVolumeControl,
true
);
}
if (state.mute !== void 0) {
this.setStateAsync("playbackInfo.mute", state.mute, true);
this.setStateAsync("player.muted", state.mute, true);
}
if (state.stream !== void 0) {
const stream = typeof state.stream === "boolean" ? String(state.stream) : state.stream || "";
this.setStateAsync("playbackInfo.stream", stream, true);
}
if (state.updatedb !== void 0) {
this.setStateAsync("playbackInfo.updatedb", state.updatedb, true);
}
if (state.volatile !== void 0) {
this.setStateAsync("playbackInfo.volatile", state.volatile, true);
}
if (state.service !== void 0) {
this.setStateAsync("playbackInfo.service", state.service, true);
}
}
updateSystemInfo(systemInfo) {
if (systemInfo.id !== void 0) {
this.setStateAsync("info.id", systemInfo.id, true);
}
if (systemInfo.host !== void 0) {
this.setStateAsync("info.host", systemInfo.host, true);
}
if (systemInfo.name !== void 0) {
this.setStateAsync("info.name", systemInfo.name, true);
}
if (systemInfo.type !== void 0) {
this.setStateAsync("info.type", systemInfo.type, true);
}
if (systemInfo.serviceName !== void 0) {
this.setStateAsync("info.serviceName", systemInfo.serviceName, true);
}
if (systemInfo.systemversion !== void 0) {
this.setStateAsync("info.systemversion", systemInfo.systemversion, true);
}
if (systemInfo.builddate !== void 0) {
this.setStateAsync("info.builddate", systemInfo.builddate, true);
}
if (systemInfo.variant !== void 0) {
this.setStateAsync("info.variant", systemInfo.variant, true);
}
if (systemInfo.hardware !== void 0) {
this.setStateAsync("info.hardware", systemInfo.hardware, true);
}
if (systemInfo.isPremiumDevice !== void 0) {
this.setStateAsync(
"info.isPremiumDevice",
systemInfo.isPremiumDevice,
true
);
}
if (systemInfo.isVolumioProduct !== void 0) {
this.setStateAsync(
"info.isVolumioProduct",
systemInfo.isVolumioProduct,
true
);
}
}
async nextTrack() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.next());
this.log.debug("Next track");
} catch (error) {
this.log.error(`Error playing next track: ${error}`);
}
}
async previousTrack() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.previous());
this.log.debug("Previous track");
} catch (error) {
this.log.error(`Error playing previous track: ${error}`);
}
}
async volumeMute() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.mute());
this.log.debug("Volume muted");
this.setStateAsync("playbackInfo.mute", true, true);
this.setStateAsync("player.muted", true, true);
} catch (error) {
this.log.error(`Error muting volume: ${error}`);
}
}
async volumeUnmute() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.unmute());
this.log.debug("Volume unmuted");
this.setStateAsync("playbackInfo.mute", false, true);
this.setStateAsync("player.muted", false, true);
} catch (error) {
this.log.error(`Error unmuting volume: ${error}`);
}
}
async playbackPause() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.pause());
this.log.debug("Playback paused");
this.setStateAsync("playbackInfo.status", "pause", true);
} catch (error) {
this.log.error(`Error pausing playback: ${error}`);
}
}
async playbackPlay(n) {
var _a;
if (n && !isNumber(n)) {
this.log.warn("player.playN state change. Invalid state value passed");
return;
}
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.play(n));
this.log.debug("Playback started");
this.setStateAsync("playbackInfo.status", "play", true);
} catch (error) {
this.log.error(`Error starting playback: ${error}`);
}
}
async playbackStop() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.stop());
this.log.debug("Playback stopped");
this.setStateAsync("playbackInfo.status", "stop", true);
} catch (error) {
this.log.error(`Error stopping playback: ${error}`);
}
}
async playbackToggle() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.toggle());
this.log.debug("Playback toggled");
this.getState("playbackInfo.status", (_err, state) => {
if ((state == null ? void 0 : state.val) === "play") {
this.setStateAsync("playbackInfo.status", "pause", true);
} else if ((state == null ? void 0 : state.val) === "pause" || (state == null ? void 0 : state.val) === "stop") {
this.setStateAsync("playbackInfo.status", "play", true);
}
});
} catch (error) {
this.log.error(`Error toggling playback: ${error}`);
}
}
async volumeSetTo(value) {
var _a;
if (!isNumber(value)) {
this.log.warn("player.volume state change. Invalid state value passed");
return;
}
const volumeValue = typeof value === "string" ? parseInt(value, 10) : value;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.setVolume(volumeValue));
this.log.debug(`Volume set to ${volumeValue}`);
this.setStateAsync("playbackInfo.volume", volumeValue, true);
this.setStateAsync("player.volume", volumeValue, true);
} catch (error) {
this.log.error(`Error setting volume: ${error}`);
}
}
async volumeUp() {
let volumeSteps = this.config.volumeSteps;
if (!volumeSteps || volumeSteps > 100 || volumeSteps < 0) {
this.log.warn(
`Invalid volume step setting. volumeSteps will be set to 10`
);
volumeSteps = 10;
}
try {
const state = await this.getStateAsync("playbackInfo.volume");
const currentVolume = (state == null ? void 0 : state.val) || 0;
const newVolumeValue = currentVolume + volumeSteps > 100 ? 100 : currentVolume + volumeSteps;
this.log.debug(
`Increasing volume from ${currentVolume} to ${newVolumeValue}`
);
await this.volumeSetTo(newVolumeValue);
} catch (error) {
this.log.error(`Error increasing volume: ${error}`);
}
}
async volumeDown() {
let volumeSteps = this.config.volumeSteps;
if (!volumeSteps || volumeSteps > 100 || volumeSteps < 0) {
this.log.warn(
`Invalid volume step setting. volumeSteps will be set to 10`
);
volumeSteps = 10;
}
try {
const state = await this.getStateAsync("playbackInfo.volume");
const currentVolume = (state == null ? void 0 : state.val) || 0;
const newVolumeValue = currentVolume - volumeSteps < 0 ? 0 : currentVolume - volumeSteps;
this.log.debug(
`Decreasing volume from ${currentVolume} to ${newVolumeValue}`
);
await this.volumeSetTo(newVolumeValue);
} catch (error) {
this.log.error(`Error decreasing volume: ${error}`);
}
}
async setRandomPlayback(random) {
var _a;
if (typeof random !== "boolean") {
this.log.warn("player.random state change. Invalid state value passed");
return;
}
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.setRandom(random));
this.log.debug(`Random play set to ${random}`);
this.setStateAsync("playbackInfo.random", random, true);
this.setStateAsync("queue.shuffleMode", random ? 1 : 0, true);
} catch (error) {
this.log.error(`Error setting random play: ${error}`);
}
}
async clearQueue() {
var _a;
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.clearQueue());
this.log.debug(`Queue cleared`);
} catch (error) {
this.log.error(`Error clearing queue: ${error}`);
}
}
async setRepeatTrack(repeat) {
var _a;
if (typeof repeat !== "boolean") {
this.log.warn(
"player.repeatTrackState state change. Invalid state value passed"
);
return;
}
try {
await ((_a = this.volumioClient) == null ? void 0 : _a.setRepeatSingle(repeat));
this.log.debug(`Repeat track set to ${repeat}`);
this.setStateAsync("playbackInfo.repeatSingle", repeat, true);
this.setStateAsync("queue.repeatSingle", repeat ? 1 : 0, true);
} catch (error) {
this.log.error(`Error setting repeat track: ${error}`);
}
}
}
function isNumber(value) {
return value != null && value !== "" && !isNaN(Number(value.toString()));
}
if (require.main !== module) {
module.exports = (options) => new Volumio(options);
} else {
(() => new Volumio())();
}
//# sourceMappingURL=main.js.map