API plugin/calls to switch scenes, sources, etc?

awrebels

New Member
Does anyone know of anything like this? I was hoping to use AHK to send certain calls to OBS to turn on and off scenes, sources and specifically AVOID using hotkeys.
 

awrebels

New Member
I actually use that plugin which is very useful. However what i am looking to do is using sending custom api calls to OBS - likely more advanced than the above plugin. Specifically I am using firebot & mixer's interactive buttons to trigger scene/source changes however I have to rely on hotkeys which sometimes produce issues with certain games. Sending api calls would hopefully eliminate that issue.

A bit complex but would be really beneficial. Any thoughts or ideas are greatly appreciated.
 

Fenrir

Forum Admin
I'm really confused how the websocket plugin is not sufficient for this. What you're describing is exactly what that plugin is for?

The websockets plugin can interact with every frontend API function that OBS Studio has currently. If Websockets cannot provide the control you want, then it is not currently possible.
 

awrebels

New Member
Sorry, I'm probably not explaining my needs fully. What I am trying to find or figure out is a way to write a custom script/api call for example to change one scene. The reason it needs to be a custom independent script is I will be using Firebot for mixer.com (https://github.com/Firebottle/Firebot) to allow specific users to change scenes within OBS.

If you are familiar with firebot or mixer you can give viewers interactive features/buttons to press during stream to trigger overlays etc. Basically I gave specific users buttons to trigger scene changes or turn on/off sources. I've been using hotkeys but that can be problematic given certain games and active window status. I'd rather a background script triggers the scenes/sources.

Websocket is a great tool for me to do scene changes myself remotely. However it is likely too complex for this specific need. I've tried to read through the documentation and code but it is a little complex for me.

What I am hoping to find is a basic tutorial, explanation, or code of writing a simple script to change a single scene or single source. A workaround was I've been using AHK's controlsend however it still requires use of hotkeys afaik. So if there was a simple script that changed one scene/source I could replicate it for a number of these interactive buttons.

Alternatively if there is an AHK solution that runs in the background to change scenes that would be another solution.

Please let me know if this needs further clarification.

And again any help is much appreciated. Thanks!
 

Fenrir

Forum Admin
I'm really not trying to be rude, but websockets IS the simple script/solution you're looking for here.

There really isn't any easier way outside coding your own plugin entirely. The API for frontend events is only exposed to internal plugins, who are then responsible for making it externally available if the need is present.

I apologize that it's not exactly user friendly, but this is really the only thing that exists right now.
 

awrebels

New Member
no offense taken. I'll have to dive into the code of that plugin to figure it out. I do think/anticipate that I would need to code the plugin from scratch - i'm just trying to figure out a way to research that. Presumably this documentation is out of date? https://github.com/jp9000/OBS/wiki/OBS-Plugin-API-Documentation

On another note do you know of any developers well versed in the obs frontend api to create a plugin? It'd be great if I could pick their brain to see if it is possible; and this would be a paid gig.
 

Fenrir

Forum Admin
That is OBS classic documentation, and is irrelevant. OBS Studio documentation is in progress, and should be ready sometime soon, but no ETA yet.
 

RytoEX

Forum Admin
Forum Moderator
Developer
@awrebels As much as I'd be interested in paid work on a new frontend plugin, AutoHotkey already has at least one Websocket implementation available, so you should just be able to include that and write AutoHotkey scripts as needed to send websocket messages to the obs-websocket plugin.
 

awrebels

New Member
@RytoEX thank you for that. although the documentation is pretty sparse. Do you know of any examples that explain how to send those websocket messages from autohotkey to obs for scene switching etc?
 

RytoEX

Forum Admin
Forum Moderator
Developer
@awrebels The author provides examples in that thread and on GitHub. Other than that, there are plenty of examples on the web of how websockets work. You can even do them manually from a browser developer console to test.

However, I confess to being a bit confused. I'll admit that I'm not very familiar with Mixer, and I've never heard of Firebot before this thread. Firebot seems to focus on performing scene/source changes in Mixer's lab/studio features. It's not, as far as I've seen, used to changing OBS scenes locally. You might be able to use custom Firebot scripts attached to buttons to fire websocket requests at your computer.

I've been using hotkeys but that can be problematic given certain games and active window status. I'd rather a background script triggers the scenes/sources.
This sounds like you're looking for an action queueing system, rather than just a simple way to fire actions in OBS as triggers occur. Though, I may be misunderstanding your request entirely.
 

MuckinOnionz

New Member
This is an old thread but I'm stumbling upon the same question. I think I can add clarity to what Awrebels was asking. I am Streaming to Twitch.tv. I want my chat on twitch.tv to be able to use a command such as !replay. to trigger a hotkey I have setup in OBS Studio to trigger the instant replay command. I'm assuming I would need the following: program that uses OAUTH to read chat and scan for specific commands AND interacts with OBS. or Program that uses OAUTH to read chat and another program that it communicates with to send !commands to OBS. I am not a programmer but I've been doing a bit of research to figure out how to make this work. there is a bot called "deep bot" that does exactly this and communicates with a program called "remote OBS" to change scenes and sources but "deep bot" doesn't have the functionality built in for other types of commands such as triggering hotkeys in OBS.

From what I've read above it seems like the "obs-websocket" and "Autohotkey" are 2 of 3 parts needed to get this idea off the ground. The last part would be the gap at the start. i.e. the program that reads the command from twitch chat (deep bot alternative) and communicates with obs-websocket and autohotkey to trigger the request in OBS. i.e. Twitch viewer types !replay in chat, a program reads the command and relays to OBS to start the instant replay. This will then [start downloading the replay and a separate scene will appear on screen] - already setup in OBS, showing the viewer the replay he selected (30seconds of footage prior to typing the !replay command).

There is an app out right now called boom.tv that does all of this for you, but it causes lag issues with single PC setups, hence my searching for an alternative method that doesn't require a cloud based service.

Hope this is clear...
 

JoinTheARC

New Member
I am interested in @MuckinOnionz's idea as well. A lot of research (even tried messing with boom.tv code) but to no avail. Not a programmer by any means, just looking to add some customization.
 

ThatFontGuy

New Member
I would like to first mention that I do NOT program in Nodejs, so the following is a hacked together script that works but is probably offensive to real programmers in how badly its written. This is a script I run in a cmd window on my desktop. I am also running Bitfocus Companion together with my streamdeck, so there are a lot of commands in here that are simply pressing buttons on my companion set up and might not make any sense to anyone else given the fact that they can't see what my companion buttons are set to do. Mostly its scene changes mind you.

This script has allowed me to gamify my chat just to make it more entertaining. So I have OBS scenes set up with my Camera in a frame located in either the Top Left, Top Right, Bottom Left or Bottom Right and this script allows viewers to move me around if I am in the way of the game's UI and they want to see something. I also a Chat scene which is a close up of me along with my chat and the game appearing in a small window. I have the same scenes duplicated and with a Color Correction filter with the Saturation set to zero that are Black and White versions of the same 5 scenes. Viewers can switch to B&W mode and still move me around. Its silly but kind of fun I hope. I also have a whole schtick with wearing a series of hats - so far only my friends have bothered with this. That one ties into the Channel Points system so only those viewers who have been around a while can use it. I have various other chat related elements in there as well. This bot monitors the channel chat of course, but I am using Nightbot for most of the regular monitoring functionality. I have had a terrible time finding examples of code to steal from, so I hope that other people will find this useful as a start. It does work, but I have only a vague idea why - its the result of hacking up what I was able to find combined with a lot of experimentation to get it working. Use at your own risk and all that.

Part ONE:
---------
//New Bot
console.log("****************\n* STARTING TFGBOT *\n****************\nVersion 1.1\n");

const { exec } = require("child_process");
const http = require('http');

const OBSWebSocket = require("obs-websocket-js");
const obs = new OBSWebSocket();

var tmi = require('tmi.js');
var say = require('say');


/* GET COLOUR MODE: */
setCstatus(1);
console.log("* In Colour Mode: " + getCstatus());

//BOT CONNECTION OPTIONS
var options = {
options: {
debug: false
},
connection: {
cluster: "aws",
reconnect: true
},
identity: {
username: "YOUR_USER_NAME",
password: "YOUR_OATH_CODE"
},
channels: ["YOUR_CHANNEL"]
};

// Create a client with our options
const client = new tmi.client(options);

// Register our event handlers (defined below)
client.on('message', onMessageHandler);
client.on('connected', onConnectedHandler);

// Connect to Twitch:
client.connect();

resetAll();
turnOffBotSign();

