diff --git a/PAGE.md b/PAGE.md index cde23f3..1686f89 100644 --- a/PAGE.md +++ b/PAGE.md @@ -1,3 +1,5 @@ +## This Requires the OBS Websocket version 5 + # OBS Plugin A proof-of-concept plugin that provides very basic OBS integration. diff --git a/package-lock.json b/package-lock.json index 219b395..6f132e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,10 +7,15 @@ "": { "name": "com.midi-mixer.obs", "version": "0.1.6", + "bundleDependencies": [ + "midi-mixer-plugin", + "obs-websocket-js", + "ws" + ], "license": "ISC", "dependencies": { "midi-mixer-plugin": "^1.0.2", - "obs-websocket-js": "^4.0.2", + "obs-websocket-js": "^5.0.2", "ws": "8.4.0" }, "devDependencies": { @@ -120,6 +125,15 @@ "node": ">=4" } }, + "node_modules/@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==", + "inBundle": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", @@ -1625,6 +1639,12 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "node_modules/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==", + "inBundle": true + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -1650,14 +1670,20 @@ } }, "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "inBundle": true, "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/decamelize": { @@ -2482,7 +2508,8 @@ "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "inBundle": true }, "node_modules/execa": { "version": "5.1.1", @@ -3114,7 +3141,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/ini": { "version": "1.3.8", @@ -3330,7 +3358,8 @@ "node_modules/isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", - "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==" + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "inBundle": true }, "node_modules/issue-parser": { "version": "6.0.0", @@ -4150,6 +4179,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/midi-mixer-plugin/-/midi-mixer-plugin-1.0.2.tgz", "integrity": "sha512-q4K7Ov2oxZlec4if2ZDf10btbU8SIcegBGZ+/m2hIYR6Z+Vix/DPl8a4awYjIEPkC8bejB66/n7wU8kjRcoJHg==", + "inBundle": true, "dependencies": { "eventemitter3": "^4.0.7", "ulid": "^2.3.0" @@ -4217,7 +4247,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "inBundle": true }, "node_modules/natural-compare": { "version": "1.4.0", @@ -6927,6 +6958,11 @@ "safer-buffer": "^2.0.2", "tweetnacl": "~0.14.0" }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, "engines": { "node": ">=0.10.0" } @@ -7274,22 +7310,33 @@ } }, "node_modules/obs-websocket-js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-4.0.2.tgz", - "integrity": "sha512-e+tGp0DQNXSnitc5lfuzEC1dG3VdWy7VLePUVb6aq7bC33Sgjoi695k0eOg4UPTIQI71Z9aJ+yn3nvBX9dQkEg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-5.0.2.tgz", + "integrity": "sha512-4XxWd5abIFOk0HjIHk+X/NwSXuOTPGsNnn7845g0UQZV0T3AtNk+dfp21zSjJVzuN/5oZR3UKjzEqg8pxMndCA==", + "inBundle": true, "dependencies": { - "debug": "^4.1.0", + "@msgpack/msgpack": "^2.7.1", + "crypto-js": "^4.1.1", + "debug": "^4.3.2", + "eventemitter3": "^4.0.7", "isomorphic-ws": "^4.0.1", - "sha.js": "^2.4.9", - "ws": "^7.2.0" + "type-fest": "^2.3.2", + "ws": "^8.2.2" + }, + "engines": { + "node": ">12.0" } }, - "node_modules/obs-websocket-js/node_modules/ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "node_modules/obs-websocket-js/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "inBundle": true, "engines": { - "node": ">=8.3.0" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/once": { @@ -7835,7 +7882,8 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "node_modules/semantic-release": { "version": "18.0.1", @@ -8191,18 +8239,6 @@ "node": ">=8" } }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, "node_modules/signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", @@ -8738,6 +8774,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", + "inBundle": true, "bin": { "ulid": "bin/cli.js" } @@ -8866,6 +8903,7 @@ "version": "8.4.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz", "integrity": "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==", + "inBundle": true, "engines": { "node": ">=10.0.0" } @@ -9015,6 +9053,11 @@ } } }, + "@msgpack/msgpack": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-2.8.0.tgz", + "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", @@ -10250,6 +10293,11 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + }, "crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -10269,9 +10317,9 @@ "dev": true }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -11448,7 +11496,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "1.3.8", @@ -14549,20 +14598,23 @@ } }, "obs-websocket-js": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-4.0.2.tgz", - "integrity": "sha512-e+tGp0DQNXSnitc5lfuzEC1dG3VdWy7VLePUVb6aq7bC33Sgjoi695k0eOg4UPTIQI71Z9aJ+yn3nvBX9dQkEg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/obs-websocket-js/-/obs-websocket-js-5.0.2.tgz", + "integrity": "sha512-4XxWd5abIFOk0HjIHk+X/NwSXuOTPGsNnn7845g0UQZV0T3AtNk+dfp21zSjJVzuN/5oZR3UKjzEqg8pxMndCA==", "requires": { - "debug": "^4.1.0", + "@msgpack/msgpack": "^2.7.1", + "crypto-js": "^4.1.1", + "debug": "^4.3.2", + "eventemitter3": "^4.0.7", "isomorphic-ws": "^4.0.1", - "sha.js": "^2.4.9", - "ws": "^7.2.0" + "type-fest": "^2.3.2", + "ws": "^8.2.2" }, "dependencies": { - "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==" + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" } } }, @@ -14978,7 +15030,8 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "semantic-release": { "version": "18.0.1", @@ -15252,15 +15305,6 @@ "integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==", "dev": true }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", diff --git a/package.json b/package.json index b048f8e..4af61a6 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "midi-mixer-plugin": "^1.0.2", - "obs-websocket-js": "^4.0.2", + "obs-websocket-js": "^5.0.2", "ws": "8.4.0" }, "bundledDependencies": [ @@ -45,7 +45,12 @@ ], "volta": { "node": "14.15.4", - "npm": "6.14.11" + "npm": "8.19.2" }, - "version": "0.1.6" + "version": "0.1.6", + "bundleDependencies": [ + "midi-mixer-plugin", + "obs-websocket-js", + "ws" + ] } diff --git a/plugin.json b/plugin.json index 8d11425..157c432 100644 --- a/plugin.json +++ b/plugin.json @@ -12,7 +12,7 @@ "label": "OBS WebSocket Address", "required": false, "type": "text", - "fallback": "localhost:4444" + "fallback": "ws://localhost:4455" }, "password": { "label": "OBS WebSocket Password", @@ -27,6 +27,11 @@ "reconnect": { "label": "Reconnect", "type": "button" + }, + "meterMultiplier": { + "label": "Meter Scaling Multiplier", + "type": "text", + "fallback": "1" } } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 50688e6..397d9b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,117 +1,173 @@ import { Assignment, ButtonType } from "midi-mixer-plugin"; -import OBSWebSocket from "obs-websocket-js"; +import OBSWebSocket, { OBSWebSocketError, EventSubscription, OBSEventTypes, OBSResponseTypes } from "obs-websocket-js"; interface Settings { address?: string; password?: string; + meterMultiplier?: string + meterScaling?: number } const obs = new OBSWebSocket(); -let sources: Record = {}; +let inputs: Record = {}; let scenes: Record = {}; const settingsP: Promise = $MM.getSettings(); -let currentScene = ""; +let settings: Settings; const connect = async () => { - const settings = await settingsP; + settings = await settingsP; - return obs.connect({ - address: settings.address ?? "localhost:4444", - password: settings.password ?? "", - }); + // We need to use a text string to allow decimals. If given value is not a valid number set it to 1 + if (!(settings.meterScaling = Number(settings.meterMultiplier))) { + settings.meterScaling = 1; + } + + let address = (settings.address ?? "ws://localhost:4455") + if (!address.startsWith("ws://") && !address.startsWith("wss://")) { + address = `ws://${address}`; + } + + return obs.connect(address, settings.password ?? "", { eventSubscriptions: EventSubscription.All | EventSubscription.InputVolumeMeters }) }; + const registerListeners = () => { - obs.on("SourceVolumeChanged", (data) => { - const source = sources[data.sourceName]; + obs.on("InputVolumeChanged", (data) => { + const source = inputs[data.inputName]; if (!source) return; - source.volume = data.volume; + source.volume = data.inputVolumeMul; }); - obs.on("SourceMuteStateChanged", (data) => { - const source = sources[data.sourceName]; + obs.on("InputMuteStateChanged", (data) => { + const source = inputs[data.inputName]; if (!source) return; - source.muted = data.muted; + source.muted = data.inputMuted; }); - obs.on("SwitchScenes", (data) => { - currentScene = data["scene-name"]; + // TODO: Test this thoroughly + obs.on("InputVolumeMeters", (data) => { + data.inputs.forEach((input: any) => { + // Only update if non-zero audio levels + if (input.inputLevelsMul.length == 0 || input.inputLevelsMul[0][0] == 0 || !settings.meterScaling || settings.meterScaling == 0) return; + // I think [0] is left channel and [1] is right channel. + // console.log(input.inputLevelsMul[0][1]); + inputs[input.inputName].meter = input.inputLevelsMul[0][1] * settings.meterScaling; + }); + }); + obs.on("CurrentProgramSceneChanged", (data) => { Object.values(scenes).forEach((button) => { - button.active = data["scene-name"] === button.id; + button.active = data.sceneName === button.id; }); }); + + obs.on("ExitStarted", () => { + disconnect(); + init(); + }) }; const mapSources = async () => { - const data = await obs.send("GetSourcesList"); - - data.sources?.forEach(async (source: any) => { - const [volume, muted] = await Promise.all([ - obs - .send("GetVolume", { - source: source.name, - }) - .then((res) => res.volume), - obs - .send("GetMute", { - source: source.name, - }) - .then((res) => res.muted), - ]); - - const assignment = new Assignment(source.name, { - name: source.name, - muted, - volume, - }); + const data = await obs.call("GetInputList"); + + // TODO: Would prefer this not be "any" but the actual type is "JsonObject" which sucks to use + data.inputs?.forEach(async (input: any) => { + try { + const [volume, muted] = await Promise.all([ + obs + .call("GetInputVolume", { + inputName: input.inputName, + }) + .then((res) => res.inputVolumeMul), + obs + .call("GetInputMute", { + inputName: input.inputName, + }) + .then((res) => res.inputMuted), + ]); + + const assignment = new Assignment(input.inputName, { + name: input.inputName, + muted, + volume, + }); - assignment.on("volumeChanged", (level: number) => { - obs.send("SetVolume", { - source: source.name, - volume: level, + assignment.on("volumeChanged", (level: number) => { + assignment.volume = level; + obs.call("SetInputVolume", { + inputName: input.inputName, + inputVolumeMul: level, + }); }); - }); - assignment.on("mutePressed", () => { - obs.send("SetMute", { - source: source.name, - mute: !assignment.muted, + assignment.on("mutePressed", () => { + obs.call("SetInputMute", { + inputName: input.inputName, + inputMuted: !assignment.muted, + }); }); - }); - sources[source.name] = assignment; + inputs[input.inputName] = assignment; + } + catch (e: any) { + if (e instanceof OBSWebSocketError) { + if (e.code == 604) { + // https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatusinvalidresourcestate + // Usual cause is that input does not support audio + } + else { + console.log(e); + console.log(input); + } + } + } }); }; const mapScenes = async () => { - const data = await obs.send("GetSceneList"); + const data = await obs.call("GetSceneList"); - currentScene = data["current-scene"]; + // TODO: Would prefer this not be "any" but the actual type is "JsonObject" which sucks to use + data.scenes.forEach((scene: any) => { - data.scenes.forEach((scene) => { - const button = new ButtonType(scene.name, { - name: `OBS: Switch to "${scene.name}" scene`, - active: scene.name === currentScene, + const button = new ButtonType(scene.sceneName, { + name: `OBS: Switch to "${scene.sceneName}" scene`, + active: scene.sceneName === data.currentProgramSceneName, }); button.on("pressed", () => { - obs.send("SetCurrentScene", { - "scene-name": scene.name, + obs.call("SetCurrentProgramScene", { + sceneName: scene.sceneName, }); button.active = true; }); - scenes[scene.name] = button; + scenes[scene.sceneName] = button; }); }; +function disconnect() { + console.log("Disconnecting"); + obs.disconnect(); + for (let k in inputs) { + let s = inputs[k]; + s.remove(); + } + + for (let k in scenes) { + let s = scenes[k]; + s.remove(); + } +} + + const init = async () => { + console.log("Initializing"); obs.disconnect(); - sources = {}; + inputs = {}; scenes = {}; try { @@ -122,7 +178,7 @@ const init = async () => { await Promise.all([mapSources(), mapScenes()]); $MM.setSettingsStatus("status", "Connected"); - } catch (err) { + } catch (err: any) { console.warn("OBS error:", err); $MM.setSettingsStatus("status", err.description || err.message || err); }