nodecg-utility-obs

A NodeCG utility that exposes a set of Replicants, Messages, and other hooks for interacting with OBS via obs-websocket


Keywords
nodecg, utility, helper, obs, obs-websocket, obs-websocket-js
License
MIT
Install
npm install nodecg-utility-obs@6.1.7

Documentation

nodecg-utility-obs npm version license Build Status Coverage Status Join the chat at https://gitter.im/nodecg/nodecg

nodecg-utility-obs is a NodeCG utility that adds a set of Replicants, Messages, and other hooks to your NodeCG bundle. It is meant for use with NodeCG v0.9. You can think of it like a mixin for your NodeCG bundle.

It requires that the instance of OBS have obs-websocket installed and configured.

Internally, it uses obs-websocket-js to communicate with obs-websocket.

Install

$ npm install --save nodecg-utility-obs

Table of Contents

Example

/* In your bundle's extension.
 * For example: nodecg/bundles/my-bundle/extension.js */

// nodecg-obs-utility implements its own logging.
// For it to work, you need to pass it a reference to NodeCG's Logger class.
const Logger = require('../../../lib/logger');

module.exports = function (nodecg) {
    // Most utilities will need a reference to an instance of the NodeCG API.
    // That's the first argument we're passing in here.
    //
    // The second argument is an instance of NodeCG's Logger class.
    // nodecg-utility-obs will use that to do its own logging, while
    // still respecting your configuration in cfg/nodecg.json.
    //
    // The third argument is optional, and is where you define certain pre-
    // and post-event hooks that can alter the behavior of nodecg-utility-obs.
    const obs = new OBSUtility(nodecg, Logger, {
        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;
            }
        }
    });
}

Features

  • Supports connecting to multiple instances of OBS, and managing them independently.
  • Replicants that update in realtime to reflect the current state of OBS, accessible from both the backend (extensions) and frontend (dashboard panels & graphics).
  • Send messages from the frontend (dashboard panels & graphics) to manage the connection and trigger events in OBS.

Planned Features

  • More pre- and post-event hooks can be added! Feel free to open an issue or a pull request.

Contributing

The nodecg-utility-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.

Connecting to multiple instances of OBS

Every instance of OBSUtility 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.

Example

In your extension:

const primaryOBS = new OBSUtility(nodecg, Logger, {namespace: 'primaryOBS'});
const secondaryOBS = new OBSUtility(nodecg, Logger, {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');
});

Hooks

Sometimes, you may need to alter the behavior of nodecg-utility-obs 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!

> Hook preTransition(transitionOpts)

This hook runs just before nodecg-utility-obs sends the TransitionToProgram message. The transitionOpts argument contains the a clone of the options that nodecg-utility-obs will send along with this TransitionToProgram request. You may make any modificatrions 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, nodecg-utility-obs will wait for it to resolve before continuing. That Promise can return the modified transitionOpts, if needed.

Example
const obs = new OBSUtility(nodecg, Logger, {
    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;
        }
    }
});

Replicants

In your extension, all replicants in this utility can be accessed from the .replicants property on the OBSUtility class:

const Logger = require('../../../lib/logger');

module.exports = function (nodecg) {
    const obs = new OBSUtility(nodecg, Logger);
    obs.replicants.websocketConfig.on('change', () => {/* ... */});
    obs.replicants.programScene.on('change', () => {/* ... */});
    obs.replicants.previewScene.on('change', () => {/* ... */});
    obs.replicants.sceneList.on('change', () => {/* ... */});
    obs.replicants.transitioning.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 => {
	// ...
});

> nodecg.Replicant('obs:previewScene')

If OBS is in "Studio" mode, this Replicant's value will be the current scene that is in Preview.

Relevant Schemas:

> nodecg.Replicant('obs:programScene')

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:

> nodecg.Replicant('obs:websocket')

The configuration and status of the websocket connection to obs-websocket.

Relevant Schemas:

> nodecg.Replicant('obs:sceneList')

A string array containing the name of every scene currently in OBS.

Relevant Schemas:

> nodecg.Replicant('obs:transitioning')

A boolean that becomes true when a transition is in progress and false when one isn't.

Relevant Schemas:

Messages Sent

> nodecg.listenFor('obs:transitioning', callback)

Emitted whenever a transition begins in OBS. First and only argument is an object, whose only property is sceneName; a string of the name of the scene being transitioned to.

Example
nodecg.listenFor('obs:transitioning', data => {
	console.log(data.sceneName); // logs the name of the scene being transitioned to
});

Messages Received

> nodecg.sendMessage('obs:connect', params, callback)

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.

Simple Example (one instance)

From a dashboard panel:

nodecg.sendMessage('obs:connect', {
    ip: 'localhost',
    port: 4444,
    password: 'foo'
}, err => {
	if (err) {
		console.error(err);
		return;
	}
	
	console.log('successfully connected to obs');
});

> nodecg.sendMessage('obs:disconnect')

Disconnects from OBS.

Example
nodecg.sendMessage('obs:disconnect');

> nodecg.sendMessage('obs:abortConnectionAttempt')

Aborts an in-progress connection attempt.

Example
nodecg.sendMessage('obs:abortConnectionAttempt');

> nodecg.sendMessage('obs:previewScene', sceneName, callback)

Requests that the preview scene be changed to sceneName. Only works in Studio mode.

Example
nodecg.sendMessage('obs:previewScene', 'Foo Scene', err => {
	if (err) {
		console.error(err);
		return;
	}
	
	console.log('successfully previewed Foo Scene');
});

> nodecg.sendMessage('obs:transition', transitionName, callback)

Transitions from Preview to Program, using the specified transitionName. Use null or an empty string ('') to use the default transition in the current instance of OBS.

Example
nodecg.sendMessage('obs:transition', 'Fade', err => {
	if (err) {
		console.error(err);
		return;
	}
	
	console.log('successfully started a Fade transition');
});

API

nodecg-utility-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-utility-obs's functionality.