### Register and Save OBS Hotkeys with Callback Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Defines a `Hotkey` class to manage OBS hotkeys, including registration, loading, and saving. The example shows how to create multiple hotkey instances and associate them with different callbacks, loading and saving them during script load and save events. ```python class Hotkey: def __init__(self, callback, obs_settings, _id): self.obs_data = obs_settings self.hotkey_id = S.OBS_INVALID_HOTKEY_ID self.hotkey_saved_key = None self.callback = callback self._id = _id self.load_hotkey() self.register_hotkey() self.save_hotkey() class h: htk_copy = None # this attribute will hold instance of Hotkey h1 = h() h2 = h() def script_load(settings): h1.htk_copy = Hotkey(cb1, settings, "h1_id") h2.htk_copy = Hotkey(cb2, settings, "h2_id") def script_save(settings): h1.htk_copy.save_hotkey() h2.htk_copy.save_hotkey() ``` -------------------------------- ### Setup Volmeter with Callback in Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt This snippet demonstrates how to set up a volume meter in OBS Studio using Python. It defines a callback function to capture audio peak data and attaches it to a specified source. It utilizes ctypes for direct FFI access to OBS functions not exposed through the obspython module. ```python from ctypes import POINTER, Source, Volmeter, c_char_p, c_int, c_bool, c_void_p # Assume wrap, volmeter_callback_t are defined elsewhere and imported # obs_get_source_by_name = wrap("obs_get_source_by_name", POINTER(Source), [c_char_p]) # obs_source_release = wrap("obs_source_release", None, [POINTER(Source)]) # obs_volmeter_create = wrap("obs_volmeter_create", POINTER(Volmeter), [c_int]) # obs_volmeter_destroy = wrap("obs_volmeter_destroy", None, [POINTER(Volmeter)]) # obs_volmeter_add_callback = wrap("obs_volmeter_add_callback", None, [POINTER(Volmeter), volmeter_callback_t, c_void_p]) # obs_volmeter_attach_source = wrap("obs_volmeter_attach_source", c_bool, [POINTER(Volmeter), POINTER(Source)]) OBS_FADER_LOG = 2 current_db = -100.0 volmeter = None @volmeter_callback_t def volmeter_callback(data, mag, peak, input_peak): global current_db current_db = float(peak[0]) def setup_volmeter(source_name): global volmeter source = obs_get_source_by_name(source_name.encode("utf-8")) volmeter = obs_volmeter_create(OBS_FADER_LOG) obs_volmeter_add_callback(volmeter, volmeter_callback, None) obs_volmeter_attach_source(volmeter, source) obs_source_release(source) # Note: On Linux, start OBS with: LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpython3.x.so obs ``` -------------------------------- ### Capture Raw Frames using Python (debugpy) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md An example of setting up remote debugging for OBS Studio using Python's `debugpy`. This allows you to attach a debugger like VS Code to the OBS process to inspect variables and step through code. Ensure `debugpy` is installed and a breakpoint is set. ```python import debugpy # Start listening for debugger connections debugpy.listen(("localhost", 5678)) print("Waiting for debugger attach...") debugpy.wait_for_client() print("Debugger attached!") # Place your breakpoint here debugpy.breakpoint() # Your script logic here... ``` -------------------------------- ### Modify OBS Property Behavior with Callbacks Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Shows how to set a callback function for a property, which is executed when the property's value is modified. This allows for dynamic updates to other properties or script logic based on user input. The example uses a button press to update its own description. ```python def callback(props, prop, *args, **kwargs): # pass settings implicitly p = S.obs_properties_get(props, "button") n = next(counter) S.obs_property_set_description(p, f"refresh pressed {n} times") return True def script_properties(): props = S.obs_properties_create() b = S.obs_properties_add_button( props, "button", "refresh pressed 0 times", refresh_pressed ) S.obs_property_set_modified_callback(b, callback) return props ``` -------------------------------- ### Add Filter to Source Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Adds a filter to an existing source. Filters are treated as sources themselves and require specific settings. This example adds a 'color_filter' with a specified opacity. ```python S.obs_data_set_int(settings, "opacity", 50) source_color = S.obs_source_create_private( "color_filter", "opacity to 50", settings ) S.obs_source_filter_add(source, source_color) ``` -------------------------------- ### Get Current Profile Settings via FFI using Python Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Explains how to retrieve current OBS profile settings using FFI in Python. It wraps functions like `obs_frontend_get_profile_config`, `config_get_string`, and `config_num_sections` to access configuration data, such as file paths from the 'SimpleOutput' section. ```python wrap("obs_frontend_get_profile_config", POINTER(Config), use_lib=G.obsffi_front) # const char *config_get_string(config_t *config, const char *section, # const char *name) wrap("config_get_string", c_char_p, argtypes=[POINTER(Config), c_char_p, c_char_p]) wrap("config_num_sections", c_size_t, argtypes=[POINTER(Config)]) wrap("config_get_section", c_char_p, argtypes=[POINTER(Config), c_size_t]) def output_to_stdout(): cfg = G.obs_frontend_get_profile_config() e = lambda x: x.encode("utf-8") s = G.config_get_string(cfg, e("SimpleOutput"), e("FilePath")) l = G.config_num_sections(cfg) for i in range(l): tag = G.config_get_section(cfg, c_size_t(i)) print(s, l) ``` -------------------------------- ### Access Source Volume Level via FFI using Python Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Demonstrates accessing audio source volume levels using Python's `ctypes` for Foreign Function Interface (FFI). It requires preloading `libpython` and defines a callback function to capture peak volume data. Note: This method might require specific setup like `LD_PRELOAD` on Linux. ```python volmeter_callback_t = CFUNCTYPE( None, c_void_p, POINTER(c_float), POINTER(c_float), POINTER(c_float) ) ... wrap( "obs_volmeter_add_callback", None, argtypes=[POINTER(Volmeter), volmeter_callback_t, c_void_p], ) ... @volmeter_callback_t def volmeter_callback(data, mag, peak, input): G.noise = float(peak[0]) ``` -------------------------------- ### Get and Reorder Scene Items Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Retrieves the order of scene items in the current scene and provides functionality to reorder them. The `get_order` function lists items with their index and name, while `reorder` demonstrates swapping the positions of two items. ```python def get_order(scene_items=None): order = list() for i, s in enumerate(scene_items): source = S.obs_sceneitem_get_source(s) name = S.obs_source_get_name(source) order.append({"index": i, "name": name, "scene_item": s}) return order def reorder(): current_scene = S.obs_frontend_get_current_scene() with scene_ar(current_scene) as scene: with scene_enum(scene) as scene_items: order = get_order(scene_items) # change second index with pre last order[1]["index"], order[-2]["index"] = ( order[-2]["index"], order[1]["index"], ) for s in sorted(order, key=lambda i: i["index"]): S.obs_sceneitem_set_order_position(s["scene_item"], s["index"]) ``` -------------------------------- ### Export OBS libobs DLL Symbols using dumpbin (Windows Command) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md This Windows command-line instruction uses the `dumpbin` utility to export symbols from the OBS Studio DLL (`obs.dll`). This is helpful for understanding the functions available for interaction with OBS via tools like `ctypes` in Python. Ensure the path to `obs.dll` is correct for your OBS Studio installation. ```cmd .\dumpbin /exports "C:\\Program Files\\obs-studio\\bin\\64bit\\obs.dll" ``` -------------------------------- ### Save Settings to JSON File using Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Exports script settings to a JSON file for backup or sharing. It uses the `obspython` library to get settings data and `pathlib` to manage file paths. The function handles potential errors during file writing. ```python import obspython as S from pathlib import Path class Settings: data = None def save_settings_to_file(): if not Settings.data: return script_path = Path(__file__).absolute() output_file = script_path.parent / "saved_settings.json" try: content = S.obs_data_get_json(Settings.data) with open(output_file, "w") as f: f.write(content) print(f"Settings saved to {output_file}") except Exception as e: print(f"Error saving settings: {e}") def script_update(settings): Settings.data = settings def script_properties(): props = S.obs_properties_create() S.obs_properties_add_text(props, "custom_text", "Text:", S.OBS_TEXT_DEFAULT) S.obs_properties_add_int(props, "custom_int", "Number:", 1, 100, 1) S.obs_properties_add_button(props, "save", "Save to File", lambda p, pr: save_settings_to_file()) return props ``` -------------------------------- ### Conditionally Show Text Input Based on Number Input (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md This Python script demonstrates how to dynamically control the visibility of a text input field based on the value of an integer input. It uses OBS Studio's scripting API to get property values and set property visibility. The `callback` function is triggered when the 'Number' property is modified. ```python def callback(props, prop, settings): _number = S.obs_data_get_int(settings, "_int") _text_value = S.obs_data_get_string(settings, "_text") text_property = S.obs_properties_get(props, "_text") if _number > 50: eg.data = _text_value + str(_number) S.obs_property_set_visible(text_property, True) return True else: eg.data = "" S.obs_property_set_visible(text_property, False) return True def script_properties(): # ui ... number = S.obs_properties_add_int(props, "_int", "Number", 1, 100, 1) text_value = S.obs_properties_add_text( props, "_text", "Additional input:", S.OBS_TEXT_DEFAULT ) S.obs_property_set_visible(text_value, False) S.obs_property_set_modified_callback(number, callback) ... ``` -------------------------------- ### Load OBS Hotkeys from JSON Settings Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Demonstrates how to load OBS hotkeys dynamically from JSON settings. It parses a JSON string containing hotkey configurations and registers them with OBS, associating them with a specified callback function. ```python ID = "htk_id" JSON_DATA = '{"%s":[{"key":"OBS_KEY_1"}]}' % ID def on_obs_key_1(pressed): if pressed: raise Exception("hotkey 1 pressed") def script_load(settings): s = S.obs_data_create_from_json(JSON_DATA) a = S.obs_data_get_array(s, ID) h = S.obs_hotkey_register_frontend(ID, ID, on_obs_key_1) S.obs_hotkey_load(h, a) ``` -------------------------------- ### Creating and Adding Sources Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Demonstrates how to create new sources (e.g., text, browser) with specific settings and add them to the current scene. ```APIDOC ## Creating and Adding Sources Sources are created with settings data and added to scenes. The source type is specified by an identifier string like "text_gdiplus", "browser_source", or "ffmpeg_source". ### Method ```python S.obs_source_create_private(id, name, settings) ``` ### Parameters #### Path Parameters - **id** (string) - Required - The identifier string for the source type (e.g., "text_gdiplus"). - **name** (string) - Required - The internal name for the source. - **settings** (obs_data_t) - Required - A data object containing the source's settings. ### Request Example ```python import obspython as S def create_text_source(): # Get current scene current_scene = S.obs_frontend_get_current_scene() scene = S.obs_scene_from_source(current_scene) # Create settings for the source settings = S.obs_data_create() S.obs_data_set_string(settings, "text", "Hello from Python!") # Create source (text_gdiplus for Windows, text_ft2_source for Linux/Mac) source = S.obs_source_create_private("text_gdiplus", "my_text_source", settings) # Add source to scene S.obs_scene_add(scene, source) # Release resources S.obs_scene_release(scene) S.obs_data_release(settings) S.obs_source_release(source) # Common source type identifiers: # browser_source, color_source, monitor_capture, game_capture # slideshow, image_source, ffmpeg_source, text_gdiplus, window_capture ``` ### Response #### Success Response (Source Object) - **source** (obs_source_t) - A reference to the newly created source object. #### Response Example (No direct response example, but the Python code shows the creation process.) ``` -------------------------------- ### Connect to Source Signals (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Illustrates connecting a Python callback function to source-specific signals, such as 'show'. The callback receives calldata, allowing extraction of the source object and its name when the 'show' signal is emitted. ```python import obspython as S def callback(calldata): source = S.calldata_source(calldata,"source") print("on source show",S.obs_source_get_name(source)) sh = S.obs_source_get_signal_handler(some_source) S.signal_handler_connect(sh,"show",callback) ``` -------------------------------- ### Volume Metering via FFI using Python and ctypes Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Accesses real-time audio levels using ctypes FFI to wrap native OBS functions. This snippet demonstrates loading the OBS native library and defining function prototypes for interacting with volume metering functionalities. It sets up structures and callback types for handling audio data. ```python import obspython as S from ctypes import * from ctypes.util import find_library # Load native library obsffi = CDLL(find_library("obs")) def wrap(funcname, restype, argtypes): func = getattr(obsffi, funcname) func.restype = restype func.argtypes = argtypes return func class Source(Structure): pass class Volmeter(Structure): pass volmeter_callback_t = CFUNCTYPE(None, c_void_p, POINTER(c_float), POINTER(c_float), POINTER(c_float)) ``` -------------------------------- ### Connect to OBS Core and Scene Signals Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Demonstrates how to connect to OBS signals for real-time notifications about source and scene changes. It includes functions to connect to core signals like 'source_create' and scene signals like 'item_add'. Requires the 'obspython' library. ```python import obspython as S def on_source_create(calldata): source = S.calldata_source(calldata, "source") print(f"Source created: {S.obs_source_get_name(source)}") def on_item_add(calldata): scene_item = S.calldata_sceneitem(calldata, "item") scene = S.obs_sceneitem_get_scene(scene_item) source = S.obs_sceneitem_get_source(scene_item) scene_name = S.obs_source_get_name(S.obs_scene_get_source(scene)) item_name = S.obs_source_get_name(source) print(f"Item {item_name} added to scene {scene_name}") def connect_core_signals(): # Core signals: source_create, source_destroy, source_remove, source_activate, etc. sh = S.obs_get_signal_handler() S.signal_handler_connect(sh, "source_create", on_source_create) def connect_scene_signals(): # Scene signals: item_add, item_remove, reorder, item_visible, item_transform source = S.obs_frontend_get_current_scene() sh = S.obs_source_get_signal_handler(source) S.signal_handler_connect(sh, "item_add", on_item_add) S.obs_source_release(source) def script_load(settings): S.obs_frontend_add_event_callback( lambda e: connect_scene_signals() if e == S.OBS_FRONTEND_EVENT_FINISHED_LOADING else None ) ``` -------------------------------- ### Private Data Communication Between Scripts using Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Enables data sharing between multiple scripts using OBS's private data store. It includes functions to write data to and read data from this store. The example demonstrates continuous communication using timers. ```python import obspython as S from contextlib import contextmanager # Writer script def send_to_private_data(data_type, field, value): settings = S.obs_data_create() setter = getattr(S, f"obs_data_set_{data_type}") setter(settings, field, value) S.obs_apply_private_data(settings) S.obs_data_release(settings) def write_shared_data(): send_to_private_data("string", "__shared_message__", "Hello from script A!") send_to_private_data("int", "__shared_counter__", 42) # Reader script @contextmanager def read_private_data(data_type, field): settings = S.obs_get_private_data() getter = getattr(S, f"obs_data_get_{data_type}") try: yield getter(settings, field) finally: S.obs_data_release(settings) def read_shared_data(): with read_private_data("string", "__shared_message__") as message: print(f"Message: {message}") with read_private_data("int", "__shared_counter__") as counter: print(f"Counter: {counter}") # Continuous communication S.timer_add(write_shared_data, 1000) S.timer_add(read_shared_data, 1000) ``` -------------------------------- ### Adding Filters to Sources Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Illustrates how to create and attach filters (like color correction or chroma key) to existing sources using `obs_source_filter_add`. ```APIDOC ## Adding Filters to Sources Filters are special sources that process other sources. They are created and attached using `obs_source_filter_add`. ### Method ```python S.obs_source_filter_add(source, filter) ``` ### Parameters #### Path Parameters - **source** (obs_source_t) - Required - The source to which the filter will be added. - **filter** (obs_source_t) - Required - The filter source object to add. ### Request Example ```python import obspython as S def add_color_filter(source_name, opacity=50): source = S.obs_get_source_by_name(source_name) if source: settings = S.obs_data_create() S.obs_data_set_int(settings, "opacity", opacity) # Create filter (filters are also sources) color_filter = S.obs_source_create_private( "color_filter", "opacity_filter", settings ) # Add filter to source S.obs_source_filter_add(source, color_filter) S.obs_source_release(source) S.obs_data_release(settings) S.obs_source_release(color_filter) # Common filter identifiers: # color_filter, chroma_key_filter, mask_filter, gain_filter # noise_suppress_filter, compressor_filter, scroll_filter ``` ### Response (This operation modifies the source by adding a filter and does not return a specific value.) ``` -------------------------------- ### Play Sound File Globally in OBS Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Creates and configures a private media source in OBS to play a specified sound file ('alert.mp3'). It sets the media source to use a local file and enables monitoring and output for the source. ```python def play_sound(): ... mediaSource = S.obs_source_create_private( "ffmpeg_source", "Global Media Source", None ) s = S.obs_data_create() S.obs_data_set_string(s, "local_file", script_path() + "alert.mp3") S.obs_source_update(mediaSource, s) S.obs_source_set_monitoring_type( mediaSource, S.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT ) ... ``` -------------------------------- ### Manage Thread for Status Updates in OBS Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Implements a background thread that continuously updates a status based on whether it's paused or not. It uses `sleep` for control and prints the status every 500ms. The thread is started upon script execution and can be toggled on/off via a hotkey. ```python def callback(pressed): if pressed: toggle_thread() def busy_thread(): while True: if not data.thread_paused: sleep(0.02) data.status = "active" # print to stdoud crashes OBS on exit else: sleep(0.5) data.status = "inactive" print('Press the "~" to toggle on/off') hook("OBS_KEY_ASCIITILDE", "id_", callback) S.timer_add(lambda: print(data.status), 500) t = threading.Thread(target=busy_thread) t.start() ``` -------------------------------- ### Moving and Positioning Sources Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Explains how to retrieve and set the position of scene items using `obs_sceneitem_get_pos` and `obs_sceneitem_set_pos`. ```APIDOC ## Moving and Positioning Sources Scene items can be repositioned using `obs_sceneitem_get_pos` and `obs_sceneitem_set_pos` with a vec2 structure. ### Method ```python S.obs_sceneitem_set_pos(item, position) ``` ### Parameters #### Path Parameters - **item** (obs_sceneitem_t) - Required - The scene item to position. - **position** (vec2) - Required - A `vec2` structure containing the new X and Y coordinates. ### Request Example ```python import obspython as S class SourceMover: def __init__(self): self.location = S.vec2() def move_source(self, source_name, dx=10, dy=10): current_scene = S.obs_frontend_get_current_scene() scene = S.obs_scene_from_source(current_scene) scene_item = S.obs_scene_find_source(scene, source_name) if scene_item: # Get current position S.obs_sceneitem_get_pos(scene_item, self.location) # Update position self.location.x += dx self.location.y += dy # Apply new position S.obs_sceneitem_set_pos(scene_item, self.location) S.obs_scene_release(scene) mover = SourceMover() mover.move_source("my_text_source", dx=50, dy=25) ``` ### Response (This operation modifies the scene item's state and does not return a specific value, but updates the item in place.) ``` -------------------------------- ### Connect to Core Signals (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Demonstrates how to connect a Python callback function to OBS core signals, such as 'source_create'. The callback receives calldata, from which source information can be extracted and processed. ```python import obspython as S def callback(calldata): source = S.calldata_source(calldata,"source") print(S.obs_source_get_name(source)) sh = S.obs_get_signal_handler() S.signal_handler_connect(sh,"source_create",callback) ``` -------------------------------- ### Duplicating Sources Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Details on how to duplicate an existing source, preserving its transform and crop settings, and adding it to another scene. ```APIDOC ## Duplicating Sources Sources can be duplicated with their transform and crop settings preserved, then added to any scene. ### Method ```python S.obs_source_duplicate(source, new_name, enable) ``` ### Parameters #### Path Parameters - **source** (obs_source_t) - Required - The source object to duplicate. - **new_name** (string) - Required - The name for the new duplicated source. - **enable** (boolean) - Required - Whether to enable the duplicated source upon creation. ### Request Example ```python import obspython as S def duplicate_source(source_name, target_scene_name): current_scene = S.obs_scene_from_source(S.obs_frontend_get_current_scene()) scene_item = S.obs_scene_find_source(current_scene, source_name) # Get transform and crop info info = S.obs_transform_info() crop = S.obs_sceneitem_crop() S.obs_sceneitem_get_info(scene_item, info) S.obs_sceneitem_get_crop(scene_item, crop) # Duplicate the source original = S.obs_sceneitem_get_source(scene_item) duplicated = S.obs_source_duplicate(original, "duplicate_" + source_name, False) # Find target scene and add duplicated source scenes = S.obs_frontend_get_scenes() for scene in scenes: name = S.obs_source_get_name(scene) if name == target_scene_name: target = S.obs_scene_from_source(scene) new_item = S.obs_scene_add(target, duplicated) S.obs_sceneitem_set_info(new_item, info) S.obs_sceneitem_set_crop(new_item, crop) S.obs_scene_release(target) S.obs_source_release(duplicated) S.source_list_release(scenes) S.obs_scene_release(current_scene) ``` ### Response #### Success Response (Duplicated Source Object) - **duplicated** (obs_source_t) - A reference to the newly created duplicated source object. ``` -------------------------------- ### Add Source to Scene Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Creates a new source with specified settings and adds it to the current scene. Requires a settings dictionary and the scene object. ```python S.obs_data_set_string(settings, "text", "The quick brown fox jumps over the lazy dog") source = S.obs_source_create_private("text_gdiplus", "test_py", settings) S.obs_scene_add(scene, source) ``` -------------------------------- ### Print Source Settings and Filter Names (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md This Python script retrieves and prints the settings, private settings, and default settings for a given source in JSON format. It also iterates through a list of filters associated with the source, extracting and printing the name of each filter. This is useful for debugging and understanding the configuration of sources and filters. ```python source = S.obs_get_source_by_name(self.source_name) settings = S.obs_source_get_settings(source) psettings = S.obs_source_get_private_settings(source) dsettings = S.obs_data_get_defaults(settings) pdsettings = S.obs_data_get_defaults(psettings) print("[---------- settings ----------") print(S.obs_data_get_json(settings)) print("---------- private_settings ----------") print(S.obs_data_get_json(psettings)) print("---------- default settings for this source type ----------") print(S.obs_data_get_json(dsettings)) print("---------- default private settings for this source type ----------") print(S.obs_data_get_json(pdsettings)) ... print("[--------- filter names --------") for i in range(filter_count): settings = S.obs_data_array_item(filters, i) filter_name = S.obs_data_get_string(settings, "name") S.obs_data_release(settings) print(filter_name) print(" filter names of %s --------" % self.source_name) ``` -------------------------------- ### Control Source Visibility with ToggleController Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Demonstrates how to toggle the visibility of a source by defining a ToggleController class and utilizing a toggle function. It requires a source name to be set before toggling. ```python class ToggleController: source_name = None def toggle(self): toggle_visibility(self.source_name) controller = ToggleController() controller.source_name = "my_webcam" controller.toggle() ``` -------------------------------- ### Read Source Settings, Private Settings, Defaults, and Filters (Python) Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Inspects and retrieves various settings (general, private, default) and filter information for a given source. Requires the 'obspython' library. It takes the source name as input and prints the retrieved information. ```python import obspython as S def print_source_info(source_name): source = S.obs_get_source_by_name(source_name) if not source: print("Source not found") return # Get various settings settings = S.obs_source_get_settings(source) psettings = S.obs_source_get_private_settings(source) dsettings = S.obs_data_get_defaults(settings) pdsettings = S.obs_data_get_defaults(psettings) print("=== Settings ===") print(S.obs_data_get_json(settings)) print("=== Private Settings ===") print(S.obs_data_get_json(psettings)) print("=== Default Settings ===") print(S.obs_data_get_json(dsettings)) # Release settings for s in (settings, psettings, dsettings, pdsettings): S.obs_data_release(s) # List filters filters = S.obs_source_backup_filters(source) filter_count = S.obs_source_filter_count(source) print(f"=== Filters ({filter_count}) ===") for i in range(filter_count): filter_data = S.obs_data_array_item(filters, i) filter_name = S.obs_data_get_string(filter_data, "name") print(f" - {filter_name}") S.obs_data_release(filter_data) S.obs_data_array_release(filters) S.obs_source_release(source) ``` -------------------------------- ### Add Scene with Sources (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Demonstrates how to create a nested scene, add random text sources to it, and then add this nested scene as an item to the current scene. This function utilizes OBS API calls to manage scenes and sources. ```python import obspython as S from random import randint def add_random_text_source(scene): r = " random text # " + str(randint(0, 10)) with data_ar() as settings: S.obs_data_set_string(settings, "text", f"random text value {r}") with source_create_ar("text_ft2_source", f"random text{r}", settings) as source: pos = S.vec2() pos.x = randint(0, 1920) pos.y = randint(0, 1080) scene_item = S.obs_scene_add(scene, source) S.obs_sceneitem_set_pos(scene_item, pos) def add_scene_with_sources(): current_scene_source = S.obs_frontend_get_current_scene() with scene_from_source_ar(current_scene_source) as scene_source: with scene_create_ar("_nested_scene") as _scene: py_scene_source = S.obs_scene_get_source(_scene) with scene_from_source_ar(py_scene_source) as scene: add_random_text_source(scene) add_random_text_source(scene) add_random_text_source(scene) # add created scene to current scene ( nested scene) _scene_source = S.obs_scene_get_source(scene) S.obs_scene_add(scene_source, _scene_source) ``` -------------------------------- ### Send Keyboard and Mouse Events to Browser Sources (Python) Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Automates keyboard and mouse interactions with browser sources by sending specific events. Requires the 'obspython' library. It takes source name, key/mouse details, and modifier states as input. ```python import obspython as S from contextlib import contextmanager @contextmanager def source_auto_release(source_name): source = S.obs_get_source_by_name(source_name) try: yield source finally: S.obs_source_release(source) def get_modifiers(key_modifiers): modifiers = 0 if key_modifiers: if key_modifiers.get("shift"): modifiers |= S.INTERACT_SHIFT_KEY if key_modifiers.get("control"): modifiers |= S.INTERACT_CONTROL_KEY if key_modifiers.get("alt"): modifiers |= S.INTERACT_ALT_KEY return modifiers def send_key_to_browser(source, key_name, key_modifiers=None, key_up=False): key = S.obs_key_from_name(key_name) vk = S.obs_key_to_virtual_key(key) event = S.obs_key_event() event.native_vkey = vk event.modifiers = get_modifiers(key_modifiers) event.native_modifiers = event.modifiers event.native_scancode = vk event.text = "" S.obs_source_send_key_click(source, event, key_up) def send_mouse_click(source, x, y, button=None, mouse_up=False, click_count=1): if button is None: button = S.MOUSE_LEFT event = S.obs_mouse_event() event.modifiers = 0 event.x = x event.y = y S.obs_source_send_mouse_click(source, event, button, mouse_up, click_count) # Usage with source_auto_release("my_browser") as source: # Press Tab send_key_to_browser(source, "OBS_KEY_TAB") send_key_to_browser(source, "OBS_KEY_TAB", key_up=True) # Click at position (100, 200) send_mouse_click(source, 100, 200) send_mouse_click(source, 100, 200, mouse_up=True) ``` -------------------------------- ### Send Hotkeys to Browser Source using Python Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Provides Python functions to send keyboard events (like Tab) to a browser source. It uses `obs_source_send_key_click` after converting key names to virtual keys and setting up key event structures. ```python def send_hotkey_to_browser(source, obs_htk_id, key_modifiers=None, key_up=False): key = S.obs_key_from_name(obs_htk_id) vk = S.obs_key_to_virtual_key(key) event = S.obs_key_event() event.native_vkey = vk event.modifiers = get_modifiers(key_modifiers) event.native_modifiers = event.modifiers # https://doc.qt.io/qt-5/qkeyevent.html event.native_scancode = vk event.text = "" S.obs_source_send_key_click(source, event, key_up) def press_tab(*p): with source_auto_release(G.source_name) as source: send_hotkey_to_browser(source, "OBS_KEY_TAB") send_hotkey_to_browser(source, "OBS_KEY_TAB", key_up=True) def press_shift_tab(*p): with source_auto_release(G.source_name) as source: send_hotkey_to_browser(source, "OBS_KEY_TAB", {"shift": True}) send_hotkey_to_browser(source, "OBS_KEY_TAB", {"shift": True}, key_up=True) ``` -------------------------------- ### Connect to Scene Signals (Python) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Shows how to connect a Python callback to scene-specific signals, like 'item_add'. The callback function processes calldata to identify the added scene item and its parent scene, then prints their names. ```python import obspython as S def connect_cur_scene(): source = S.obs_frontend_get_current_scene() sh = S.obs_source_get_signal_handler(source) S.signal_handler_connect(sh, "item_add", callback) S.obs_source_release(source) def callback(calldata): scene_item = S.calldata_sceneitem(calldata, "item") #scene = S.calldata_source(cd,"scene") # bad utf symbols scene = S.obs_sceneitem_get_scene(scene_item) name = S.obs_source_get_name source = S.obs_sceneitem_get_source scene_source = S.obs_scene_get_source scene_name = name(scene_source(scene)) scene_item_name = name(source(scene_item)) print(f"item {scene_item_name} has been added to scene {scene_name}") ``` -------------------------------- ### OBS Resource Management with Python Context Managers Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt This snippet demonstrates how to use Python context managers for automatic resource management in OBS Studio scripting. It provides context managers for sources, data settings, scenes, and scene item lists, ensuring proper cleanup and adherence to OBS memory management patterns. ```python import obspython as S from contextlib import contextmanager @contextmanager def source_ar(source_name): """Auto-release source context manager""" source = S.obs_get_source_by_name(source_name) try: yield source finally: S.obs_source_release(source) @contextmanager def data_ar(): """Auto-release data context manager""" settings = S.obs_data_create() try: yield settings finally: S.obs_data_release(settings) @contextmanager def scene_ar(scene_source): """Auto-release scene context manager""" scene = S.obs_scene_from_source(scene_source) try: yield scene finally: S.obs_scene_release(scene) @contextmanager def scene_enum(scene): """Auto-release scene item list context manager""" items = S.obs_scene_enum_items(scene) try: yield items finally: S.sceneitem_list_release(items) # Usage example def safe_update_source(source_name, text): with source_ar(source_name) as source: if source: with data_ar() as settings: S.obs_data_set_string(settings, "text", text) S.obs_source_update(source, settings) ``` -------------------------------- ### Create and Add Text Source in OBS using Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Demonstrates how to create a text source with specified settings and add it to the current OBS scene. It handles platform-specific text source types (text_gdiplus for Windows, text_ft2_source for Linux/Mac). ```python import obspython as S def create_text_source(): # Get current scene current_scene = S.obs_frontend_get_current_scene() scene = S.obs_scene_from_source(current_scene) # Create settings for the source settings = S.obs_data_create() S.obs_data_set_string(settings, "text", "Hello from Python!") # Create source (text_gdiplus for Windows, text_ft2_source for Linux/Mac) source = S.obs_source_create_private("text_gdiplus", "my_text_source", settings) # Add source to scene S.obs_scene_add(scene, source) # Release resources S.obs_scene_release(scene) S.obs_data_release(settings) S.obs_source_release(source) # Common source type identifiers: # browser_source, color_source, monitor_capture, game_capture # slideshow, image_source, ffmpeg_source, text_gdiplus, window_capture ``` -------------------------------- ### Network Traffic Analysis using tcpdump (Bash) Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md This bash command demonstrates how to capture network traffic on a specified interface, filtering for port 443. This is useful for security analysis, such as checking for unexpected 'calling home' activity from OBS Studio. Replace `` with your actual network interface name. ```bash # tcpdump -i 'port 443' ``` -------------------------------- ### Write Private Data using Lua Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Illustrates how to write integer data to OBS Studio's private storage using Lua. It uses `obs_data_create`, `obs_data_set_int`, and `obs_apply_private_data` to store the value. ```lua local obs = obslua local settings = S.obs_data_create() S.obs_data_set_int(settings,"__private__", 7) S.obs_apply_private_data(settings) S.obs_data_release(settings) ``` -------------------------------- ### Add UI Elements to OBS Properties Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Demonstrates how to add various UI elements to OBS properties, such as buttons, boolean toggles, integer inputs, sliders, text fields, color pickers, and font selectors. These functions are essential for creating interactive script settings. ```python S.obs_properties_add_button(props, "button1", "Refresh1:",callback) S.obs_properties_add_bool(props,"_bool","_bool:") S.obs_properties_add_int(props,"_int","_int:",1,100,1) S.obs_properties_add_int_slider(props,"_slider","_slider:",1,100,1) S.obs_properties_add_text(props, "_text", "_text:", S.OBS_TEXT_DEFAULT) S.obs_properties_add_color(props,"_color","_color:") S.obs_properties_add_font(props,"_font","_font:") bool_p = S.obs_properties_add_bool(props, "_obs_bool", "Yes/No"); S.obs_property_set_long_description(bool_p, "Check if yes,else uncheck") ``` -------------------------------- ### Read Private Data using Python Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Shows how to read string data from OBS Studio's private storage using Python. It employs a context manager to safely access and release the private data using `obs_get_private_data` and `obs_data_get_string`. ```python @contextmanager def p_data_ar(data_type, field): settings = S.obs_get_private_data() get = getattr(obs, f"obs_data_get_{data_type}") try: yield get(settings, field) finally: S.obs_data_release(settings) def print_private_data(): with p_data_ar("string", "__private__") as value: print(value) ``` -------------------------------- ### Play Audio Globally in OBS (Python) Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt This Python script explains how to play an audio file globally within OBS, making it audible on both the stream and local monitoring. It involves creating a media source, setting its file path, enabling monitoring and output, and assigning it to an audio output index. The script also includes cleanup for when OBS is unloaded. ```python import obspython as S OUTPUT_INDEX = 63 # Last audio output index def play_sound(file_path): # Create media source media_source = S.obs_source_create_private( "ffmpeg_source", "Global Media Source", None ) # Set file path settings = S.obs_data_create() S.obs_data_set_string(settings, "local_file", file_path) S.obs_source_update(media_source, settings) # Enable monitoring (hear it locally) and output (in stream) S.obs_source_set_monitoring_type( media_source, S.OBS_MONITORING_TYPE_MONITOR_AND_OUTPUT ) S.obs_data_release(settings) S.obs_set_output_source(OUTPUT_INDEX, media_source) S.obs_source_release(media_source) def script_unload(): S.obs_set_output_source(OUTPUT_INDEX, None) # Play sound on scene change def on_event(event): if event == S.OBS_FRONTEND_EVENT_SCENE_CHANGED: play_sound("/path/to/alert.mp3") ``` -------------------------------- ### Register OBS Frontend Event Callbacks Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Allows registering callbacks for various OBS frontend events, such as scene changes, streaming start/stop, and recording status. It uses the 'obspython' library to add event listeners. ```python import obspython as S def on_event(event): if event == S.OBS_FRONTEND_EVENT_SCENE_CHANGED: print("Scene changed!") elif event == S.OBS_FRONTEND_EVENT_STREAMING_STARTED: print("Streaming started!") elif event == S.OBS_FRONTEND_EVENT_STREAMING_STOPPED: print("Streaming stopped!") elif event == S.OBS_FRONTEND_EVENT_RECORDING_STARTED: print("Recording started!") elif event == S.OBS_FRONTEND_EVENT_RECORDING_STOPPED: print("Recording stopped!") elif event == S.OBS_FRONTEND_EVENT_FINISHED_LOADING: print("OBS finished loading!") def script_load(settings): S.obs_frontend_add_event_callback(on_event) # Check program state def check_state(): is_streaming = S.obs_frontend_streaming_active() is_recording = S.obs_frontend_recording_active() is_recording_paused = S.obs_frontend_recording_paused() studio_mode = S.obs_frontend_preview_program_mode_active() replay_active = S.obs_frontend_replay_buffer_active() ``` -------------------------------- ### Add Color Filter to Source in OBS using Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Demonstrates how to add a color filter to an existing source in OBS, allowing for adjustments like opacity. It creates a 'color_filter' source with specified settings and attaches it to the target source. Requires the `obspython` library. ```python import obspython as S def add_color_filter(source_name, opacity=50): source = S.obs_get_source_by_name(source_name) if source: settings = S.obs_data_create() S.obs_data_set_int(settings, "opacity", opacity) # Create filter (filters are also sources) color_filter = S.obs_source_create_private( "color_filter", "opacity_filter", settings ) # Add filter to source S.obs_source_filter_add(source, color_filter) S.obs_source_release(source) S.obs_data_release(settings) S.obs_source_release(color_filter) # Common filter identifiers: # color_filter, chroma_key_filter, mask_filter, gain_filter # noise_suppress_filter, compressor_filter, scroll_filter ``` -------------------------------- ### Duplicate Source in OBS using Python Source: https://context7.com/upgradeq/streaming-software-scripting-reference/llms.txt Explains how to duplicate an existing source in OBS, preserving its transform and crop settings, and then add it to a specified target scene. This function requires the `obspython` library and valid source and scene names. ```python import obspython as S def duplicate_source(source_name, target_scene_name): current_scene = S.obs_scene_from_source(S.obs_frontend_get_current_scene()) scene_item = S.obs_scene_find_source(current_scene, source_name) # Get transform and crop info info = S.obs_transform_info() crop = S.obs_sceneitem_crop() S.obs_sceneitem_get_info(scene_item, info) S.obs_sceneitem_get_crop(scene_item, crop) # Duplicate the source original = S.obs_sceneitem_get_source(scene_item) duplicated = S.obs_source_duplicate(original, "duplicate_" + source_name, False) # Find target scene and add duplicated source scenes = S.obs_frontend_get_scenes() for scene in scenes: name = S.obs_source_get_name(scene) if name == target_scene_name: target = S.obs_scene_from_source(scene) new_item = S.obs_scene_add(target, duplicated) S.obs_sceneitem_set_info(new_item, info) S.obs_sceneitem_set_crop(new_item, crop) S.obs_scene_release(target) S.obs_source_release(duplicated) S.source_list_release(scenes) S.obs_scene_release(current_scene) ``` -------------------------------- ### Send Hotkey Event to OBS Source: https://github.com/upgradeq/streaming-software-scripting-reference/blob/master/README.md Provides a function to programmatically send hotkey events to OBS. It constructs an OBS key combination, including modifiers, and injects the event into OBS, simulating a key press and release. ```python def send_hotkey(obs_htk_id, key_modifiers=None): if key_modifiers: shift = key_modifiers.get("shift") control = key_modifiers.get("control") alt = key_modifiers.get("alt") command = key_modifiers.get("command") ... combo = S.obs_key_combination() combo.modifiers = modifiers combo.key = S.obs_key_from_name(obs_htk_id) ... S.obs_hotkey_inject_event(combo, False) S.obs_hotkey_inject_event(combo, True) S.obs_hotkey_inject_event(combo, False) ```