// Called every time a message comes in
function onMessageHandler (target, context, msg, self) {

if (self) { return; } // Ignore messages from the bot
Cstatus = getCstatus();

// Remove whitespace from chat message
const commandName = msg.trim();

// Filter out Nightbot, Bang Commands :)
if(context.username == "nightbot") {
// do nothing
} else if(msg.charAt(0) == "!") {
// Ignore ! commands as well
if(commandName === "!setBW") {
setCstatus(0);
client.say(target, context.username + " switched us to B&W mode");
console.log("* " + context.username + " switched CStatus to B&W");
return;
}

if(commandName === "!setColour") {
setCstatus(1);
client.say(target, context.username + "switched us to Colour mode");
console.log("* " + context.username + " switched CStatus to Colour");
return;
}

if(commandName === "!bw") {
if(Cstatus === 1) {
setCstatus(0);
client.say(target, context.username + " switched us to B&W mode");
console.log("* " + context.username + " switched CStatus to B&W");
return;
} else {
setCstatus(1);
client.say(target, context.username + "switched us to Colour mode");
console.log("* " + context.username + " switched CStatus to Colour");
return;

}

}
} else {
//Make a noise whenever someone speaks in chat (Win10 using cmdmp3win.exe which I downloaded and placed in this same folder):
exec("cmdmp3win ComputerError.wav", (error, stdout, stderr) => {});
FlashChatAnim();
}

// TOGGLE COLOUR STATUS:
if(commandName === '!bw') {
if(getCstatus() === 1) {
client.say(target, "Note: Further scene changes will be to B&W versions until this command is issued again");
console.log(`* Turned B&W mode on`);
toggleCstatus();
} else {
client.say(target, "Returning to colour mode with the next scene change");
console.log(`* Turned B&W mode off`);
toggleCstatus();
}
}

if(commandName === '!hello') {
var username = context["display-name"];
client.say(target, username +' Hi there, welcome to the channel! Please feel free to ask questions');
console.log('* Printed Greeting *');
}

/* GULL INFO */
if((msg.toLowerCase()).includes("seagull")) {
client.say(target, 'Please do not mention the gulls, it only encourages them. You can type !gulls to warn other viewers though');
}

/* GULL WARNING */
if(commandName === '!gulls') {
const warningText = '*** GULL WARNING ***';
client.say("channel", warningText);
console.log(`* Executed ${commandName} command`);

/* Make an http request to toggle visibility on the GULLWARNING scene */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/26','Displayed Gull Warning');
}

/* CAMERA MOVEMENT TO TL BL TR BR positions */
/* This section ensures that if a command to switch from colour to B&W has been issued
the camera will stay in the same mode. It doesn't do anything if the streamer selects
a different mode though, so the streamer must be sure to use the correct scene change */
switch(commandName) {
case '!tl':
/* Determine if we want colour or B&W version: */
if(getCstatus() === 1) {
/* Move Camera to TL position */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/2','* Move Camera to TL');
} else {
/* Move Camera to TL position in B&W */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/2','* Move Camera to TL B&W');
}
break;

case '!tr':
/* Determine if we want colour or B&W version: */
if(getCstatus() === 1) {
/* Move Camera to TR position */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/4','* Move Camera to TR');
} else {
/* Move Camera to TR position in B&W */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/4','* Move Camera to TR B&W');
}
break;

case '!bl':
/* Determine if we want colour or B&W version: */
if(getCstatus() === 1) {
/* Move Camera to BL position */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/18','* Move Camera to BL');
} else {
/* Move Camera to BL position in B&W */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/18','* Move Camera to BL B&W');
}
break;

case '!br':
/* Determine if we want colour or B&W version: */
if(getCstatus() === 1) {
/* Move Camera to BR position */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/20','* Move Camera to BR');
} else {
/* Move Camera to BR position in B&W */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/20','* Move Camera to BR B&W');
}
break;

case "!chat":
/* Determine if we want colour or B&W version: */
if(getCstatus() === 1) {
/* Move Camera to Chat Screen */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/11','* Move Camera to Chat');
} else {
/* Move Camera to Chat Screen in B&W */
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/11','* Move Camera to Chat B&W');
}
break;

// Colour Only:
case "!chatcl":
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/11','* Move Camera to Chat Colour');
setCstatus(1);
break;

case "!tlcl":
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/2','* Move Camera to TL Colour');
setCstatus(1);
break;

case "!trcl":
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/4','* Move Camera to TR Colou');
setCstatus(1);
break;

case "!blcl":
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/18','* Move Camera to BL Colou');
setCstatus(1);
break;

case "!brcl":
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/20','* Move Camera to BR Colou');
setCstatus(1);
break;

// B&W Only:
case "!chatbw":
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/11','* Move Camera to Chat B&W');
setCstatus(0);
break;

case "!tlbw":
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/2','* Move Camera to TL B&W');
setCstatus(0);
break;

case "!trbw":
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/4','* Move Camera to TR B&W');
setCstatus(0);
break;

case "!blbw":
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/18','* Move Camera to BL B&W');
setCstatus(0);
break;

case "!brbw":
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/20','* Move Camera to BR B&W');
setCstatus(0);
break;


case '!clap':
exec("cmdmp3win clapping.wav", (error, stdout, stderr) => {});
break;

}
 

ThatFontGuy

New Member
Part TWO: (the forum has a limit of 15k characters, the script does not):
-------

/* NEW HAT CHANGE DETECTION CODE BASED ON CHANNEL POINTS */
if (context["custom-reward-id"] === "YOUR_CUSTOM_REWARD_ID") {

/* BEANIE */
if((msg.toLowerCase()).includes("1")) {
var username = context["display-name"];
client.say(target,'Please put on The Cloth Beanie');
}

/*Cowboy Leather*/
if((msg.toLowerCase()).includes("2")) {
var username = context["display-name"];
client.say(target, 'Please put on The Cowboy Leather hat');
}

/*Leather Skullcap*/
if((msg.toLowerCase()).includes("3")) {
var username = context["display-name"];
client.say(target, 'Please put on The Leather Skullcap');
}

/*Military Beret*/
if((msg.toLowerCase()).includes("4")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Military Beret');
}

/*Military Field Cap*/
if((msg.toLowerCase()).includes("5")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Military Field Cap');
}

/*Glengarry*/
if((msg.toLowerCase()).includes("6")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Glengarry');
}

/*Porkpie*/
if((msg.toLowerCase()).includes("7")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Pork Pie');
}

/*Monkey*/
if((msg.toLowerCase()).includes("8")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Monkey Hat');
}

/*Raccoon*/
if((msg.toLowerCase()).includes("9")) {
var username = context["display-name"];
client.say(target, 'Please requests you put on The Raccoon Hat');
}

/* Play a drum sound to get attention */
exec("cmdmp3win Drum.wav", (error, stdout, stderr) => {});
}

/* No Hat */
if((msg.toLowerCase()).includes("no hat")) {
var username = context["display-name"];
client.say(target, username + ' says you can take off your hat!');
exec("cmdmp3win Drum.wav", (error, stdout, stderr) => {});
}

if(commandName === '!hats') {
client.say(target, 'To request thatFontGuy to switch to a specific hat please use Channel Points to buy a Change Hats token, or you can request he take off the hat using !nohat');
console.log(context.username + " asked about hats");
}

}

function FlashChatAnim () {
/* Flash Chat Animation: */
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/6','')
}

// Called every time the bot connects to Twitch chat
function onConnectedHandler (addr, port) {
console.log(`* Connected to ${addr}:${port}`);
}

// Check every 30s to see what the current viewer count is
// If its over a specified threshhold then toggle the ViewerCount icon in the Status Bar scene
function checkViewerCount() {
http.get('http://tmi.twitch.tv/group/user/thatfontguy/chatters', (resp) => {
let data = '';

// a chunk of data has been received
resp.on('data', (chunk) => {
data += chunk;
});

resp.on('end', () => {
// Get Chatter count:
let response = JSON.parse(data);
ChatterCount = response.chatter_count;

// Convert to an Integer:
var val = parseInt(ChatterCount, 10);

// Are we over the threshold?
threshhold = 10;
if(val >= threshhold) {
// Turn on the scene element that marks the threshold
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/7','');
} else if(val < threshhold) {
// Turn on the scene element that marks the threshold
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/15','');
}

// Display the number of viewers between 0 and 10+ as the Count
switch(val) {
case 0:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/31','');
break;

case 1:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/6','');
break;

case 2:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/7','');
break;

case 3:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/8','');
break;

case 4:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/14','');
break;

case 5:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/15','');
break;

case 6:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/16','');
break;

case 7:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/22','');
break;

case 8:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/23','');
break;

case 9:
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/24','');
break;

case (val >= 10):
// Change value of Count to show val number:
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/30','');
break;
}
});

}).on("error", (err) => {
console.log("Error: " + err.message);
});
}

