Added more settings to frame_updater and made it react to 16:9 ratio with showing/hiding frame source. Added JSON parser and an example on how to use it.

This commit is contained in:
4aiman 2023-12-21 19:52:46 +03:00
commit 99653c68da
4 changed files with 1715 additions and 45 deletions

View file

@ -12,9 +12,19 @@ Enjoy!
## [frame_updater.lua](https://github.com/4aiman/obs_scripts/blob/main/frame_updater.lua)
Checks the size of a game capture source and updates filepath of an image source to match that.<br>
Right now only 2 resolutions are supported ad nothing is in the GUI apart from upadte interval and 2 sources: the game capture one and the frame/overlay one.<br>
Be sure to select the folder with your frames.<br>
If you want to change your crop filter name, then load the script and *refresh it*. That's the only way to update the list in OBS properties after it's been created, since one can't update a list on properties update. (In reality refreshing recreates the properties object)<br>
Tinker with it to suit your needs.
## [death_counter.lua](https://github.com/4aiman/obs_scripts/blob/main/death_counter.lua)
Uses one of the text sources as a death counter.<br>
Set up a hotkey and press it for the counter to go up.<br>
Reset the counter in the script setting window.
## [obs_source_set_settings_fix.lua](https://github.com/4aiman/obs_scripts/blob/main/obs_source_set_settings_fix.lua)
A helper file that can help one iterate OBS source's properties (also works for filters, as those are treated as sources internally).<br>
Find details inside the file.
## [DEPS](https://github.com/4aiman/obs_scripts/blob/main/deps)
This folder contains all the Lua scripts that will help circumvent crappy desing of Lua bindings in OBS.<br>

