--[[
Author: @iixisii
Date: 02.21.2025
Description: YES, PLEASE!
Version: 2.0.1
]]
obs = obslua
os = require 'os'
bit = require 'bit'
utils = {properties={};history={}}; filter= {}; event_list= {
{id="fade"; name="will hide and show"},
{id="flicker"; name="will flicker"},
{id="hover";name="will hover up and down"},
{id="rotate";name="will rotate 360 degrees"},
{id="shake";name="will shake"},
}
event_video_list= {
{id="pause"; name = "will pause"},
{id="play"; name = "will play"},
}
hotkey_key_list= {
"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"1","2","3","4","5","6","7","8","9","0",
"num1","num2","num3","num4","num5","num6","num7","num8","num9","num0",
"enter","esc","backspace","tab","space","minus","equals","leftbracket","rightbracket","backslash","semicolon","apostrophe","grave","comma","period","slash","capslock",
"f1","f2","f3","f4","f5","f6","f7","f8","f9","f10","f11","f12",
"printscreen","scrolllock","pause","insert","home","pageup","delete","end","pagedown","right","left","down","up",
}
filter.id= "filter-upstreamx-iixisii-v2.0.1"
filter.type= obs.OBS_SOURCE_TYPE_FILTER
filter.output_flags= bit.bor(obs.OBS_SOURCE_VIDEO)
function get_filter_source(src)
return obs.obs_filter_get_target(src.source)
end
filter.get_name= function()
return "UpstreamX"
end
filter.get_height= function(src)
if src == nil then
return 0
end
return src.height
end
filter.get_width= function(src)
if src == nil then
return 0
end
return src.width
end
filter.get_properties= function(src)
local p= obs.obs_properties_create()
local mode= utils.obs_properties_add_list(p, "mode", "", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_property_list_add_string(mode, "Time will activate when streaming or recording", "mode1")
obs.obs_property_list_add_string(mode, "Time will activate when streaming", "mode2")
obs.obs_property_list_add_string(mode, "Time will activate when recording", "mode3")
obs.obs_property_list_add_string(mode, "Time will start/stop when you press specific hotkey", "mode4")
-- [[ HOTKEY GROUP ]]
local hotkey_start_op= obs.obs_properties_create()
local hotkey_start_group= utils.obs_properties_add_group(p, "hotkey_start_group", "Start", obs.OBS_GROUP_NORMAL,hotkey_start_op)
local hotkey_start_shift_key= utils.obs_properties_add_bool(hotkey_start_op, "hotkey_start_shift_key", "SHIFT")
local hotkey_start_key_list= utils.obs_properties_add_list(hotkey_start_op, "hotkey_start_key_list", "", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_property_list_add_string(hotkey_start_key_list, "SELECT KEY", "")
local hotkey_stop_op= obs.obs_properties_create()
local hotkey_stop_group= utils.obs_properties_add_group(p, "hotkey_stop_group", "Stop", obs.OBS_GROUP_NORMAL, hotkey_stop_op)
local hotkey_stop_shift_key= utils.obs_properties_add_bool(hotkey_stop_op, "hotkey_stop_shift_key", "SHIFT")
local hotkey_stop_key_list= utils.obs_properties_add_list(hotkey_stop_op, "hotkey_stop_key_list", "", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_property_list_add_string(hotkey_stop_key_list, "SELECT KEY", "")
local hotkey_reset_op= obs.obs_properties_create()
local hotkey_reset_group= utils.obs_properties_add_group(p, "hotkey_reset_group", "Reset", obs.OBS_GROUP_NORMAL, hotkey_reset_op)
local hotkey_reset_shift_key= utils.obs_properties_add_bool(hotkey_reset_op, "hotkey_reset_shift_key", "SHIFT")
local hotkey_reset_key_list= utils.obs_properties_add_list(hotkey_reset_op, "hotkey_reset_key_list", "", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_property_list_add_string(hotkey_reset_key_list, "SELECT KEY", "")
for _, key in pairs(hotkey_key_list) do
obs.obs_property_list_add_string(hotkey_start_key_list, string.upper(key), key)
obs.obs_property_list_add_string(hotkey_stop_key_list, string.upper(key), key)
obs.obs_property_list_add_string(hotkey_reset_key_list, string.upper(key), key)
end
obs.obs_property_set_visible(hotkey_start_group, false)
obs.obs_property_set_visible(hotkey_stop_group, false)
obs.obs_property_set_visible(hotkey_reset_group, false)
local show_hotkeys_button= utils.obs_properties_add_button(p, "show_hotkeys_button", "SET HOTKEYS ⇶", function(props, p)
utils.hide_all(props, src)
local mode= src.setting.get_str("mode")
if mode == "mode4" then
utils.show_hotkeys(props, src)
end
local go_back= obs.obs_properties_get(props, "go_back")
obs.obs_property_set_visible(go_back, true)
return true
end)
local go_back= utils.obs_properties_add_button(p, "go_back", "↩ Back", function(props, p)
utils.go_back(props, src)
return true
end)
obs.obs_property_set_visible(go_back, false)
obs.obs_property_set_visible(show_hotkeys_button, false)
-- hotkey start callback
obs.obs_property_set_modified_callback(hotkey_start_shift_key, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_start= obj.get_arr("hotkey_start")
if hotkey_start == nil or hotkey_start.data == nil then
-- handle error
obj.free()
return false
end
obs.obs_hotkey_unregister(src.start)
local timer_mode= obj.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_start.next()
local is_shift = _settings.get_bul("hotkey_start_shift_key")
hotkey.bul("shift", is_shift)
hotkey.free();
end
hotkey_start.free();obj.free()
utils.update_hotkey(src)
end
return true
end)
obs.obs_property_set_modified_callback(hotkey_start_key_list, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_start= obj.get_arr("hotkey_start")
if hotkey_start and hotkey_start.data == nil then
-- handle error
obj.free()
return false
end
obs.obs_hotkey_unregister(src.start)
local timer_mode= _settings.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_start.next()
local key= _settings.get_str("hotkey_start_key_list")
if key == nil or key == "" or key == "" then
key="none"
end
hotkey.str("key", "OBS_KEY_" .. string.upper(key))
hotkey.free();
end
hotkey_start.free();obj.free()
utils.update_hotkey(src)
end
return true
end)
-- hotkey stop callback
obs.obs_property_set_modified_callback(hotkey_stop_shift_key, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_stop= obj.get_arr("hotkey_stop")
if hotkey_stop == nil or hotkey_stop.data == nil then
-- handle error
obj.free()
return false
end
obs.obs_hotkey_unregister(src.stop)
local timer_mode= _settings.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_stop.next()
local is_shift = _settings.get_bul("hotkey_stop_shift_key")
hotkey.bul("shift", is_shift)
hotkey.free();
end
hotkey_stop.free();obj.free()
utils.update_hotkey(src)
end
end)
obs.obs_property_set_modified_callback(hotkey_stop_key_list, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_stop= obj.get_arr("hotkey_stop")
if hotkey_stop and hotkey_stop.data == nil then
-- handle error
obj.free()
return false
end
local timer_mode= _settings.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_stop.next()
local key= _settings.get_str("hotkey_stop_key_list")
if key == nil or key == "" or key == "" then
key="none"
end
hotkey.str("key", "OBS_KEY_" .. string.upper(key))
hotkey.free();
end
hotkey_stop.free();obj.free()
utils.update_hotkey(src)
end
return true
end)
-- hotkey reset callback
obs.obs_property_set_modified_callback(hotkey_reset_shift_key, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_reset= obj.get_arr("hotkey_reset")
if hotkey_reset == nil or hotkey_reset.data == nil then
-- handle error
obj.free()
return false
end
obs.obs_hotkey_unregister(src.reset)
local timer_mode= _settings.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_reset.next()
local is_shift = _settings.get_bul("hotkey_reset_shift_key")
hotkey.bul("shift", is_shift)
hotkey.free();
end
hotkey_reset.free();obj.free()
utils.update_hotkey(src)
end
return true
end)
obs.obs_property_set_modified_callback(hotkey_reset_key_list, function(props, p, settings)
local _settings= src.setting
if src.source_name ~= nil then
local obj= utils.get_setting_from_source(_settings, src.source_name)
local hotkey_reset= obj.get_arr("hotkey_reset")
if hotkey_reset and hotkey_reset.data == nil then
-- handle error
obj.free()
return false
end
obs.obs_hotkey_unregister(src.reset)
local timer_mode= _settings.get_str("mode")
if timer_mode == "mode4" then
local hotkey= hotkey_reset.next()
local key= _settings.get_str("hotkey_reset_key_list")
if key == nil or key == "" or key == "" then
key="none"
end
hotkey.str("key", "OBS_KEY_" .. string.upper(key))
hotkey.free();
end
hotkey_reset.free();obj.free()
utils.update_hotkey(src)
end
return true
end)
--
local mode_time= utils.obs_properties_add_list(p, "mode_time", "", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
obs.obs_property_list_add_string(mode_time, "Time will count upwards", "mode1")
obs.obs_property_list_add_string(mode_time, "Time will count downwards", "mode2")
local timer_mode2= utils.obs_properties_add_text(p, "timer_mode2", "Timer:", obs.OBS_TEXT_DEFAULT)
obs.obs_property_set_visible(timer_mode2, false)
obs.obs_property_set_long_description(timer_mode2,"format is Hh:Mm:Ss stands for (hours, minutes, seconds)
")
obs.obs_property_set_modified_callback(mode_time, function(props, prop, settings)
local _settings= PairStack(settings, nil, true)
local mode = _settings.get_str("mode_time")
local timer_mode2= obs.obs_properties_get(props, "timer_mode2")
if mode == nil or mode == "" or mode ~= "mode2" then
_settings.str("timer_mode2","")
obs.obs_property_set_visible(timer_mode2, false)
-- if not src.isActive then src.raw_now= "";src.now=0 end
else
obs.obs_property_set_visible(timer_mode2, true)
end
utils.update_source_time(src)
return true;
end)
-- [[ ACTION EVENT GROUP ]] UNDER - DEVELOPMENT COMMING SOON ...
-- local actionOp= obs.obs_properties_create()
-- local action_group = utils.obs_properties_add_group(p, "action_setup_group","Action Event", obs.OBS_GROUP_CHECKABLE , actionOp)
-- local action_group_enable_label= utils.obs_properties_add_text(actionOp, "action_group_enable_label", "(is disabled)", obs.OBS_TEXT_INFO)
-- obs.obs_property_set_visible(action_group_enable_label, false)
-- local action_screen;
-- local action_source= utils.obs_properties_add_list(actionOp, "action_source", "Source:",obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
-- obs.obs_property_set_visible(action_source, false)
-- obs.obs_property_list_add_string(action_source, "(SELECT SOURCE)", "def")
-- local action_event= utils.obs_properties_add_list(actionOp, "action_event", "",obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
-- obs.obs_property_set_visible(action_event, false)
-- local action_event_timing= utils.obs_properties_add_list(actionOp, "action_event_timing", "",obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
-- obs.obs_property_set_visible(action_event_timing, false)
-- obs.obs_property_list_add_string(action_event_timing, "(SELECT EVENT TIMING)", "")
-- -- seconds, minutes, hours
-- local ix=1
-- for i=5, 60, 5 do
-- obs.obs_property_list_add_string(action_event_timing, "every " .. i .. " seconds", i.."s")
-- obs.obs_property_list_add_string(action_event_timing, "every " .. i .. " minutes", i.."m")
-- obs.obs_property_list_add_string(action_event_timing, "every " .. ix .. " hours", ix .."hr")
-- ix =ix+1
-- end
-- local action_execute= utils.obs_properties_add_button(actionOp, "action_execute", "Activate",function() end)
-- obs.obs_property_set_visible(action_execute, false)
-- obs.obs_property_set_modified_callback(action_event_timing, function(props, prop, settings)
-- local _settings= PairStack(settings, nil, true)
-- local event_timing = _settings.get_str("action_event_timing")
-- if event_timing == nil or event_timing == "" or event_timing == "" then
-- obs.obs_property_set_visible(action_execute, false)
-- else
-- obs.obs_property_set_visible(action_execute, true)
-- end
-- return true
-- end)
-- [[ MODE EVENT CALLBACK ]]
obs.obs_property_set_modified_callback(mode, function(props, prop, settings)
local _settings= PairStack(settings, nil, true)
local mode = _settings.get_str("mode")
local show_hotkeys_button= obs.obs_properties_get(props, "show_hotkeys_button")
local previous_mode= src.setting.get_str("source_filter_time_mode")
if mode ~= "mode4" then
obs.obs_property_set_visible(show_hotkeys_button, false)
else
obs.obs_property_set_visible(show_hotkeys_button, true)
end
if previous_mode ~= mode then
src.reset(true);src.stop(true);
end
src.setting.str("source_filter_time_mode", mode)
utils.quick_update(src)
return true;
end)
-- ACTION SOURCE CALLBACK
-- obs.obs_property_set_modified_callback(action_source, function(props, prop, settings)
-- local _settings= PairStack(settings, nil, true)
-- local source_name = _settings.get_str("action_source")
-- _settings.str("action_event", "")
-- _settings.str("action_event_timing", "")
-- obs.obs_property_set_visible(action_event_timing, false)
-- obs.obs_property_set_visible(action_event, false)
-- obs.obs_property_set_visible(action_execute, false)
-- --_settings.str("action_source", "", true)
-- local sceneitem= utils.get_sceneitem(source_name)
-- obs.obs_property_list_clear(action_event)
-- if not (source_name == nil or source_name == "" or source_name == "") then
-- obs.obs_property_set_visible(action_event, true)
-- obs.obs_property_list_add_string(action_event, "(SELECT EVENT)", "")
-- if sceneitem and sceneitem.item ~= nil then
-- local source_id= obs.obs_source_get_unversioned_id(sceneitem.source)
-- if source_id== "ffmpeg_source" then
-- for _, event in pairs(event_video_list) do
-- obs.obs_property_list_add_string(action_event, event.name, event.id)
-- end
-- end
-- sceneitem.release()
-- end
-- for _, event in pairs(event_list) do
-- obs.obs_property_list_add_string(action_event, event.name, event.id)
-- end
-- end
-- return true
-- end)
-- ACTION EVENT CALLBACK
-- obs.obs_property_set_modified_callback(action_event, function(props, prop, settings)
-- local _settings= PairStack(settings, nil, true)
-- local event_name = _settings.get_str("action_event")
-- if event_name == nil or event_name == "" or event_name == "" then
-- _settings.str("action_event_timing", "")
-- obs.obs_property_set_visible(action_event_timing, false)
-- obs.obs_property_set_visible(action_execute, false)
-- else
-- obs.obs_property_set_visible(action_event_timing, true)
-- end
-- return true
-- end)
-- -- ACTION GROUP ACTIVE CALLBACK
-- obs.obs_property_set_modified_callback(action_group, function(props, prop, settings)
-- local _settings= PairStack(settings, nil, true)
-- _settings.str("action_event", "")
-- _settings.str("action_event_timing", "")
-- _settings.str("action_source", "")
-- --local action_group_enable_label= obs.obs_properties_get(actionOp, "action_group_enable_label")
-- local active= false;
-- if _settings.get_bul("action_setup_group") then
-- active=true
-- end
-- obs.obs_property_set_visible(action_group_enable_label, not active)
-- obs.obs_property_set_visible(action_source, active)
-- obs.obs_property_list_clear(action_source)
-- obs.obs_property_list_clear(action_event)
-- obs.obs_property_set_visible(action_event, false)
-- obs.obs_property_set_visible(action_event_timing, false)
-- obs.obs_property_set_visible(action_execute, false)
-- -- all the current source in the scene
-- local sources_names= utils.get_all_source_names_from_scene()
-- obs.obs_property_list_add_string(action_source, "(SELECT SOURCE)", "")
-- for _, source in pairs(sources_names) do
-- obs.obs_property_list_add_string(action_source, source, source)
-- end
-- return true;
-- end)
-- TIMER MODE2 CALLBACK
obs.obs_property_set_modified_callback(timer_mode2, function(props, prop, settings)
local _settings= PairStack(settings, nil, true)
local tm_mode= _settings.get_str("mode_time")
local tm_mode2= _settings.get_str("timer_mode2")
local hours, minutes, seconds = string.match(tm_mode2, "(%d+):(%d+):(%d+)")
if hours == nil or minutes == nil or seconds == nil then
return
end
if tm_mode == "mode2" and src.raw_now ~= tm_mode2 then
src.raw_now= tm_mode2
src.now = (tonumber(hours) * 3600) + (tonumber(minutes) * 60) + tonumber(seconds)
src.setting.int("source_filter_time_value", src.now)
src.setting.str("source_filter_time_raw_value", tm_mode2)
utils.update_source_time(src)
end
return;
end)
return p
end
filter.get_defaults= function(settings)
local _settings= PairStack(settings, nil, true)
-- _settings.str("source-name", "none", true)
_settings.str("mode", "mode1", true)
_settings.str("mode_time", "mode1", true)
_settings.bul("action_setup_group", false, true)
_settings.str("action_source", "", true)
_settings.str("action_event", "", true)
local source_name= _settings.get_str("source_name")
if source_name ~= "" and source_name ~= nil then
-- utils.get_setting_from_source(_settings, source_name, true).free()
end
end
filter.update= function(src, settings)
utils.init_filter_source_size(src)
end
filter.create= function(setting, source)
local _setting= PairStack(setting,nil, true)
local source_name= _setting.get_str("source_name");
local time_mode= _setting.get_str("source_filter_time_mode")
local time_value= _setting.get_int("source_filter_time_value")
local time_raw_value= _setting.get_str("source_filter_time_raw_value")
if time_value == nil or time_mode ~= "mode4" then
time_value= 0; time_raw_value= ""
end
local src= {now= time_value;isActive=false;source_name=source_name; raw_now=time_raw_value;fx=nil;is_dead=false}; src.source= source;
utils.init_filter_source_size(src)
obs.obs_enter_graphics()
src.fx= obs.gs_effect_create(shader, nil, nil)
obs.obs_leave_graphics()
if src.fx ~= mil then
src.params= {width = obs.gs_effect_get_param_by_name(src.fx, "width"); height = obs.gs_effect_get_param_by_name(src.fx, "height")}
else
filter.destory(src)
return nil
end
src.setting= PairStack(setting, nil, true)
local function clock()
if src.is_dead then
obs.timer_remove(clock)
obs.obs_hotkey_unregister(src.start)
obs.obs_hotkey_unregister(src.stop)
obs.obs_hotkey_unregister(src.reset)
obs.obs_frontend_remove_event_callback(src.front_end_callback)
return
end
-- get the filter's source target
local tm_mode=src.setting.get_str("mode_time")
if tm_mode == "mode2" then
if src.now > 0 then
src.now= src.now-1
else -- handle case if src.now is less than 0
-- obs.timer_remove(clock); src.isActive= false
return utils.update_source_time(src)
end
else
src.now= src.now+1
end
return utils.update_source_time(src)
end
function src.start(isPressed)
if not isPressed or src.isActive or src.is_dead then
return
end
src.isActive= true
obs.timer_remove(clock)
obs.timer_add(clock, 1000)
end
function src.stop(isPressed)
if not isPressed then
return
end
obs.timer_remove(clock)
src.isActive= false
end
function src.reset(isPressed)
if not isPressed or src.is_dead then
return
end
local tm_mode=src.setting.get_str("mode_time")
local tm_mode2 = src.setting.get_str("timer_mode2")
if tm_mode == "mode2" then
local hours, minutes, seconds = string.match(tm_mode2, "(%d+):(%d+):(%d+)")
if hours == nil or minutes == nil or seconds == nil then
-- error
else
src.now = (tonumber(hours) * 3600) + (tonumber(minutes) * 60) + tonumber(seconds)
end
else
src.now=0
end
src.stop(true)
utils.update_source_time(src)
return src.start(true)
end
function src.front_end_callback(id)
if src.is_dead then
return
end
local mode= src.setting.get_str("mode")
if mode == "mode1" then
if id == obs.OBS_FRONTEND_EVENT_STREAMING_STARTING or id == obs.OBS_FRONTEND_EVENT_RECORDING_STARTING then
src.reset(true)
elseif id == obs.OBS_FRONTEND_EVENT_RECORDING_STOPPED or id == obs.OBS_FRONTEND_EVENT_STREAMING_STOPPING then
src.stop(true)
end
elseif mode == "mode2" then
if id == obs.OBS_FRONTEND_EVENT_STREAMING_STARTING then
src.reset(true)
elseif id == obs.OBS_FRONTEND_EVENT_STREAMING_STOPPING then
src.stop(true)
end
elseif mode == "mode3" then
if id == obs.OBS_FRONTEND_EVENT_RECORDING_STARTING then
src.reset(true)
elseif id == obs.OBS_FRONTEND_EVENT_RECORDING_STOPPED then
src.stop(true)
end
end
end
obs.obs_frontend_add_event_callback(src.front_end_callback)
utils.quick_update(src)
utils.update_hotkey(src)
return src
end
filter.video_tick= function(src, fps)
utils.init_filter_source_size(src)
end
filter.destroy= function(src, d1,d2, d3)
src.is_dead=true
obs.remove_current_callback()
if src.fx ~= nil then
obs.obs_enter_graphics()
obs.gs_effect_destroy(src.fx)
obs.obs_leave_graphics()
end
-- obs.remove_current_callback()
-- obs.obs_hotkey_unregister(src.start)
-- obs.obs_hotkey_unregister(src.stop)
-- obs.obs_hotkey_unregister(src.reset)
--obs.obs_frontend_remove_event_callback(src.front_end_callback)
src= nil
end
filter.video_render= function(src)
if not src then
return
end
local width= src.width;local height= src.height
if not obs.obs_source_process_filter_begin(src.source, obs.GS_RGBA, obs.OBS_NO_DIRECT_RENDERING) then
obs.obs_source_skip_video_filter(src.source)
return
end
if src.params == nil then
obs.obs_source_process_filter_end(src.source, src.fx, width, height)
return
end
if src.source_name == nil or src.source_name == "" then
src.source_name= obs.obs_source_get_name(obs.obs_filter_get_target(src.source))
src.setting.str("source_name", src.source_name)
utils.get_setting_from_source(src.setting, src.source_name).free()
utils.update_hotkey(src)
end
obs.gs_effect_set_int(src.params.width, width)
obs.gs_effect_set_int(src.params.height, height)
obs.gs_blend_state_push()
obs.gs_blend_function(obs.GS_BLEND_ONE, obs.GS_BLEND_INVSRCALPHA)
obs.obs_source_process_filter_end(src.source, src.fx, width, height)
obs.gs_blend_state_pop()
end
__LIST_SCENE_ITEMS__={}
-- other utils functionalities
utils.quick_update = function(src)
local time_mode= src.setting.get_str("source_filter_time_mode")
if time_mode ~= "mode4" and not src.isActive then
local is_recording = obs.obs_frontend_recording_active()
local is_streaming = obs.obs_frontend_streaming_active()
if is_recording then
src.front_end_callback(obs.OBS_FRONTEND_EVENT_RECORDING_STARTING)
end
if is_streaming then
src.front_end_callback(obs.OBS_FRONTEND_EVENT_STREAMING_STARTING)
end
end
end
utils.get_setting_from_source= function(setting, name, reset)
local obj= setting.get_obj(script_path() .. "_" .. name .. "_setting")
if not obj or obj.data == nil or reset then
if obj then obj.free() end
obj= PairStack()
local hotkey_start=PairStack();hotkey_start.bul("shift", false);hotkey_start.str("key", "OBS_KEY_NONE")
local hotkey_start_arr=ArrayStack();hotkey_start_arr.insert(hotkey_start.data)
local hotkey_stop=PairStack();hotkey_stop.bul("shift", false);hotkey_stop.str("key", "OBS_KEY_NONE")
local hotkey_stop_arr=ArrayStack();hotkey_stop_arr.insert(hotkey_stop.data)
local hotkey_reset=PairStack();hotkey_reset.bul("shift", false);hotkey_reset.str("key","OBS_KEY_NONE")
local hotkey_reset_arr=ArrayStack();hotkey_reset_arr.insert(hotkey_reset.data)
obj.arr("hotkey_start",hotkey_start_arr.data)
obj.arr("hotkey_stop",hotkey_stop_arr.data)
obj.arr("hotkey_reset",hotkey_reset_arr.data)
hotkey_start.free();hotkey_stop.free();hotkey_reset.free()
hotkey_start_arr.free();hotkey_stop_arr.free();hotkey_reset_arr.free()
setting.obj(script_path() .. "_" .. name .. "_setting", obj.data)
end
return obj
end
utils.obs_properties_add_list= function(p, name, desc, type, format)
table.insert(utils.properties, name)
local property= obs.obs_properties_add_list(p, name, desc, type, format)
return property
end
utils.obs_properties_add_button= function(p, name, desc, callback)
table.insert(utils.properties, name)
local property= obs.obs_properties_add_button(p, name, desc, callback)
return property
end
utils.obs_properties_add_text= function(p, name, desc, type)
table.insert(utils.properties, name)
local property= obs.obs_properties_add_text(p, name, desc, type)
return property
end
utils.obs_properties_add_group= function(p, name, desc, type, op)
table.insert(utils.properties, name)
local property= obs.obs_properties_add_group(p, name, desc, type, op)
return property
end
utils.obs_properties_add_bool= function(p, name, desc)
table.insert(utils.properties, name)
local property= obs.obs_properties_add_bool(p, name, desc)
return property
end
utils.hide_all= function(p, src)
-- hide all the properties
for _, property_name in pairs(utils.properties) do
local property= obs.obs_properties_get(p, property_name)
local is_visible= obs.obs_property_visible(property)
if is_visible then
table.insert(utils.history, property_name)
end
if property then
obs.obs_property_set_visible(property, false)
end
end
end
utils.go_back= function(p, src)
if #utils.history <= 0 then
return
end
for _, property_name in pairs(utils.properties) do
-- check property_name is in utils.history then show it else hide it
local property= obs.obs_properties_get(p, property_name)
if property then
local is_visible= false
for _, prop in pairs(utils.history) do
if prop == property_name then
is_visible= true
break
end
end
obs.obs_property_set_visible(property, is_visible)
end
end
utils.history= {}
end
utils.show_hotkeys= function(p, src)
local hotkey_start_group= obs.obs_properties_get(p, "hotkey_start_group")
local hotkey_stop_group= obs.obs_properties_get(p, "hotkey_stop_group")
local hotkey_reset_group= obs.obs_properties_get(p, "hotkey_reset_group")
local mode= src.setting.get_str("mode")
if mode == "mode4" then
obs.obs_property_set_visible(hotkey_start_group, true)
obs.obs_property_set_visible(hotkey_stop_group, true)
obs.obs_property_set_visible(hotkey_reset_group, true)
local hotkey_start_key_list= obs.obs_properties_get(p, "hotkey_start_key_list")
local hotkey_stop_key_list= obs.obs_properties_get(p, "hotkey_stop_key_list")
local hotkey_reset_key_list= obs.obs_properties_get(p, "hotkey_reset_key_list")
obs.obs_property_set_visible(hotkey_start_key_list, true)
obs.obs_property_set_visible(hotkey_stop_key_list, true)
obs.obs_property_set_visible(hotkey_reset_key_list, true)
local hotkey_start_shift_key= obs.obs_properties_get(p, "hotkey_start_shift_key")
local hotkey_stop_shift_key= obs.obs_properties_get(p, "hotkey_stop_shift_key")
local hotkey_reset_shift_key= obs.obs_properties_get(p, "hotkey_reset_shift_key")
obs.obs_property_set_visible(hotkey_start_shift_key, true)
obs.obs_property_set_visible(hotkey_stop_shift_key, true)
obs.obs_property_set_visible(hotkey_reset_shift_key, true)
end
end
utils.update_hotkey= function(src)
local source_name= src.source_name
local obj= utils.get_setting_from_source(src.setting, source_name)
local hotkey_start_arr= obj.get_arr("hotkey_start")
local hotkey_stop_arr= obj.get_arr("hotkey_stop")
local hotkey_reset_arr = obj.get_arr("hotkey_reset")
obs.obs_hotkey_unregister(src.start)
obs.obs_hotkey_unregister(src.stop)
obs.obs_hotkey_unregister(src.reset)
if hotkey_start_arr.data == nil or hotkey_stop_arr.data == nil or hotkey_reset_arr.data == nil then
-- handle error
obj.free()
return
end
-- make sure hotkeys are valid before registering them
local hotkey_start= hotkey_start_arr.next()
local hotkey_stop= hotkey_stop_arr.next()
local hotkey_reset= hotkey_reset_arr.next()
if hotkey_start.data == nil or hotkey_stop.data == nil or hotkey_reset.data == nil then
-- handle error
hotkey_start_arr.free();hotkey_stop_arr.free();hotkey_reset_arr.free()
obj.free()
return
end
local start_key= hotkey_start.get_str("key")
local stop_key= hotkey_stop.get_str("key")
local reset_key= hotkey_reset.get_str("key")
local start_shift= hotkey_start.get_bul("shift")
local stop_shift= hotkey_stop.get_bul("shift")
local reset_shift= hotkey_reset.get_bul("shift")
if (start_key ~= nil and start_key ~= "OBS_KEY_NONE") or start_shift then
local start_id = obs.obs_hotkey_register_frontend(script_path(),"Start (upstreamX) for " .. tostring(source_name), src.start);
obs.obs_hotkey_load(start_id, hotkey_start_arr.data)
end
if (stop_key ~= nil and stop_key ~= "OBS_KEY_NONE") or stop_shift then
local stop_id = obs.obs_hotkey_register_frontend(script_path(),"Stop (upstreamX) for " .. tostring(source_name) , src.stop);
obs.obs_hotkey_load(stop_id, hotkey_stop_arr.data)
end
if (reset_key ~= nil and reset_key
~= "OBS_KEY_NONE") or reset_shift then
local reset_id = obs.obs_hotkey_register_frontend(script_path(),"Reset (upstreamX) for " .. tostring(source_name), src.reset);
obs.obs_hotkey_load(reset_id, hotkey_reset_arr.data)
end
hotkey_start.free();hotkey_stop.free();hotkey_reset.free()
hotkey_start_arr.free();hotkey_stop_arr.free();hotkey_reset_arr.free()
obj.free()
end
utils.update_source_time = function(src)
local source = get_filter_source(src)
if not source then
return
end
local source_id= obs.obs_source_get_unversioned_id(source)
if source_id == "text_gdiplus" then
local text= obs.obs_source_get_settings(source)
local text_settings= PairStack(text, nil, true)
local text_source= text_settings.get_str("text")
local hours= math.floor(src.now/3600)
local minutes= math.floor((src.now%3600)/60)
local seconds= math.floor(src.now%60)
local time= string.format("%02d:%02d:%02d", hours, minutes, seconds)
text_settings.str("text", time)
obs.obs_source_update(source, text)
text_settings.free()
end
end
utils.init_filter_source_size= function(src)
local src_target= obs.obs_filter_get_target(src.source)
if src_target then
src.width= obs.obs_source_get_base_width(src_target)
src.height= obs.obs_source_get_base_height(src_target)
else
src.height=0;src.width=0
end
end
utils.get_sceneitem= function(item_name)
local sourceObject = obs.obs_get_source_by_name(item_name)
local current_source_scene = obs.obs_frontend_get_current_scene()
local current_scene = obs.obs_scene_from_source(current_source_scene)
if current_scene ~= nil and sourceObject ~= nil then
local scene_item = obs.obs_scene_sceneitem_from_source(current_scene, sourceObject)
-- check in groups if the current item doesn't exist;
if not scene_item then
for _, gN in ipairs(__GroupList()) do
local groupSource = obs.obs_get_source_by_name(gN)
if groupSource then
local groupItem = obs.obs_scene_sceneitem_from_source(current_scene, groupSource)
obs.obs_source_release(groupSource)
if groupItem then -- iterate through the items in the group and check for (item_name);
local hasItem = false
local __ls = obs.obs_sceneitem_group_enum_items(groupItem)
if __ls ~= nil then
for _, it in ipairs(__ls) do
local s = obs.obs_sceneitem_get_source(it)
if s ~= nil then
local sN = obs.obs_source_get_name(s)
if sN == item_name then
obs.obs_sceneitem_addref(it)
scene_item = it
hasItem = true; break
end
end
end
obs.sceneitem_list_release(__ls)
end
obs.obs_sceneitem_release(groupItem)
if hasItem then
break
end
end
end
end
end
if current_source_scene ~= nil then obs.obs_source_release(current_source_scene) end
if sourceObject ~= nil then obs.obs_source_release(sourceObject) end
local item_obj = {
index = (#__LIST_SCENE_ITEMS__) + 1;
item = scene_item; source = obs.obs_sceneitem_get_source(scene_item)
}
item_obj["release"] = function()
if item_obj.item ~= nil then
obs.obs_sceneitem_release(item_obj.item)
item_obj.item = nil
table.remove(__LIST_SCENE_ITEMS__, item_obj.index)
return true
end
table.remove(__LIST_SCENE_ITEMS__, item_obj.index)
return false
end
table.insert(__LIST_SCENE_ITEMS__, item_obj)
return __LIST_SCENE_ITEMS__[#__LIST_SCENE_ITEMS__]
end
if current_source_scene ~= nil then obs.obs_source_release(current_source_scene) end
if sourceObject ~= nil then obs.obs_source_release(sourceObject) end
return nil
end
utils.get_all_source_names_from_scene = function(ignoreSource)
local source_name_list = nil
-- Get the current scene
local currentSource = obs.obs_frontend_get_current_scene()
local currentScene = obs.obs_scene_from_source(currentSource)
if currentScene ~= nil and currentSource ~= nil then
-- Enumerate the items in the current scene
local sceneItems = obs.obs_scene_enum_items(currentScene)
if sceneItems ~= nil then
source_name_list = {}
for _, sceneItem in ipairs(sceneItems) do
local source = obs.obs_sceneitem_get_source(sceneItem)
if source ~= nil then
local sourceName = obs.obs_source_get_name(source)
if obs.obs_sceneitem_is_group(sceneItem) then
local __ls = obs.obs_sceneitem_group_enum_items(sceneItem)
if __ls ~= nil then
-- iterate through all the items in the group;
for _, it in ipairs(__ls) do
local s = obs.obs_sceneitem_get_source(it)
if s ~= nil then
local sN = obs.obs_source_get_name(s)
if not ignoreSource then
table.insert(source_name_list, sN)
elseif ignoreSource ~= sN then
table.insert(source_name_list, sN)
end
end
end
obs.sceneitem_list_release(__ls)
end
end
if not ignoreSource then
table.insert(source_name_list, sourceName)
elseif ignoreSource ~= sourceName then
table.insert(source_name_list, sourceName)
end
end
end
end
-- Release the scene items list
obs.sceneitem_list_release(sceneItems)
end
-- Release the current scene source
obs.obs_source_release(currentSource)
return source_name_list
end
-- schedule an event
scheduled_events = {}
function scheduler(timeout)
-- if type(timeout) ~= "number" or timeout < 0 then
-- return obs.script_log(obslua.LOG_ERROR, "[Scheduler] invalid timeout value")
-- end
local scheduler_callback = nil
local function interval()
obs.timer_remove(interval)
if type(scheduler_callback) ~= "function" then
return
end
return scheduler_callback(scheduler_callback)
end
local self = nil; self = {
after = function(callback)
if type(callback) == "function" or type(timeout) ~= "number" or timeout < 0 then
scheduler_callback = callback
else
obs.script_log(obslua.LOG_ERROR, "[Scheduler] invalid callback/timeout " .. type(callback))
return false
end
obs.timer_add(interval, timeout)
end;push = function(callback)
if callback == nil or type(callback) ~= "function" then
obs.script_log(obslua.LOG_WARNING, "[Scheduler] invalid callback at {push} " .. type(callback))
return false
end
obs.timer_add(callback, timeout)
table.insert(scheduled_events, callback)
return {
clear = function()
if callback == nil or type(callback) ~= "function" then
return nil
end
return obs.timer_remove(callback)
end;
}
end; clear = function()
if scheduler_callback ~= nil then
obs.timer_remove(scheduler_callback)
end
for _, clb in pairs(scheduled_events) do
obs.timer_remove(clb)
end
scheduled_events = {}; scheduler_callback = nil
end
}
return self
end
OBS_SCENEITEM_TYPE = 1;OBS_SRC_TYPE = 2;OBS_OBJ_TYPE = 3
OBS_ARR_TYPE = 4;OBS_SCENE_TYPE = 5;OBS_SCENEITEM_LIST_TYPE = 6
OBS_SRC_LIST_TYPE = 7;OBS_UN_IN_TYPE = -1
obs_wrap_source = {};
function obs_wrap_source(object, object_type)
local self = nil
self = {
type = object_type, data = object;free = function()
if self.type == OBS_SCENE_TYPE then
obs.obs_scene_release(self.data)
elseif self.type == OBS_SRC_TYPE then
obs.obs_source_release(self.data)
elseif self.type == OBS_ARR_TYPE then
obs.obs_data_array_release(self.data)
elseif self.type == OBS_OBJ_TYPE then
obs.obs_data_release(self.data)
elseif self.type == OBS_SCENEITEM_TYPE then
obs.obs_sceneitem_release(self.data)
elseif self.type == OBS_SCENEITEM_LIST_TYPE then
obs.sceneitem_list_release(self.data)
elseif self.type == OBS_SRC_LIST_TYPE then
obs.source_list_release(self.data)
elseif self.type == OBS_UN_IN_TYPE then
self.data = nil
return
else
self.data = nil
end
end
}
table.insert(error_wrapper, self)
return self
end
error_freed = 0
error_wrapper = {};function error_wrapper_handler (callback)
return function(...)
local args = {...}
local data = nil
local caller = ""
for i, v in ipairs(args) do
if caller ~= "" then
caller = caller .. ","
end
caller = caller .. "args[" .. tostring(i) .. "]"
end
caller = "return function(callback,args) return callback(" .. caller .. ") end";
local run = loadstring(caller)
local success, result = pcall(function()
data = run()(callback, args)
end)
if not success then
error_freed = 0
for _, iter in pairs(error_wrapper) do
if iter and type(iter.free) == "function" then
local s, r = pcall(function()
iter.free()
end)
if s then
error_freed = error_freed + 1
end
end
end
obs.script_log(obs.LOG_ERROR, "[ErrorWrapper ERROR] => " .. tostring(result))
end
return data
end
end
-- array handle
function ArrayStack(stack, name, ignoreStack)
if not ignoreStack then
if type(stack) ~= "userdata" then
stack = nil
elseif stack and (type(name) ~= "string" or name == "")then
stack = nil
obs.script_log(obs.LOG_ERROR, "FAILED TO LOAD AN [ArrayStack] INVALID NAME GIVEN")
return nil
end
end
local self = nil
self = {
index = 0;get = function(index)
if type(index) ~= "number" or index < 0 then
return nil
end
if index > self.size() then
return nil
end
return obs_wrap_source(obs.obs_data_array_item(self.data, index),OBS_OBJ_TYPE)
end;next = function()
if type(self.index) ~= "number" or self.index < 0 or self.index > self.size() then
return nil
end
local temp = self.index;self.index = self.index + 1
return PairStack(obs.obs_data_array_item(self.data, temp), nil, true)
end;free = function()
if self.data == nil then
return false
end
obs.obs_data_array_release(self.data)
self.data = nil
return true
end;insert = error_wrapper_handler(function(value)
if value == nil or type(value) ~= "userdata" then
obs.script_log("FAILED TO INSERT OBJECT INTO [ArrayStack]")
return false
end
obs.obs_data_array_push_back(self.data, value)
end); size = error_wrapper_handler(function()
if self.data == nil then
return 0
end
return obs.obs_data_array_count(self.data);
end);
}
if not ignoreStack then
if stack and name then
self.data = obs.obs_data_get_array(stack, name)
else
self.data = obs.obs_data_array_create()
end
else
self.data = stack
end
table.insert(error_wrapper, self)
return self
end
-- pair stack used to manage memory stuff :)
function PairStack(stack, name, ignoreStack)
if not ignoreStack then
if type(stack) ~= "userdata" then
stack = nil
elseif stack and (type(name) ~= "string" or name == "")then
stack = nil
obs.script_log(obs.LOG_ERROR, "FAILED TO LOAD AN [PairStack] INVALID NAME GIVEN")
return nil
end
end
local self = nil; self = {
free = function()
if self.data == nil then
return false
end
obs.obs_data_release(self.data)
self.data = nil
return true
end; str = error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (self.data == nil or type(self.data) ~= "userdata") or (value == nil or type(value) ~="string") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT STR INTO [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return false
end
if def then
obs.obs_data_set_default_string(self.data, name, value)
else
obs.obs_data_set_string(self.data, name, value)
end
return true
end);int = error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (self.data == nil or type(self.data) ~= "userdata") or (value == nil or type(value) ~="number") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT INT INTO [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return false
end
if def then
obs.obs_data_set_default_int(self.data, name, value)
else
obs.obs_data_set_int(self.data, name, value)
end
return true
end);dbl=error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (self.data == nil or type(self.data) ~= "userdata") or (value == nil or type(value) ~="number") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT INT INTO [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return false
end
if def then
obs.obs_data_set_default_double(self.data, name, value)
else
obs.obs_data_set_double(self.data, name, value)
end
return true
end);bul = error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (self.data == nil or type(self.data) ~= "userdata") or (type(value) == "nil" or type(value) ~="boolean") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT BUL [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return false
end
if def then
obs.obs_data_set_default_bool(self.data, name, value)
else
obs.obs_data_set_bool(self.data, name, value)
end
return true
end); arr = error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (self.data == nil or type(self.data) ~= "userdata") or (type(value) ~="userdata") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT ARR INTO [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return false
end
if def then
obs.obs_data_set_default_array(self.data, name, value)
else
obs.obs_data_set_array(self.data, name, value)
end
return true
end); obj = error_wrapper_handler(function(name, value, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata") or (type(value) ~="userdata") then
obs.script_log(obs.LOG_ERROR,"FAILED TO INSERT OBJ INTO [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if def then
obs.obs_data_set_default_obj(self.data, name, value)
else
obs.obs_data_set_obj(self.data, name, value)
end
return true
end);
-- getter
get_str = error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata")then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET STR FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return obs.obs_data_get_string(self.data, name)
else
return obs.obs_data_get_default_string(self.data, name)
end
end);get_int = error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata")then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET INT FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return obs.obs_data_get_int(self.data, name)
else
return obs.obs_data_get_default_int(self.data, name)
end
end);get_dbl = error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata")then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET DBL FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return obs.obs_data_get_double(self.data, name)
else
return obs.obs_data_get_default_double(self.data, name)
end
end);get_obj = error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata")then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET OBJ FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return PairStack(obs.obs_data_get_obj(self.data, name), nil, true)
else
return PairStack(obs.obs_data_get_default_obj(self.data, name), nil, true)
end
end);get_arr =error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata")then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET ARR FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return ArrayStack(obs.obs_data_get_array(self.data, name), nil, true)
else
return ArrayStack(obs.obs_data_get_default_array(self.data, name), nil, true)
end
end);get_bul = error_wrapper_handler(function(name, def)
if (name == nil or type(name) ~= "string" or name == "") or (type(self.data) ~= "userdata") then
obs.script_log(obs.LOG_ERROR,"FAILED TO GET BUL FROM [PairStack] " .. "FOR [" .. tostring(name) .. "] " .. " OF VALUE [" .. tostring(value) .. "] TYPE: " .. tostring(type(value)))
return nil
end
if not def then
return obs.obs_data_get_bool(self.data, name)
else
return obs.obs_data_get_default_bool(self.data, name)
end
end); del= error_wrapper_handler(function(name)
obs.obs_data_erase(self.data, name)
return true
end)
}
if not ignoreStack then
if stack and name then
self.data = obs.obs_data_get_obj(stack, name)
else
self.data = obs.obs_data_create()
end
else
self.data = stack
end
table.insert(error_wrapper, self)
return self
end
--[[ MAIN SOURCE INIT STARTUP FUNCTIONS]]
function script_load(settings)
obs.obs_register_source(filter)
end
function WelcomeHome()
return [[
UpstreamX - 2.0
Select a source and add a filter called 'UpstreamX'.
Useful Links
Video Tutorial: click here
Dev
Author: @iixisii
updates follow XDeviixisiiX
]]
end
function script_properties()
local p = obs.obs_properties_create()
utils.obs_properties_add_text(p, "label", WelcomeHome(), obs.OBS_TEXT_INFO)
return p;
end
shader = [[
uniform float4x4 ViewProj;
uniform texture2d image;
uniform int width;
uniform int height;
sampler_state textureSampler {
Filter = Linear;
AddressU = Border;
AddressV = Border;
BorderColor = 00000000;
};
struct VertData
{
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};
float4 ps_get(VertData v_in) : TARGET
{
return image.Sample(textureSampler, v_in.uv.xy);
}
VertData VSDefault(VertData v_in)
{
VertData vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}
technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = ps_get(v_in);
}
}
]]