nodecg-obs
adds the ability to connect to 1-4 instances of OBS (via obs-websocket
) to your NodeCG bundle. It has two parts:
- The backend:
nodecg-utility-obs
, an npm package- This is server-side code that runs in Node.js.
- The frontend:
nodecg-widget-obs
, a Polymer element- This is client-side code that runs in your browser.
In addition, there's a supplementary Polymer element called nodecg-obs-scene
that provides realtime data bindings with information about a given scene in OBS.
Once your bundle has connected to OBS, you'll have access to a set of Replicants and Messages that you can use to both control OBS and react to events originating from OBS. For example, you could have code that changes based on what scene is active, or implement a "Transition" button that uses a different transition depending on what scene is being transitioned to. There's a lot of possibilities!
You can think of nodecg-obs
sort of like a set of mixins for your NodeCG bundle. It is meant for use with NodeCG v1. This documentation goes over how to install both nodecg-utility-obs
and nodecg-widget-obs
with the default settings to get you up and running as fast as possible.
Internally, nodecg-obs
uses obs-websocket-js
to communicate with obs-websocket
.
nodecg-utility-obs
and nodecg-widget-obs
should be installed as dependencies of your bundle.
Due to limitations of Bower, you'll need to install bower-npm-resolver
to install nodecg-widget-obs
.
- Install
nodecg-utility-obs
andbower-npm-resolver
via npm:cd nodecg/bundles/my-bundle npm install --save nodecg-utility-obs bower-npm-resolver
- Add
bower-npm-resolver
to a.bowerrc
file in the root of your bundle (create it if it does not exist):{ "resolvers": [ "bower-npm-resolver" ] }
- Install
nodecg-widget-obs
via Bowerbower install --save npm:nodecg-widget-obs
- Example
- Features
- Planned Features
- Contributing
- Namespaces & connecting to multiple instances of OBS
- Hooks
- Replicants
- Messages Sent
- Messages Received
- API
- Credits
Out of the box, very little configuration is required. You can go more in-depth and do more advanced things if you like, but they're not necessary to get up and running quickly.
First, in your bundle's extension (for example: nodecg/bundles/my-bundle/extension.js
)
const {OBSUtility} = require('nodecg-utility-obs');
module.exports = function (nodecg) {
const obs = new OBSUtility(nodecg);
}
Then, in one of your bundle's panels (for example: nodecg/bundles/dashboard/my-panel.html
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="../bower_components/webcomponentsjs/webcomponents-loader.js"></script>
<link rel="import" href="../bower_components/nodecg-widget-obs/nodecg-widget-obs.html">
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<nodecg-widget-obs></nodecg-widget-obs>
</body>
</html>
The recommended panel width
(in your package.json
's nodecg
stanza) is 3
.
And that's it! You now have access to all of the Replicants and Messages in your code, and an interface for establishing a connection to OBS. You may begin creating interactions and integrations with OBS in your bundle.
- Configure the IP, port, and password to use for connections on up to four separate instances of OBS, and monitor the status of these connections.
- Automatic reconnection.
- Replicants that update in real-time to reflect the current state of OBS, accessible from both the backend (extensions) and frontend (dashboard panels & graphics).
- Pre- and post-event hooks for extending
OBSUtility
with your own custom behaviors. - Full access to the
obs-websocket-js
API.OBSUtility
inherits fully from theobs-websocket-js
class. - Uses NodeCG's built-in logging system (which means it can also report errors to Sentry).
- More pre- and post-event hooks can be added! Feel free to open an issue or a pull request.
The nodecg-obs team enthusiastically welcomes contributions and project participation! There's a bunch of things you can do if you want to contribute! The Contributor Guide has all the information you need for everything from reporting bugs to contributing entire new features. Please don't hesitate to jump in if you'd like to, or even ask us questions if something isn't clear.
All participants and maintainers in this project are expected to follow Code of Conduct, and just generally be kind to each other.
Please refer to the Changelog for project history details, too.
Each individual connection to OBS has a namespace
. This is used to separate the Replicants and Messages of each instance,
otherwise they would collide with each other. Changing the namespace changes the prefix used in the names of
that instance's Replicants and Messages.
By default, OBSUtility
will use the obs
namespace. However, if you wish to make multiple instances of OBSUtility
(to connect to multiple instances of OBS), you'll need to give each one a unique namespace. Attempting to create
an instance of OBSUtility
with a namespace that is already in use will throw an error.
In your extension:
const primaryOBS = new OBSUtility(nodecg, {namespace: 'primaryOBS'});
const secondaryOBS = new OBSUtility(nodecg, {namespace: 'secondaryOBS'});
In a dashboard panel:
nodecg.sendMessage('primaryOBS:connect', {
ip: 'localhost',
port: 4444,
password: 'foo'
}, err => {
if (err) {
console.error(err);
return;
}
console.log('successfully connected to primaryOBS');
});
nodecg.sendMessage('secondaryOBS:connect', {
ip: '192.168.0.122',
port: 4444,
password: 'bar'
}, err => {
if (err) {
console.error(err);
return;
}
console.log('successfully connected to secondaryOBS');
});
Sometimes, you may need to alter the behavior of OBSUtility
or intercept and change data before it is dispatched to OBS. For these cases, a small selection of pre- and post-event hooks are available.
If none of the available hooks fit your use case, please open an issue or, even better, a pull request!
This hook runs just before OBSUtility
sends the TransitionToProgram
message. The transitionOpts
argument contains a clone of the options that OBSUtility
will send along with this TransitionToProgram
request. You may make any modifications you wish to this object, but you must return your modified object for your changes to have effect.
If your preTransition
hook returns a Promise, OBSUtility
will wait for it to resolve before continuing. That Promise can return the modified transitionOpts
, if needed.
const obs = new OBSUtility(nodecg, {
hooks: {
// If needed, preTransition can be an `async` method, or otherwise return a Promise.
preTransition(transitionOpts) {
// If we're transitioning to Scene A, use a Fade.
// Else, use a Cut.
transitionOpts['with-transition'] = obs.replicants.previewScene.value.name === 'Scene A' ?
'Fade' :
'Cut';
// Your preTransition hook can optionally return a "transitionOpts" object.
// This is passed directly to obs-websocket-js' "transitionToProgram" method.
// If you don't return anything, the defaults will be used.
return transitionOpts;
}
}
});
In your extension, all replicants in this utility can be accessed from the .replicants
property on the OBSUtility
class:
module.exports = function (nodecg) {
const obs = new OBSUtility(nodecg);
obs.replicants.websocket.on('change', () => {/* ... */});
obs.replicants.programScene.on('change', () => {/* ... */});
obs.replicants.previewScene.on('change', () => {/* ... */});
obs.replicants.sceneList.on('change', () => {/* ... */});
obs.replicants.transitioning.on('change', () => {/* ... */});
obs.replicants.studioMode.on('change', () => {/* ... */});
};
In your dashboard panels and graphics, you'll need to declare them as you would any other Replicant:
const previewScene = nodecg.Replicant('obs:previewScene');
previewScene.on('change', newVal => {
// ...
});
If OBS is in "Studio" mode, this Replicant's value
will be the current scene that is in Preview.
If OBS is not in "Studio" mode, this Replicant's value
will be null
.
Relevant Schemas:
If OBS is in "Studio" mode, this Replicant's value
will be the current scene that is in Program. If OBS is not in "Studio" mode, this Replicant's value
will be the currently selected scene. In other words, this Replicant always tells you what scene is going out on the stream right now.
Relevant Schemas:
The configuration and status of the websocket connection to obs-websocket
.
Relevant Schemas:
A string array containing the name of every scene currently in OBS.
Relevant Schemas:
A boolean that becomes true
when a transition is in progress and false
when one isn't.
Relevant Schemas:
A boolean that becomes true
when OBS is in Studio Mode false
when OBS isn't in Studio Mode.
Relevant Schemas:
A special replicant that is shared between all instances/namespaces. It always uses the name _obs:namespaces
,
regardless of what namespaces have been used. The purpose of this Replicant is to enable code on the Dashboard
to track how many instances have been created and present separate interfaces for each of those instances.
Relevant Schemas:
Emitted whenever a transition begins in OBS. First and only argument is an object with the following properties:
toScene
- The name scene being transitioned to (the Preview scene at the time of the transition starting).fromScene
- The name of the scene being transitioned from (the Program scene at the time of the transition starting).sceneName
(deprecated) - Same astoScene
.
nodecg.listenFor('obs:transitioning', data => {
console.log(data.sceneName); // logs the name of the scene being transitioned to
});
Request a connection to an instance of OBS that has obs-websocket
installed.
Each OBSUtility
instance can connect to one instance of OBS at a time. To connect to multiple instances of OBS,
use multiple instances of OBSUtility
.
nodecg.sendMessage('obs:connect', {
ip: 'localhost',
port: 4444,
password: 'foo'
}).then(() => {
console.log('successfully connected to obs');
}).catch(err => {
console.error('failed to connect to obs:', err);
});
Disconnects from OBS.
nodecg.sendMessage('obs:disconnect');
Requests that the preview scene be changed to sceneName
. Only works in Studio mode.
nodecg.sendMessage('obs:previewScene', 'Foo Scene').then(() => {
console.log('successfully previewed Foo Scene');
}).catch(err => {
console.error('failed to preview Foo Scene:', err);
});
Transitions from Preview to Program, using the transition with the specified name
, over the specified duration
. Both properties are optional, omitting either will use the default for that property.
By default, will transition to whatever the current Preview scene is. If you wish to specify a specific scene to transition to, provide it as the optional sceneName
parameter.
nodecg.sendMessage('obs:transition', 'Fade').then(() => {
console.log('successfully started a Fade transition');
}).catch(err => {
console.error('failed to start Fade transition', err);
});
nodecg-obs
extends obs-websocket-js
. Please
refer to obs-websocket-js
's documentation for a full API.
Use caution when using obs-websocket-js
's API directly, as you may be bypassing some or all of
nodecg-obs
's functionality.
Visual design by @chrishanel