checkViewerCount();

function pushCompanionButton(bank, msg) {
http.get(bank, (resp) => {
let data = '';

// a chunk of data has been received
resp.on('data', (chunk) => {
data += chunk;
});

resp.on('end', () => {
if(msg != '') {
console.log(msg);
}
});

}).on("error", (err) => {
console.log("Error: " + err.message);
});
}

/* This function turns off the visibility of all scene elements like the Gull Warning, Applause etc */
function resetAll() {
pushCompanionButton('http://127.0.0.1:8888/press/bank/2/25','* Resetting all Toggles');
}

function turnOffBotSign() {
pushCompanionButton('http://127.0.0.1:8888/press/bank/1/8', '* Turning off the bot sign');
}

function setCstatus(val) {
Cstatus = val;
}

function getCstatus(){
return Cstatus;
};

function toggleCstatus() {
if(getCstatus() === 1) {
Cstatus = 0;
} else {
Cstatus = 1;
}
return Cstatus;
}


setInterval(function(){
checkViewerCount()
}, 30000)



/* Switches OBS to the specified Scene */
/* NOTE that I will be attempting to use this in place of many of the Companion requests above so that I can reduce the requirement to use
Companion as much as possible. I have not tried that yet but the changeScene code does work at the moment*/

function changeScene(TargetScene) {

const obs = new OBSWebSocket();
obs.connect({ address: 'localhost:4444', password: 'YOUR_PASSWORD' }).then(() => {
obs.send('SetCurrentScene', {
'scene-name': TargetScene
})
.then(() => {})
.catch(err =>{
console.log(err);
})
});
}
 

ThatFontGuy

New Member
This is an old thread but I'm stumbling upon the same question. I think I can add clarity to what Awrebels was asking. I am Streaming to Twitch.tv. I want my chat on twitch.tv to be able to use a command such as !replay. to trigger a hotkey I have setup in OBS Studio to trigger the instant replay command. I'm assuming I would need the following: program that uses OAUTH to read chat and scan for specific commands AND interacts with OBS. or Program that uses OAUTH to read chat and another program that it communicates with to send !commands to OBS. I am not a programmer but I've been doing a bit of research to figure out how to make this work. there is a bot called "deep bot" that does exactly this and communicates with a program called "remote OBS" to change scenes and sources but "deep bot" doesn't have the functionality built in for other types of commands such as triggering hotkeys in OBS.

From what I've read above it seems like the "obs-websocket" and "Autohotkey" are 2 of 3 parts needed to get this idea off the ground. The last part would be the gap at the start. i.e. the program that reads the command from twitch chat (deep bot alternative) and communicates with obs-websocket and autohotkey to trigger the request in OBS. i.e. Twitch viewer types !replay in chat, a program reads the command and relays to OBS to start the instant replay. This will then [start downloading the replay and a separate scene will appear on screen] - already setup in OBS, showing the viewer the replay he selected (30seconds of footage prior to typing the !replay command).

There is an app out right now called boom.tv that does all of this for you, but it causes lag issues with single PC setups, hence my searching for an alternative method that doesn't require a cloud based service.

Hope this is clear...


Saw your post and attached the source for my hacked together bot. If you have solved your problem or have any useful feedback on mine please let me know :)
 

mesihas

New Member
I know this thread is a bit old but seems to be the closest of what I am looking for: Is it possible to use websocket to control OBS form ESP8266 or ESP32?
 

Danilov3s

New Member
I know this thread is a bit old but seems to be the closest of what I am looking for: Is it possible to use websocket to control OBS form ESP8266 or ESP32?

That's doable, however IMO you would want something more robust like a Pi Zero
 

YorVeX

Member
I know this thread is old, but it's what Google brought up when I tried to find out whether there is something that gives me a bit more simple HTTP API than obs-websocket. Actually it was the only result that came at least close to what I wanted, everything else was just web GUIs that came with buttons/controls already. I wanted that pretty much for the reasons stated here, it can be used from more tools (including AHK) and more easily than if you have to handle a websocket connection and format JSON data.

When I didn't find anything I've created my own solution, so in case somebody else finds this thread for the same reason: what you're looking for is here.
 
Top