From 4c23b01f61856ebb7189a6b2a9d9b763db5c3c17 Mon Sep 17 00:00:00 2001 From: skarab42 Date: Sun, 28 Feb 2021 19:55:17 +0100 Subject: [PATCH] feat: OBS toggle audio source (#183) --- app/server/libs/actions/types/obs.js | 5 ++ app/server/libs/obs.js | 32 ++++++++++- app/server/libs/twitch/pushActions.js | 1 + app/static/locales/en/app.json | 19 ++++--- app/static/locales/es/app.json | 19 ++++--- app/static/locales/fr/app.json | 17 +++--- .../Widgets/OBS/GoToScene/Settings.svelte | 8 ++- .../Widgets/OBS/ToggleAudio/Settings.svelte | 32 +++++++++++ .../Widgets/OBS/ToggleAudio/Widget.svelte | 56 +++++++++++++++++++ .../Widgets/OBS/ToggleAudio/config.js | 9 +++ .../Widgets/OBS/ToggleAudio/index.js | 3 + .../Widgets/OBS/ToggleScene/Settings.svelte | 7 ++- front-src/client/components/Widgets/index.js | 12 ++-- 13 files changed, 186 insertions(+), 34 deletions(-) create mode 100644 front-src/client/components/Widgets/OBS/ToggleAudio/Settings.svelte create mode 100644 front-src/client/components/Widgets/OBS/ToggleAudio/Widget.svelte create mode 100644 front-src/client/components/Widgets/OBS/ToggleAudio/config.js create mode 100644 front-src/client/components/Widgets/OBS/ToggleAudio/index.js diff --git a/app/server/libs/actions/types/obs.js b/app/server/libs/actions/types/obs.js index 8533f973..fc9e165e 100644 --- a/app/server/libs/actions/types/obs.js +++ b/app/server/libs/actions/types/obs.js @@ -6,6 +6,11 @@ function create(action) { } const actions = { + ToggleAudio(action) { + const { source } = action.widget.component.props; + + return obs.send("ToggleMute", { source }); + }, ToggleScene(action) { const { currentScene } = obs.getState(); const { scene1, scene2 } = action.widget.component.props; diff --git a/app/server/libs/obs.js b/app/server/libs/obs.js index 49044bbb..714a279c 100644 --- a/app/server/libs/obs.js +++ b/app/server/libs/obs.js @@ -16,6 +16,8 @@ let reconnectionTimeoutId = null; let recordingHeartbeatId = null; let recordingHeartbeatTimeout = 2000; +let sourceTypes = []; + let state = { connected: false, connecting: false, @@ -63,6 +65,24 @@ function updateSceneList() { }); } +function updateSourceTypesList() { + return send("GetSourceTypesList").then(({ types }) => { + sourceTypes = types; + }); +} + +function updateSourcesList() { + return send("GetSourcesList").then(({ sources }) => { + sources = sources.map((source) => { + const sourceType = sourceTypes.find( + (type) => type.typeId === source.typeId + ); + return sourceType ? { ...source, caps: sourceType.caps } : source; + }); + updateState({ sources }); + }); +} + function recordingHeartbeat() { recordingHeartbeatId = setTimeout(() => { updateStreamStatus(); @@ -103,6 +123,14 @@ function registerEvents(obs) { }); obs.on("ScenesChanged", updateSceneList); + + obs.on("SourceVolumeChanged", ({ sourceName, volume }) => { + emit(`source.volume`, { sourceName, volume }); + }); + + obs.on("SourceMuteStateChanged", ({ sourceName, muted }) => { + emit(`source.muted`, { sourceName, muted }); + }); } function onMessage(obs) { @@ -157,14 +185,16 @@ function connect({ host = "localhost", port = 4444, password = null } = {}) { obs .connect({ address, password }) - .then(() => { + .then(async () => { logger.info("Connected"); connecting = false; updateState({ connected: true, connecting }); obs.on("ConnectionClosed", onConnectionClosed); watch && onMessage(obs); registerEvents(obs); + await updateSourceTypesList(); updateStreamStatus(); + updateSourcesList(); updateSceneList(); emit("connected"); }) diff --git a/app/server/libs/twitch/pushActions.js b/app/server/libs/twitch/pushActions.js index a0bb55bd..74efa353 100644 --- a/app/server/libs/twitch/pushActions.js +++ b/app/server/libs/twitch/pushActions.js @@ -9,6 +9,7 @@ const types = { SceneList: "obs", GoToScene: "obs", ToggleScene: "obs", + ToggleAudio: "obs", AnimeTimeline: "anime", }; diff --git a/app/static/locales/en/app.json b/app/static/locales/en/app.json index 145a2707..63b5d7bd 100644 --- a/app/static/locales/en/app.json +++ b/app/static/locales/en/app.json @@ -160,29 +160,32 @@ "rule": "rule", "group": "group", "and": "and", - "or": "or" + "or": "or", + "source": "source" }, "obs": { "scene-list": "OBS | Scene list", "go-to-scene": "OBS | Go to scene", - "toggle-scene": "OBS | toggle between two scenes", + "toggle-scene": "OBS | Toggle between two scenes", + "toggle-audio": "OBS | Toggle audio source", "no-scene-selected": "No scene selected", "connect-at-startup": "Connect OBS at startup", "first-start-install-sentence": "If you want to use OBS with Marv you need to install OBS WebSocket.", "overlay-install-sentence": "To install Marv, create a browser source in OBS with the url below.", "check-disable-source-not-visible": "Check: Shutdown source when not visible.", "check-refresh-browser-on-activate": "Check: Refresh browser when scene becomes active.", - "overlay-not-found": "Overlay not found" + "overlay-not-found": "Overlay not found", + "no-source-selected": "obs.no-source-selected" }, "anime": { - "timeline": "Anime | Timeline" + "timeline": "Animation" }, "twitch": { - "chat": "Twitch chat", - "stream": "Twitch stream", + "chat": "Twitch | Chat", + "stream": "Twitch | Stream", + "rewards": "Twitch | Rewards", + "followers": "Twitch | Followers", "commands": "Commands", - "rewards": "Rewards", - "followers": "Followers", "connect-at-startup": "Connect Twitch at startup", "empty-command-list": "Empty command list", "command-cooldown": "Cooldown \"{{command}}\" -> ~{{rest}}", diff --git a/app/static/locales/es/app.json b/app/static/locales/es/app.json index 0c3d85b8..f1f803e1 100644 --- a/app/static/locales/es/app.json +++ b/app/static/locales/es/app.json @@ -159,29 +159,32 @@ "regla": "regla", "grupo": "grupo", "and": "and", - "or": "or" + "or": "or", + "source": "fuente" }, "obs": { "scene-list": "OBS | Lista de escenas", "go-to-scene": "OBS | Ir a la escena", "toggle-scene": "OBS | Cambiar entre dos escenas", + "toggle-audio": "OBS | Alternar fuente de audio", "no-scene-selected": "Ninguna escena seleccionada", "connect-at-startup": "Conectar a OBS al inicio", "first-start-install-sentence": "Para conectar Marv a OBS, debes instalar OBS WebSocket.", "overlay-install-sentence": "Para instalar Marv, crea una fuente del navegador en OBS con el enlance de abajo.", "check-disable-source-not-visible": "Marque la casilla: Desactivar la fuente en la que no este visible.", "check-refresh-browser-on-activate": "Marque la casilla: Recargar el navegador cuando la escena sea activa.", - "overlay-not-found": "Overlay no encontrado" + "overlay-not-found": "Overlay no encontrado", + "no-source-selected": "obs.no-source-selected" }, "anime": { - "timeline": "Anime | Timeline" + "timeline": "Animación" }, "twitch": { - "chat": "chat de Twitch", - "stream": "directo de Twitch", - "commands": "Comandos", - "rewards": "Recompensas", - "followers": "Partidarios", + "chat": "Twitch | Chat", + "stream": "Twitch | Stream", + "rewards": "Twitch | Recompensas", + "Followers": "Twitch | Seguidores", + "comandos": "Comandos", "connect-at-startup": "Conectar a Twitch durante el inicio", "empty-command-list": "Ningun comando", "command-cooldown": "Cooldown \"{{command}}\" -> ~{{rest}}", diff --git a/app/static/locales/fr/app.json b/app/static/locales/fr/app.json index f04070fb..e04df3e6 100644 --- a/app/static/locales/fr/app.json +++ b/app/static/locales/fr/app.json @@ -160,29 +160,32 @@ "rule": "règle", "group": "groupe", "and": "et", - "or": "ou" + "or": "ou", + "source": "source" }, "obs": { "scene-list": "OBS | Liste des scènes", "go-to-scene": "OBS | Aller à la scène", "toggle-scene": "OBS | Basculer entre deux scènes", + "toggle-audio": "OBS | Basculer source audio", "no-scene-selected": "Aucune scène sélectionnée", "connect-at-startup": "Connecter OBS au démarrage", "first-start-install-sentence": "Pour connecter Marv à OBS, tu dois installer OBS WebSocket.", "overlay-install-sentence": "Pour installer Marv, créer une source navigateur dans OBS avec l'url ci-dessous.", "check-disable-source-not-visible": "Coche la case: Désactiver la source quand elle n'est pas visible.", "check-refresh-browser-on-activate": "Coche la case: Rafraîchir le navigateur lorsque la scène devient active.", - "overlay-not-found": "Overlay non trouvé" + "overlay-not-found": "Overlay non trouvé", + "no-source-selected": "obs.no-source-selected" }, "anime": { - "timeline": "Anime | Timeline" + "timeline": "Animation" }, "twitch": { - "chat": "Twitch chat", - "stream": "Twitch stream", + "chat": "Twitch | Chat", + "stream": "Twitch | Stream", + "rewards": "Twitch | Récompenses", + "followers": "Twitch | Supporters", "commands": "Commandes", - "rewards": "Récompenses", - "followers": "Supporters", "connect-at-startup": "Connecter Twitch au démarrage", "empty-command-list": "Aucune commande", "command-cooldown": "Cooldown \"{{command}}\" -> ~{{rest}}", diff --git a/front-src/client/components/Widgets/OBS/GoToScene/Settings.svelte b/front-src/client/components/Widgets/OBS/GoToScene/Settings.svelte index 709af104..de7147a3 100644 --- a/front-src/client/components/Widgets/OBS/GoToScene/Settings.svelte +++ b/front-src/client/components/Widgets/OBS/GoToScene/Settings.svelte @@ -6,14 +6,16 @@ export let data; + let none = _("words.none"); + $: panel = data.panel; $: widget = data.widget; $: scenes = $state.scenes || []; $: props = widget.component.props; - $: items = [_("words.none"), ...scenes.map((s) => s.name)]; + $: items = [none, ...scenes.map((s) => s.name)]; - function onChange({ detail: scene }) { - props.scene = scene; + function onChange({ detail }) { + props.scene = detail === none ? null : detail; update(panel); } diff --git a/front-src/client/components/Widgets/OBS/ToggleAudio/Settings.svelte b/front-src/client/components/Widgets/OBS/ToggleAudio/Settings.svelte new file mode 100644 index 00000000..f7f18aac --- /dev/null +++ b/front-src/client/components/Widgets/OBS/ToggleAudio/Settings.svelte @@ -0,0 +1,32 @@ + + +
+