1559
deps/JSON.lua vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -7,23 +7,28 @@ total_seconds = 0
cur_seconds = 0
-- names of the sources that are being synced up
master_source_name = ""
padding_filter_name = "pad to frame"
slave_source_name = ""
-- actual sources
master_combobox = nil
slave_combobox = nil
master_filers_combobox = nil
global_props = nil
-- seconds between sync attempts
sync_delay = 5
activated = false
-- padding filter name
padding_filter_name = "pad to frame"
-- common path to all your frames
basic_fmames_path = "add yours"
base_fmames_path = ""
sizes_3_by_2 = {{width = 1440, height = 960}}
sizes_3_by_4 = {{width = 1280, height = 960}}
sizes_16_by_9 = {{width = 1920, height = 1080}}
-- a hotkey to force synchronisation of a given pair
hotkey_id = obs.OBS_INVALID_HOTKEY_ID
function string.split(inputstr, sep)
if sep == nil then
sep = "%s"
@ -48,39 +53,70 @@ function timer_callback()
if master_source~= nil and slave_source~= nil then
local master_filters = obs.obs_source_enum_filters(master_source)
-- obs_source_get_filter_by_name
local master_height = obs.obs_source_get_height(master_source)
local master_width = obs.obs_source_get_width(master_source)
local padding_left = 0
local padding_top = 0
local actual_height = master_height
local actual_width = master_width
-- obs_source_get_filter_by_name
for idx, filter in pairs(master_filters) do
local filter_name = obs.obs_source_get_name(filter)
if filter_name == padding_filter_name then
local filter_props = obs.obs_source_get_settings(filter)
local master_height = obs.obs_source_get_height(master_source)
local master_width = obs.obs_source_get_width(master_source)
local padding_left = obs.obs_data_get_int(filter_props, 'left')
local padding_top = obs.obs_data_get_int(filter_props, 'top')
local actual_height = master_height + padding_top
local actual_width = master_width + padding_left
if filter_name == padding_filter_name then
-- check if the padding filter is enabled at all
if obs.obs_source_enabled(filter) == true then
-- if it is - modify actual size with regard to set padding
local filter_props = obs.obs_source_get_settings(filter)
padding_left = obs.obs_data_get_int(filter_props, 'left')
padding_top = obs.obs_data_get_int(filter_props, 'top')
actual_height = master_height + padding_top
actual_width = master_width + padding_left
else
break
end
end
end
if sizing_mode ~= true then
for id, size in ipairs (sizes_3_by_2) do
if actual_width == size.width and actual_height == size.height then
--print("it's 3:2 ratio!")
sizing_mode = 'frame_3x2'
break
end
end
end
--print(master_width .. "x"..master_height ..'; '.. (padding_left or 0) .. ':' .. (padding_top or 0) .. '; ' .. actual_width .. 'x' .. actual_height)
if sizing_mode ~= true then
for id, size in ipairs (sizes_3_by_2) do
if actual_width == size.width and actual_height == size.height then
--print("it's 3:2 ratio!")
sizing_mode = 'frame_3x2'
break
end
end
end
if sizing_mode ~= true then
for id, size in ipairs (sizes_3_by_4) do
if actual_width == size.width and actual_height == size.height then
--print("it's 4:3 ratio!")
sizing_mode = 'frame_4x3'
break
end
end
end
if sizing_mode ~= true then
for id, size in ipairs (sizes_16_by_9) do
if actual_width == size.width and actual_height == size.height then
--print("it's 16:9 ratio!")
-- obs.obs_source_enabled doesn't want the second param, despite what's said in the docs
-- obs.obs_source_active is readonly as per documentation, but only returns false
-- obs.obs_source_set_hidden does nothing
-- obs.obs_source_dec_showing does nothing
-- obs.obs_source_dec_active does nothing
-- obs.obs_scene_from_source doesn't produce anything, making it impossible to work with any scene items despite being used is some people's code
obs.obs_source_set_enabled(slave_source, false)
break
end
end
end
if sizing_mode ~= true then
for id, size in ipairs (sizes_3_by_4) do
if actual_width == size.width and actual_height == size.height then
--print("it's 4:3 ratio!")
sizing_mode = 'frame_4x3'
break
end
end
end
end
end
if sizing_mode ~= false then
local slave_props = obs.obs_source_get_settings(slave_source)
@ -93,12 +129,13 @@ function timer_callback()
if month >8 and month < 12 then season = 'autumn' end
if month >11 or month < 3 then season = 'winter' end
local frame_path = basic_fmames_path .. sizing_mode .. '_' .. season .. ".png"
local frame_path = base_fmames_path .. sizing_mode .. '_' .. season .. ".png"
if image ~= frame_path then
obs.obs_data_set_string(slave_props, 'file', frame_path)
obs.obs_source_update(slave_source, slave_props)
end
obs.obs_source_set_enabled(slave_source, true)
end
obs.obs_source_release(master_source)
@ -134,13 +171,16 @@ end
-- can change for the entire script module itself
function script_properties()
-- create properties dialogue
local props = obs.obs_properties_create()
global_props = obs.obs_properties_create()
-- add sync delay settings
obs.obs_properties_add_int(props, "sync_delay", "Sync cycle (seconds)", 1, 3600, 1)
-- add main source combobox
local master = obs.obs_properties_add_list(props, "master_source", "Game source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_properties_add_int(global_props, "sync_delay", "Sync cycle (seconds)", 1, 3600, 1)
-- add main source global_props
master_combobox = obs.obs_properties_add_list(global_props, "master_source", "Game source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
-- add master filters list; a more convenient way to select the padding filter
master_filers_combobox = obs.obs_properties_add_list(global_props, "filter_source", "Pading filter", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING )
-- add the source that will sync up with the main one
local slave = obs.obs_properties_add_list(props, "slave_source", "Frame source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
slave_combobox = obs.obs_properties_add_list(global_props, "slave_source", "Frame source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
frame_path_edit = obs.obs_properties_add_path(global_props, "frame_path_edit", "Frame Folder", obs.OBS_PATH_DIRECTORY, nil ,nil)
-- get all the sources
local sources = obs.obs_enum_sources()
if sources ~= nil then
@ -152,32 +192,48 @@ function script_properties()
then
local name = obs.obs_source_get_name(source)
if source_id == "game_capture" then
obs.obs_property_list_add_string(master, name, name)
obs.obs_property_list_add_string(master_combobox, name, name)
end
if source_id == "image_source" then
obs.obs_property_list_add_string(slave, name, name)
obs.obs_property_list_add_string(slave_combobox, name, name)
end
end
end
end
if master_source_name ~= '' then
local master_source = obs.obs_get_source_by_name(master_source_name)
if master_source~= nil and master_filers_combobox ~= nil then
local master_filters = obs.obs_source_enum_filters(master_source)
for idx, filter in pairs(master_filters) do
local filter_name = obs.obs_source_get_name(filter)
obs.obs_property_list_add_string(master_filers_combobox, filter_name, filter_name)
end
obs.obs_source_release(master_source)
end
end
-- they say it's important to release sources
obs.source_list_release(sources)
return props
return global_props
end
-- A function named script_description returns the description shown to
-- the user
function script_description()
return "This script allows one to automatically change 'frames' depending on a game capture source's size.\n\nThe idea is to have several overlays for different aspect ratios of the game capture source and auto-select them dependinf on that.\nJust pick some overlays below for every aspect you'd like to have, and enjoy automation.\n\nMade by 4aiman"
return "This script allows one to automatically change 'frames' depending on a game capture source's size.\n\nThe idea is to have several overlays for different aspect ratios of the game capture source and auto-select them dependinf on that.\nJust pick some overlays below for every aspect you'd like to have, and enjoy automation.\n\nOnce the Game source is set *refresh* the script in order to be able to select the crop filter.\n\nMade by 4aiman"
end
-- A function named script_update will be called when settings are changed
function script_update(settings)
total_seconds = obs.obs_data_get_int(settings, "sync_delay")
master_source_name = obs.obs_data_get_string(settings, "master_source")
padding_filter_name = obs.obs_data_get_string(settings, "filter_source")
slave_source_name = obs.obs_data_get_string(settings, "slave_source")
print("Frame Synchronizer script upadted. Delay has been set to " .. total_seconds .. '; Master source is now "' .. master_source_name .. '"; Slave source is now "' .. slave_source_name ..'".')
base_fmames_path = obs.obs_data_get_string(settings, "frame_path_edit") .. '/'
print("Frame Synchronizer script upadted. Delay has been set to " .. total_seconds .. '; Master source is now "' .. master_source_name .. '; Filter source is now "' .. padding_filter_name .. '"; Slave source is now "' .. slave_source_name ..'".')
end

View file

@ -0,0 +1,45 @@
--[[
Issue:
One can't iterate over a source properties in Lua
Why it happens:
-- obs.obs_get_source_properties always returns nill
-- obs.obs_source_get_settings can't be iterated over
-- obs_properties_first can be used, but obs_properties_next expects a pointer while Lua bindings operate with objects
-- OBS devs ignored issues aimed to fix this for several years
Solution accepted by the OBS devs:
Use FFI to create a second wrapper for something that an already embedded LUa bindings should give access to.
My solution:
Use json-lua by tiye (https://github.com/tiye/json-lua/tree/main) to make JSON dataiteratable
How to use:
- add these lines to any of your scripts to be able to iterate over source properties through lua
- work with native Lua tables using 2 new methods
]]
-- load JSON
json = require("deps.JSON")
-- helper to get the settings of a source
obs.obs_source_get_settings_json = function (source)
local properties = obs.obs_source_get_settings(source)
local json_encoded = obs.obs_data_get_json(properties)
local data = json:decode(json_encoded)
return data
end
-- helper to set the settings of a source
obs.obs_source_set_settings_json = function (source, json_properties)
local properties = obs.obs_source_get_settings(source)
for key, value in pairs(json_properties) do
obs.obs_data_set_string(properties, key, value)
end
obs.obs_source_update(slave_source, slave_props)
end