OpenLP and OBS Integration

Below (at the bottom of this webpage) are two downloads that fully integrate OBS with OpenLP. This allows you to run OpenLP and OBS as separate applications, and use the OpenLP Controller within OBS, as well as lyrics integration using web page overlays. There is also auto-switching of scenes and audio based on whether OpenLP is showing lyrics or showing slides or showing bible verses. There is an automatic countdown based on a fixed time and also overlays for logos.

There is even extra logic to automatically change the Scene to the camera view if OpenLP is blanked or showing the background theme.

They are based on older, more stable versions of OpenLP and OBS.

Installation instructions

To get this going, follow these steps:

No installation is required - these are fully portable files that can run even from a USB stick.

WARNINGS

Usage Notes

If you want to use BlackMagic ATEM mini ATEM Software Control integration, then see here: ATEM Global Hotkeys 

If you would like to run OpenLP on a different computer, then modify the IP address for the Custom Browser Dock, and the Lyrics Source:

OPENLP Stage Code

Here is the code for stage.js. It is based on the sample code from the OpenLP forum https://forums.openlp.org/discussion/5336/tutorial-how-to-control-obs-via-openlp-custom-stage-view/ but switches automatically between scenes by detecting what OpenLP is displaying. There are two modes, manual and auto:

If the OBS current scene does not have "auto" in the scene title, then ignore any commands from OpenLP. This feature allows you to decouple OBS from OpenLP so you can use OpenLP at the start and end without affecting the live stream. 

For instance, this service run sheet will allow you to start a pre-roll video, then switch to the autoCamera at the start. From this point onwards, OpenLP will control OBS scene switching.

Then at the end, play the post-roll. 

So when the pre-roll and post-roll videos are running in OBS, you can use OpenLP to display anything you want without fear of affecting the livestream.

2. Auto modes

/******************************************************************************

 * OpenLP - Open Source Lyrics Projection                                      *

 * --------------------------------------------------------------------------- *

 * Copyright (c) 2008-2017 OpenLP Developers                                   *

 * --------------------------------------------------------------------------- *

 * This program is free software; you can redistribute it and/or modify it     *

 * under the terms of the GNU General Public License as published by the Free  *

 * Software Foundation; version 2 of the License.                              *

 *                                                                             *

 * This program is distributed in the hope that it will be useful, but WITHOUT *

 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *

 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *

 * more details.                                                               *

 *                                                                             *

 * You should have received a copy of the GNU General Public License along     *

 * with this program; if not, write to the Free Software Foundation, Inc., 59  *

 * Temple Place, Suite 330, Boston, MA 02111-1307 USA                          *

 ******************************************************************************/

window.OpenLP = {

  loadService: function (event) {

    $.getJSON(

      "/api/service/list",  // To see all use http:/127.0.0.1:4316/api/service/list

      function (data, status) {

        for (idx in data.results.items) {

          idx = parseInt(idx, 10);

          if (data.results.items[idx]["selected"]) {

            // inserted for OBS control, I want to be able to read out the information

            OpenLP.currentTitle = data.results.items[idx]["title"];

            OpenLP.currentNotes = data.results.items[idx]["notes"];

            OpenLP.currentPlugin = data.results.items[idx]["plugin"];

            // see CSS file

            $("#currentslide").attr("data-plugin", OpenLP.currentPlugin);

            break;

          }

        }

        OpenLP.updateSlide();

      }

    );

  },

  loadSlides: function (event) {

    $.getJSON(

      "/api/controller/live/text",

      function (data, status) {

        OpenLP.currentSlides = data.results.slides;

        OpenLP.currentSlide = 0;

        $.each(data.results.slides, function(idx, slide) {

          if (slide["selected"])

            OpenLP.currentSlide = idx;

        })

        OpenLP.loadService();

      }

    );

  },

  updateSlide: function() {

    // Show the current slide on top. Any trailing slides for the same verse

    // are shown too underneath in grey.

    // Then leave a blank line between following verses

    var slide = OpenLP.currentSlides[OpenLP.currentSlide];

    var text = "";

    // use title if available

    if (slide["title"]) {

        text = slide["title"];

    } else {

        text = slide["text"];

    }

    // use thumbnail if available

    if (slide["img"]) {

        text += "<br /><img src='" + slide["img"].replace("/thumbnails/", "/thumbnails320x240/") + "'><br />";

    }

    // use slide_notes if available

    if (slide["slide_notes"]) {

        text += '<br />' + slide["slide_notes"];

    }

    // for OBS, I like replacing new lines by forward slashes

    text = text.replace(/\n/g, "<br>");

//    text = text.replace(/\n/g, " &nbsp; ◇ &nbsp;");

    $("#currentslide").html(text);


    OpenLP.obsRemote();

  },

  pollServer: function () {

    $.getJSON(

      "/api/poll",  // To see all use http:/127.0.0.1:4316/api/poll

      function (data, status) {

        if (OpenLP.currentItem != data.results.item ||

            OpenLP.currentService != data.results.service) {

          OpenLP.currentItem = data.results.item;

          OpenLP.currentService = data.results.service;

          OpenLP.loadSlides();

          // also triggers loadService(), which triggers updateSlide()

        }

        else if (OpenLP.currentSlide != data.results.slide) {

          OpenLP.currentSlide = parseInt(data.results.slide, 10);

          OpenLP.updateSlide();

        }

        //inserted for being able to control OBS by display style

        if(OpenLP.currentlyShowing != "blank" && data.results.blank) {

          OpenLP.currentlyShowing = "blank";

          OpenLP.updateSlide();

        }

        else if(OpenLP.currentlyShowing != "theme" && data.results.theme) {

          OpenLP.currentlyShowing = "theme";

          OpenLP.updateSlide();

        }

        else if(OpenLP.currentlyShowing != "display" && data.results.display) {

          OpenLP.currentlyShowing = "display";

          OpenLP.updateSlide();

        }

        else if(OpenLP.currentlyShowing != "slides" && 

                !data.results.blank && 

                !data.results.theme && 

                !data.results.display) {

          OpenLP.currentlyShowing = "slides";

          OpenLP.updateSlide();

        }

      }

    );

  },

  obsRemote: function () {

    /*

    A list of all the information that could be useful to remote control OBS:

    pollServer() evaluates /api/poll, provides

    - OpenLP.currentlyShowing: blank|theme|display|slides

    loadService() evaluates /api/poll, provides

    - OpenLP.currentPlugin

    - OpenLP.currentTitle

    loadSlides() evaluates /api/controller/live/text, provides

    - OpenLP.currentSlides[OpenLP.currentSlide]["text"]

    - OpenLP.currentSlides[OpenLP.currentSlide]["html"]

    - OpenLP.currentSlides[OpenLP.currentSlide]["tag"]


    obs-websocket-js documentation at:

    https://github.com/haganbmj/obs-websocket-js


    obs-websocket controls can be found at:

    https://github.com/Palakis/obs-websocket/blob/4.x-current/docs/generated/protocol.md

    */

    

    OpenLP.obsHandler = new OBSWebSocket();



    OpenLP.obsHandler.connect({address: 'localhost:4444', password: ''}).then(() => {


      // Override scenes with scenechange

      

      // Example 1a: use an item with the title "scenechange:altar" to switch to OBS scene "altar"

      if(preg = /scenechange:(.+)/i.exec(OpenLP.currentTitle)) {

        OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': preg[1]});

      }

      // Example 1b: put "scenechange:altar" into the notes of an item

      else if(preg = /scenechange:(.+)/i.exec(OpenLP.currentNotes)) {

        OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': preg[1]});

      }


      // Automatic scene changes only if the scene starts with "auto", otherwise ignore

      else {

        OpenLP.obsHandler.send('GetCurrentScene').then(data => {

          console.log(data['name'].substring(0,4) === 'auto');

          // Check if it is in auto scene

          if (data['name'].substring(0,4) === 'auto') {

            // If OpenLP is blank, then switch to "autoCamera"

            if(OpenLP.currentlyShowing == 'blank' ) {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoCamera'});

            }

            // If OpenLP is theme, then switch to "autoCamera"

            else if(OpenLP.currentlyShowing == 'theme' ) {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoCamera'});

            }

            // If OpenLP is hidden (i.e. display) then switch to "autoMirror"

            else if(OpenLP.currentlyShowing == 'display' ) {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoMirror'});

            }

            // If OpenLP is showing a song, then change scene to "autoLyrics"

            else if(OpenLP.currentPlugin == 'songs') {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoLyrics'});

            }

            // If OpenLP is showing custom text slides, then switch to "autoLyrics"

            else if(OpenLP.currentPlugin == 'custom') {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoLyrics'});

            }

            // If OpenLP is showing images, then switch to "autoMirror"

            else if(OpenLP.currentPlugin == 'images') {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoMirror'});

            }

            // If OpenLP is showing media, then switch to "autoMirror"

            else if(OpenLP.currentPlugin == 'media') {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoMirror'});

            }

            // If OpenLP is showing presentations, then switch to "autoMirror"

            else if(OpenLP.currentPlugin == 'presentations') {

              OpenLP.obsHandler.send('SetCurrentScene', {'scene-name': 'autoMirror'});

            }

  

          }

        });

      // Example 2: toggle visibility of OBS scene item "lyrics",

      // depending on if the slide your showing is a song or not

  //    OpenLP.obsHandler.send('SetSceneItemProperties', {'item': 'lyrics', 'visible': (OpenLP.currentPlugin == "songs")});

      }

    });

  }

}

$.ajaxSetup({ cache: false });

setInterval("OpenLP.pollServer();", 50);

OpenLP.pollServer();

OBS configuration SETUP

The following configuration is already part of the portable downloads below, but are included for reference.

OpenLP Web Source:
http://127.0.01:4316/stage/obs

Browser Dock:
http://127.0.01:4316/

Here is an older video showing an example of a previous version of this integration, showing how this is set up in OBS.

Downloads

OpenLP version: 2.4.6

OBS version: 27.2.4

OBS Plugins included: