How to Write Python Scripts that Run in OBS
Prerequisites
The prerequisite for reading this article is that you have already mastered how to run Python scripts in OBS, you can check out the article How to Configure OBS to Run Python Scripts for information on that.
Python Script Functions Exported to OBS
When a Python script has functions with specific names and parameters, OBS will find and use those functions to achieve certain effects, such as displaying a piece of text in OBS that explains what the script does. This connection between Python scripts and OBS is officially known as Python Script Function Exports.
Exporting Python script functions to OBS is optional
Exporting Python script functions to OBS is an optional behavior; Python scripts you write can have no functions exported, and this will not affect OBS’s ability to execute the script.
Display Python Script Description in OBS via the script_description Function
Every Python script that is successfully loaded into OBS will have a description in the OBS Scripts Window. By defining a function called script_description
in your Python script, you can set the description text for that script, and of course, script_description
should return a string.
OBS supports the inclusion of whitespace characters in Python script descriptions
The string returned by the script_description
function can contain certain whitespace characters, e.g., tabs (\t
), and they can be displayed normally in the Scripts Window of OBS.
# Import the obspython module
import obspython as obs
def script_description():
return 'This is a simple but ineffective script\nAuthor:\toops\nVersion:\t0.1\nContact:\txxx'
Display Python Script Properties in OBS via the script_properties Function
The script_description
function is very important when you want Python scripts to be interactive with OBS users, and it needs to return a Property Set object that contains information about the script’s relevant properties. OBS will create a series of controls in the Scripts Window based on the Property Set object returned by script_description
, such as textboxes, buttons, checkboxes, and so on. With these controls, OBS users can modify and adjust the script’s properties to change the functionality of the Python script.
What are the Python Script Properties in OBS?
Python Script Properties in OBS can refer either to the controls that appear in the Scripts Window or to the objects (Script Property objects) used to create them. Each Script Property corresponds to a Script Setting Item that stores the value of the property, except for button controls.
What are the Python Script Settings in OBS?
Python Script Settings are stored in an OBS Data Settings object, which reads and writes some data in a manner similar to key-value pairs. There is no official term like “Python Script Settings” in the official OBS documentation, so we’ll use it for convenience. An item in Python Script Settings does not necessarily correspond to a Script Property, and although you can influence the functionality of Python scripts based on Script Settings, they’re not visible to OBS users.
For different Scene Collections, OBS will either save the Python Script Settings locally in some form at the appropriate time, or reverse the process, so that the Script Settings are made permanent. When a Python script file is removed from the OBS’s Scripts Window, the corresponding Script Settings are also deleted locally.
In the function script_properties
, we create a Property Set object using obs_properties_create
and add a Property object corresponding to the numberbox to the Property Set with obs_properties_add_text
.
def script_properties():
# Create a Property Set object
props = obs.obs_properties_create()
# Add a Script Property object that corresponds to the numberbox for indicating hours
obs.obs_properties_add_int(props, 'hours', 'Hours:', 2, 5, 1)
return props
Perform Tasks when Loading or Unloading Python Scripts in OBS via the script_load, script_unload Functions
If you want to perform certain tasks, such as reading or writing data from or to a file, when a Python script is loaded or unloaded by OBS, then you can define the functions script_load
, script_unload
in your Python script.
script_load(settings)
- settings parameter
The
settings
parameter is the Script Settings object corresponding to the Python script.
When does OBS load or unload Python scripts?
Python scripts will be loaded when you add a script to the OBS’s Scripts Window, reload a script, restore defaults, or when OBS starts. Python scripts will be unloaded when you remove a script from the OBS’s Scripts Window, reload a script, before restoring defaults, or when OBS is closed.
In the code below, we record and display the last stop time of the script via the functions script_load
and script_unload
. In fact, this is ineffective when you close OBS directly, for reasons that will be explained later.
# The data variable represents the Script Settings
data = None
def script_load(settings):
global data
data = settings
# Read the Script Setting Item closed_time, which is the stop time of the script
closed_time = obs.obs_data_get_string(data, 'closed_time')
if closed_time:
obs.script_log(obs.LOG_INFO, f'The script was last stopped at {closed_time}')
def script_unload():
# Write the current time to the Script Setting Item closed_time as the stop time of the script
from datetime import datetime
obs.obs_data_set_string(data, 'closed_time', datetime.now().ctime())
[exports.py] The script was last stopped at Mon Mar 4 07:12:37 2024
The obs_data_get_string, obs_data_set_string functions of the OBS obspython module
The obspython
module’s obs_data_get_string
and obs_data_set_string
functions are used to perform read and write operations on Data Items of string type in the OBS Data Settings object.
Similar functions include obs_data_get_int
, obs_data_set_int
, etc.
Perform Tasks after OBS Users Modify Python Script Properties via the script_update Function
If you want to perform certain tasks after an OBS user modifies Python Script Properties (via the Scripts Window), e.g., adjusting the implemented functionality according to the modified Script Properties, then you can define the function script_update
in the Python script, which is executed at a point in time between the script_load
function and the script_unload
function.
It should be noted that any modification of the Script Properties will result in the call of the script_update
function. If you are only monitoring changes to one Script Property, then you can use the obs_property_set_modified_callback
function of the obspython
module.
script_update(settings)
- settings parameter
The
settings
parameter is the Script Settings object corresponding to the Python script.
When does OBS call the script_update function in a Python script?
In addition to being called after an OBS user modifies Python Script Properties, the script_update
function is also called when adding a script, reloading a script, restoring defaults, or when OBS is started.
The values displayed by the controls in the OBS Script Window may not be the same as the values corresponding to the Python Script Setting Items
Until an OBS user makes a valid edit to a control in the Scripts Window, the value displayed by the control will not be synchronized to the corresponding Python Script Setting Item. This can be confusing because the value that the OBS user sees from the control may not be the same as the value you read from the Python Script Settings. Once the window control corresponding to a Script Property has been validly edited, the value in the corresponding control can be safely read from the Python Script Settings.
To avoid the above inconsistencies, you can define the script_defaults
function and set the default values for the controls’ corresponding Script Setting Items.
Previously, in the function script_properties
, we added a numberbox with a minimum value of 2
, but reading its corresponding Python Script Setting Item could result in 0
if the numberbox has not been validly edited.
def script_update(settings):
# Read the Script Setting Item hours and display it
hours = obs.obs_data_get_int(settings, 'hours')
obs.script_log(obs.LOG_INFO, f'The current hours are {hours}')
[exports.py] The current hours are 0
Write Data to Python Script Settings when OBS is Closed via the script_save Function
The script_save
function in Python scripts is called when OBS is closed, at which point some important data can be written to the Script Settings so that they can be read the next time OBS is started.
script_save(settings)
- settings parameter
The
settings
parameter is the Script Settings object corresponding to the Python script.
Script Settings written via the script_unload function when OBS is closed are not stored locally
Although OBS calls the script_unload
function for Python scripts when it is closed, writes to Script Setting Items may be “invalidated” because they will not be stored locally by OBS, unlike clicking the Reload Scripts Button in the Scripts Window.
The best way to save important data is to define the function script_save
rather than script_unload
, although the previous example demonstrated the opposite.
Instead of the script_unload
function, we use the script_save
function, which causes the OBS close time to be considered as the script’s stop time, and the time of other user actions (e.g., clicking the Reload Scripts Button) will no longer be considered as the script’s stop time.
def script_save(settings):
# Write the current time to the Script Setting Item closed_time as the stop time of the script
from datetime import datetime
obs.obs_data_set_string(settings, 'closed_time', datetime.now().ctime())
Specify Default Values for Python Script Properties Using Python Script Settings
In the official obspython
module provided with OBS, you can’t specify default values for Python Script Properties directly via parameters, although some functions that add Script Properties can achieve an approximate effect. To set default values for controls in the Scripts Window, you should define the function script_defaults
in the Python script and specify default values for the Script Setting Items corresponding to the Script Properties in that function.
script_defaults(settings)
- settings parameter
The
settings
parameter is the Script Settings object corresponding to the Python script.
The default value of an OBS Python Script Setting Item is used only when it has no specific value
It’s important to note that once a Python Script Setting Item has a specific value, its default value is no longer used, which happens after an OBS user edits a control, or after you assign a value to a Script Setting Item via a function.
When you click the Defaults Button in the Scripts Window of OBS, the default values of the Python Script Setting Items will come back to work because the specific values of the Script Setting Items have been cleared.
In the function script_defaults
, we specify the default value of the Script Setting Item hours
as 3
, which will cause the numberbox in the Scripts Window to display 3
by default. If the numberbox has been edited before, then you will need to click the Defaults Button to see the effect.
def script_defaults(settings):
# Set the default value of the Setting Item hours to 3
obs.obs_data_set_default_int(settings, 'hours', 3)
The obs_data_set_default_int function of the OBS obspython module
The obs_data_set_default_int
function of the obspython
module is used to set default values for Data Items of integer type in the OBS Data Settings object.
Perform Tasks at Each Frame Drawn by OBS via the Python Script's script_tick Function
If you want to perform certain tasks as OBS draws each frame, then you can define the function script_tick
in your Python script.
script_tick(seconds)
- seconds parameter
The
seconds
parameter is the number of seconds elapsed from the previous frame to this one.
Using the script_tick function in Python scripts may cause performance issues for OBS
OBS calls the script_tick
function more frequently, so it is not a good idea to use this function for complex tasks, and OBS may not be able to respond to the user after a long run if you keep outputting information to the Script Log Window via the script_log
function.
The obspython
module of OBS provides some additional functions for timers, which can be used to avoid problems caused by the script_tick
function.
def script_tick(seconds):
obs.script_log(obs.LOG_INFO, f'{seconds} OBS is about to become unresponsive!!!')
Get the Directory where the Python Script is Located via the script_path Function
For added Python scripts, OBS defines a function called script_path
(not part of the obspython
module) that can be used to get the directory where the current script is located.
The difference between the script_path function defined by OBS for scripts and the __file__ attribute of Python modules
The __file__
attribute indicates the file path of the Python module, while the script_path
function returns the path to the folder where the script file is located.
We adjust the previous code to call the script_path
function in script_load
and display the returned directory.
def script_load(settings):
# …
obs.script_log(obs.LOG_INFO, script_path())
# Output in Windows
[exports.py] …/scripts/
Add or Remove Script Timers for OBS via the timer_add, timer_remove Functions
With the timer_add
and timer_remove
functions of the obspython
module, you can add or remove Script Timers for OBS. Script Timers will repeatedly call the given callback function or method at specified intervals, unlike the script_tick
function.
Once the timer_add
function has been used, the added Script Timer will start working. If you want the Script Timer to stop, you can remove it with the timer_remove
function or call the remove_current_callback
function of the obspython
module in the callback function or method.
timer_add(callback, milliseconds)
timer_remove(callback)
- callback parameter
The
callback
parameter is the function or method that is called back by the Script Timer, and in thetimer_remove
function, the Script Timer corresponding to thecallback
will be removed.- milliseconds parameter
The
milliseconds
parameter is the time interval in milliseconds at which the timer will be triggered, and accepts a value of integer type.
The timer_remove function of the obspython module cannot remove the Script Timer corresponding to the instance method
If a Python function in a module is used as a callback target, timer_add
and timer_remove
will work correctly, and if an instance method of a Python class is used as a callback target, then timer_remove
may fail and its corresponding Script Timer will not be removed.
In the code below, welcome
is the callback function of the Script Timer, and we use remove_current_callback
to make this function be called only once.
# Script Timer callback function welcome
def welcome():
obs.script_log(obs.LOG_INFO, 'This is a callback function that is only called once')
# Remove the Script Timer corresponding to welcome
obs.remove_current_callback()
# Add a Script Timer with a 3-second interval
obs.timer_add(welcome, 3000)
[exports.py] This is a callback function that is only called once