Skip to content

Instantly share code, notes, and snippets.

@Dramacydal
Created January 1, 2023 19:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dramacydal/8804c7d2cc48575169beda18e3de7773 to your computer and use it in GitHub Desktop.
Save Dramacydal/8804c7d2cc48575169beda18e3de7773 to your computer and use it in GitHub Desktop.
obs script to update scene items positions with actual window positions
import obspython as obs
import re
import win32gui
import win32api
# Global variables holding the values of data settings / properties
update_frequency = 50 # Update frequency in msec
# Global animation activity flag
is_active = True
# Identifier of the hotkey set by OBS
hotkey_id = obs.OBS_INVALID_HOTKEY_ID
def walk_scene_items_in_current_source(walker):
current_scene_as_source = obs.obs_frontend_get_current_scene()
if not current_scene_as_source:
return
current_scene = obs.obs_scene_from_source(current_scene_as_source)
items = obs.obs_scene_enum_items(current_scene)
for i, s in enumerate(items):
walker(s, items)
obs.sceneitem_list_release(items)
obs.obs_source_release(current_scene_as_source)
# Called at script load
def script_load(settings):
# global hotkey_id
# hotkey_id = obs.obs_hotkey_register_frontend(script_path(), "Source Shake", on_shake_hotkey)
# hotkey_save_array = obs.obs_data_get_array(settings, "shake_hotkey")
# obs.obs_hotkey_load(hotkey_id, hotkey_save_array)
# obs.obs_data_array_release(hotkey_save_array)
return
def script_save(settings):
obs.obs_save_sources()
# Hotkey save
# hotkey_save_array = obs.obs_hotkey_save(hotkey_id)
# obs.obs_data_set_array(settings, "shake_hotkey", hotkey_save_array)
# obs.obs_data_array_release(hotkey_save_array)
def script_unload():
return
def script_description():
return """Source Shake!!
Shake a source in the current scene when a hotkey is pressed. Go to Settings
then Hotkeys to select the key combination.Check the
Source Shake Scripting Tutorial on the OBS Wiki for more information."""
def sync_scene_item(scene_item, scene_items):
hwndMain = get_scene_item_hwnd(scene_item)
if not hwndMain:
return
order = obs.obs_sceneitem_get_order_position(scene_item)
is_visible = obs.obs_sceneitem_visible(scene_item)
if win32gui.IsIconic(hwndMain):
if is_visible:
obs.obs_sceneitem_set_visible(scene_item, False)
return
else:
if not is_visible:
obs.obs_sceneitem_set_visible(scene_item, True)
if win32gui.GetForegroundWindow() == hwndMain:
if (order != len(scene_items)):
obs.obs_sceneitem_set_order_position(scene_item, len(scene_items))
# print(hwndMain)
sync_scene_item_pos(scene_item, hwndMain)
return
def sync_scene_items():
walk_scene_items_in_current_source(sync_scene_item)
def get_scene_item_hwnd(scene_item):
source = obs.obs_sceneitem_get_source(scene_item)
settings = obs.obs_source_get_settings(source)
window = obs.obs_data_get_string(settings, 'window')
obs.obs_data_release(settings)
windowParts = window.split(":")
windowClassName = unescape_window_name(windowParts[1])
windowName = unescape_window_name(windowParts[0])
return win32gui.FindWindow(windowClassName, windowName)
def sync_scene_item_pos(sceneitem, hwnd):
if not hwnd:
return
rect = win32gui.GetWindowRect(hwnd)
# print(rect)
hMonitor = win32api.MonitorFromWindow(hwnd, 0)
if not hMonitor:
return
monitorInfo = win32api.GetMonitorInfo(hMonitor)
if not monitorInfo:
return
newPos = obs.vec2()
oldPos = obs.vec2()
newPos.x = rect[0] - monitorInfo['Monitor'][0]
newPos.y = rect[1] - monitorInfo['Monitor'][1]
obs.obs_sceneitem_get_pos(sceneitem, oldPos)
if oldPos.x != newPos.x or oldPos.y != newPos.y:
obs.obs_sceneitem_set_pos(sceneitem, newPos)
def unescape_window_name(str):
def repl(m):
# print(m.group(1))
ch = chr(int(m.group(1), 16))
return ch
return re.sub('#([A-Z0-9]{2})', repl, str)
total_seconds = 0.0
# Called every frame
def script_tick(seconds):
global total_seconds, update_frequency
total_seconds += seconds
if total_seconds < update_frequency / 1000.0:
return
total_seconds = 0.0
sync_scene_items()
# Callback for the hotkey
def on_shake_hotkey(pressed):
global is_active
is_active = pressed
# Called to set default values of data settings
def script_defaults(settings):
obs.obs_data_set_default_double(settings, "update_frequency", 50.0)
# Called to display the properties GUI
def script_properties():
props = obs.obs_properties_create()
obs.obs_properties_add_float_slider(props, "update_frequency", "Update frequency", 20, 1000, 10)
return props
# Called after change of settings including once after script load
def script_update(settings):
global update_frequency
update_frequency = obs.obs_data_get_double(settings, "update_frequency")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment