OBS Stopwatch Script Update 5.9
OBS Stopwatch Script Update 5.9
-----------------------------------------------------------------------------------
-----------------------------------------------------
Open Broadcaster Software®️
OBS > Tools > Scripts
@midnight-studios
Stopwatch
***********************************************************************************
****************************************************
Version 5.9
NEW FEATURES
OPTIMIZATION
BUGS
- Fixed error on load for setting 'Autoload last time stamp when OBS starts'
@goods0ul
NOTES
***********************************************************************************
****************************************************
]]
--Globals
obs = obslua;
gversion = "5.9";
luafile = "[Link]";
obsurl = "comprehensive-stopwatch-countdown-
timer.1364/";
patch_notes = "Patch Notes";
icon="data:image/
png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAENElEQVQ4jY1UTUgjZxh+ksl/
JuMkMYb4F40bNZqK0KJFqBZqS9ddyl76dyhdKPRQShH2sNDSnnopCz11D10KS/
dSKNiDoD2I7KXFQ0XSSGpM1llFMYn5mZiMY2IymfIOhgazXfaDj5n53u975vme531fnaqqeMHxJYCvAOgAl
ABcAyA1jxLO1tYW1tbWoL+Kd3x8jGg0imw2C0VRWkMEYgNgBeAFYKTFRqOh7aVnE9xwFTSZTGJ7exszMzPQ
6XSQZRk8z9P7YrVa/Y5hmKLBYHCpqirW63Wcn5/
j7OwMHo9HA6bvNqY2mw1Op1N70qaTkxPkcjmbLMsDZrN5hOO4NxuNhlMUxTFiSCA0FEW5GQ6H/
wmHwzfamDavUKlUYDKZAoFA4Gue52/r9f/9v6OjQ5uKojwpFAr3RFF8UCwWjW63OzQ/P/
9yGyiBnZ6eEtN3eZ7/9XJZrlQqP2cymcf5fL4QDAbHdTrd2yzLXvd4PD9yHHdLEISFXC7nsdvtuTb3c7kcE
okEJiYmhliWtaiqWs5ms4f1el0lE2lOTU0hn8/
DYrF09vb23jebze9JkvRXNBqdMpvNaIJaLh1tHScAzpvsSd+joyOkUimEQiFNa4vFAlEU4Xa7HwYCgduFQu
HRxsbGx5p+qqq+o/7/
SF7uQSaTwcHBgZYdgiBMqKqa2dnZ8S8tLaFcLicIIR6PjzU13Qew+gzPKNEj9JJOp5tag+O41/v7+x/
v7u7+sLOzc8BxHN1icXR0dMXlcn3xQhW1v7+PSCSC6enptxwOx3WWZRcbjcbTjY2NAJ1nWRYGgwHj4+Oqoi
gFYnr/
UlPlClYFwJ1arVYjU8bGxhZ8Pt9KMxiLxd5gGEbTlTSv1WqQJOmJw+G4RqCfPYfkN4qiFDs7O9HT0/
Nqa4BhmKd2u10DrFaruLi4oJmncibQSUCrLHJabDlHzItGo1E7FIvFvg+FQjMmkykkCMK9eDwOivl8PvqhB
spxXJAOEujfz2HazzBMdXh4OJNMJoupVGre7/
cbBEGor6+vY2RkROsLlwY6jUajS5KkSGvtf0oVemUeAPiDgsFgUHMeQJ3MmZycxNzcnMZWkiT4/
f67FJRl+UFrmcYB/
N7y3UyLSHOBzNjb20MgEMDg4CC6urqwublJZo12d3ffVRRFEQTh4TNTqlQqaawoTShOVdOsqMPDQ8zOzmqF
QK3PZrO91NPTs2U0GkmWG4lEYrWt9cViMSwvL1Ntvw9gRafT/aTX6z8AwFKcuhU5zjDMkNfr/
XZgYCBKgMfHx3eSyeSqw+Fob9LEipxMp9MRp9P5uclkWuB5/
hOKWa3Wvb6+vjLP8wNer5fXUkRRLkql0ofZbPY3ug019TZQ6jKU0AzD7Iqi+Josy6+4XK6P7Hb7LbvdPkS5
SXpXKpU/ZVn+5ezs7FG9Xi9brVZNLr1ej38BVDs6EbSfFQsAAAAASUVORK5CYII=";
desc =
[[
<hr/><center><h2>Advanced Timer</h2>( Version: %s )</center>
<br><center><img width=38 height=42 src="]] .. icon .. [["/></center>
<br><center><a href="[Link] ..
luafile ..[[">Find it on GitHub</a></center>
<center><a href="[Link] .. obsurl ..
[[updates">]] .. patch_notes ..[[</a></center>
<br><p>The script's visibility adjusts with layout settings: "Advanced" shows
advanced properties. "Basic" hides them but keeps values active, so set them
correctly.</p><p>Find help on the <a
href="[Link] .. obsurl ..[[">OBS Forum
Thread</a>.</p><hr/>
]];
debug_file = ""
debug_file_name = "Debug Log"
text_prefix = "";
text_suffix = "";
text_prefix_validated = "";
text_suffix_validated = "";
last_text = "";
custom_time_format = "";
timer_source = "";
timer_activation_source = "";
countdown_type = "";
backup_folder = "";
import_list = "";
longtimetext_s = "";
longtimetext_p = "";
last_split_data = "";
split_source = "";
active_source = "";
timer_expire_event = "";
cycle_source_children = "";
stop_text = "";
toggle_mili_trigger = "";
sec_add_1 = "";
sec_add_2 = "";
sec_add_3 = "";
sec_sub_1 = "";
sec_sub_2 = "";
sec_sub_3 = "";
output_file_name = "-backup($date_stamp)";
output_file_ext = ".json";
font_normal = "#ffffff";
font_dimmed = "#bfbbbf";
font_highlight = "#fffdcf";
add_limit_note_source = "";
sub_limit_note_source = "";
note_source_marker_a = "";
note_source_marker_b = "";
audio_marker_a = "";
audio_marker_b = "";
current_count_direction = "UP";
count_orientation = "NORMAL";
timer_activation = 1;
timer_reset = 0;
debug_entry = 0;
debug_entry = 0;
add_limit_note_source_visible = 0;
sub_limit_note_source_visible = 0;
sources_loaded = 0;
timer_manipulation = 1;
sec_add_limit = 0;
sec_add_limit_used = 0;
sec_sub_limit_used = 0;
sec_sub_limit = 0;
total_sources = 0;
sw_days_saved = 0;
sw_hours_saved = 0;
sw_minutes_saved = 0;
sw_seconds_saved = 0;
sw_milliseconds_saved = 0;
split_type = 2;
current_seconds = 0;
cycle_direction = 1;
default_seconds = 0;
split_count = 0;
timer_year = 0;
timer_month = 0;
timer_day = 0;
timer_hours = 0;
timer_minutes = 0;
timer_seconds = 0;
timer_mode = 0;
last_timer_mode = 0;
timer_format = 1;
start_recording = 1;
media_playback_limit = 0;
enable_marker_notes = 1;
orig_time = 0;
time_frequency = 0;
completed_cycles = 0;
ns_last = 0;
cycle_index = 1;
timer_cycle = 10; --milliseconds
split_itm = {};
connectedHandlers = {};
presuf = {
text_marker_a = "",
text_marker_b = ""
}
ignore_list = {
"",
"none",
"None",
"Select",
"select",
"list"
};
split_data = nil;
hour_format = nil;
minute_format = nil;
local ctx = {
propsDef = nil, -- property definition
propsDefSrc = nil, -- property definition (source scene)
propsSet = nil, -- property settings (model)
propsVal = {}, -- property values
propsValSrc = nil, -- property values (first source scene)
};
props = nil;
enable_property_toggle_mili_trigger = true;
set_visible_properties = false;
enable_property_color_normal = true;
enable_property_color_marker_a = true;
enable_property_color_marker_b = true;
enable_property_split_source = true;
enable_property_trigger_options = true;
enable_property_start_recording = true;
enable_property_text_prefix = true;
enable_property_text_suffix = true;
enable_property_timer_manipulation = true;
enable_property_timer_activation = true;
enable_property_debug = true;
enable_property_backup = true;
timer_event_active = false;
timer_mode_changed = false;
debug_enabled = false; -- careful, may use more
system memory
script_ready = false;
set_timer_activated = false;
color_normal_updated = false;
activated = false;
prevent_callback = false;
timer_active = false;
reset_activated = false;
active_source_force_visible = false;
split_startpause = false;
disable_script = false;
enable_direction_toggle = false;
backup_split_time = false;
show_mili = true;
timer_expired = true;
mili_toggle_triggered = false;
direction_changed = false;
prevent_negative_time = false;
record_timer_set = false;
media = { -- table start
text_marker_a = "",
text_marker_b = "",
source_name_audio_marker_a = "",
source_name_audio_marker_b = "",
source_name_audio_marker_end = "",
note_source_marker_a = "",
note_source_marker_b = "",
note_source_unversioned_id_marker_a = "";
note_source_unversioned_id_marker_b = "";
note_marker_a = "",
note_marker_b = "",
activated_marker_a = false,
activated_marker_b = false,
activated_media_marker_a = false,
activated_media_marker_b = false,
activated_time_marker_a = 0,
activated_time_marker_b = 0,
cycle_direction_marker_a = 2;
cycle_direction_marker_b = 2;
cycle_index_marker_a = 1; -- index from 1-based table
cycle_index_marker_b = 1; -- index from 1-based table
cycle_index_note_marker_a = 1; -- index from 1-based table
cycle_index_note_marker_b = 1; -- index from 1-based table
current_seconds_marker_a = 0,
current_seconds_marker_b = 0,
duration_marker_a = 0,
duration_marker_b = 0,
reset_text_marker_a = 0,
reset_text_marker_b = 0,
hide_note_marker_a = 0,
hide_note_marker_b = 0,
duration_marker_end = 0,
last_orientation_marker_a = "NORMAL";
last_orientation_marker_b = "NORMAL";
media_ended_marker_a = false,
media_ended_marker_b = false,
last_state_marker_a = obs.OBS_MEDIA_STATE_NONE,
last_state_marker_b = obs.OBS_MEDIA_STATE_NONE
}; -- table end
selected_source_list = {};
hotkey_id_reset = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_start = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_pause = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_split = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_mili = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_direction = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_add_1 = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_add_2 = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_add_3 = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_sub_1 = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_sub_2 = obs.OBS_INVALID_HOTKEY_ID;
hotkey_id_sec_sub_3 = obs.OBS_INVALID_HOTKEY_ID;
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
With a deque, removing items from both ends is fast regardless of the size of
the deque.
Whenever a new item is used, it's added to the deque with pushleft().
When required it removes the oldest item with popright().
]]
local Deque = {} -- Declare the Deque table to act as the class
Deque.__index = Deque -- Set the __index of Deque to itself to allow method
lookups.
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: This method adds a value to the start (left) of the Deque
Method to add a value to the front (left) of the Deque.
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function Deque:pushleft(value)
-- We decrease the index for the 'first' element.
local first = [Link] - 1
-- Assign the new index as our new 'first' index.
[Link] = first
-- Assign the passed value at the new 'first' position.
self[first] = value
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: This method removes a value from the end (right) of the Deque
and returns it
This method also returns the removed value.
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function Deque:popright()
-- We store the 'last' index in a local variable.
local last = [Link]
-- If 'first' index is greater than 'last', then the Deque is empty.
if [Link] > last then error("deque is empty") end
-- We store the value at the 'last' index in a local variable.
local value = self[last]
-- Remove the value from the Deque.
self[last] = nil
-- Decrease the 'last' index by one, moving it one step to the left.
[Link] = last - 1
-- Return the removed value.
return value
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Credit: OBS
Modified: User dependent
function: Script Description
type: OBS Core
input type: data
returns: string
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function script_description()
debug_log( 'script_description() -- function variable names: ' )
return [Link]( desc, tostring( gversion ) );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Get the name of this script
Credit: midnight-studios, et al
Modified:
function: regular expression
type: Support
input type: string
returns: string
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function filename()
local str = [Link](2).source:sub(2);
return str:match("^.*/(.*).lua$") or str;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Dumps input to string, if input is a table it returns the
expanded table
Credit: et al
Modified: yes
function:
type: Support (debug tool)
input type: variable
returns: string
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function pre_dump(input, visited)
visited = visited or {}
local tbl = {}
for key, value in pairs(input) do
local keyStr = (type(key) ~= "number") and "'" .. tostring(key) .. "'" or
tostring(key)
tbl[#tbl + 1] = "[" .. keyStr .. "] = " .. "'" .. pre_dump(value,
visited) .. "'"
end
visited[input] = nil -- Remove the current table from visited to allow for
other references
return "{ " .. [Link](tbl, ", ") .. " }"
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Use this to create a Script Log Output used in testing
Credit: et al
Modified: No
function:
type: Support (debug tool)
input type: string
returns: print(string)
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function log( name, msg )
if msg ~= nil then
msg = " > " .. tostring( msg );
else
msg = "";
end;
obs.script_log( obs.LOG_DEBUG, tostring( name ) .. msg );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function debug_log( content )
if disable_script then return; end;
if not debug_enabled or not enable_property_debug then
return
end
if debug_file == "" then
debug_file = create_debug_file( debug_file_name, content )
else
update_debug_file( debug_file, content )
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function create_debug_file( input_file_name, content )
if disable_script then return; end;
content = content or [Link]( "%s [%s]\n", "Debug Information",
[Link]("%Y-%m-%d_%H.%M.%S"))
local file_name = [Link]( "%s-%s[%s]%s", filename(), input_file_name,
[Link]("%Y-%m-%d_%H.%M.%S"), ".txt");
-- set output path as the script path by default
local script_path = script_path();
local output_path = script_path .. file_name;
-- if specified output path exists, then set this as the new output path
output_path = script_path .. file_name;
output_path = output_path:gsub( [[\]], "/" );
log( "create_debug_file", output_path )
-- Open file in write mode, this will create the file if it does not exist
local file = [Link]( output_path, "w" )
-- If the file has been opened successfully
if file then
-- Write content to the file
file:write( content )
-- Close the file
file:close()
else
-- Print error message
print("Failed to open file " .. file_name .. " for writing")
end
return output_path;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function rewrite_line_debug_file( filename, line_num, content )
if disable_script then return; end;
-- Store all lines in memory
local lines = {}
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_debug_file( filename, content )
if disable_script then return; end;
if filename ~= nil then
debug_entry = debug_entry + 1
content = tostring(debug_entry) .. ") " .. [Link]( " ",
[Link](debug_entry) ) .. content
-- Open file in append mode
local file = [Link]( filename, "a" )
-- If the file has been opened successfully
if file then
-- Write new content on a new line
file:write( "\n" .. content )
-- Close the file
file:close()
else
-- Print error message
print("Failed to open file " .. tostring(filename) .. " for
appending. Could not add content: " .. pre_dump(content))
end
-- adds unnecessary processing
--rewrite_line_debug_file( filename, 2, "Last item entered: " ..
content )
else
--print("Failed " .. tostring(filename) .. " Does not exist. Could not
add content: " .. pre_dump(content))
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Builds a table by splitting a string by defined character
or sequence of characters marking
the beginning or end of a unit of data. That which
delimits, that separates.
Credit: midnight-studios, et al
Modified:
function: breaks string into sections by a reference that is returned
in a table
type:
input type: string, delimiter
returns: table
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function explode_alt( str, delim )
debug_log( 'explode_alt(' .. pre_dump(str) .. ", " .. pre_dump(delim) .. ') --
function variable names: str, delim ' )
local tbl, index;
tbl = {};
index = 0;
if( #str == 1 ) then return {str} end; -- returns a table with the input string
as the only value
while true do
local trace_index = [Link]( str, delim, index, true ); -- find the next
d in the string
if trace_index ~= nil then -- if "not not" found then..
[Link]( tbl, [Link]( str, index, trace_index - 1 ) ); -- Save it
in our array.
index = trace_index + 1; -- save just after where we found it for
searching next time.
else
[Link]( tbl, [Link]( str, index ) ); -- Save what's left in our
array.
break; -- Break at end, as it should be, according to the lua manual.
end;
end;
return tbl;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Builds a table by splitting a string by defined character
or sequence of characters marking
the beginning or end of a unit of data. That which
delimits, that separates.
Credit: midnight-studios, et al
Modified:
function: breaks string into sections by a reference that is returned
in a table
type:
input type: string, delimiter
returns: table
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function explode( str, div )
debug_log( 'explode(' .. pre_dump(str) .. ", " .. pre_dump(delim) .. ') --
function variable names: str, delim ' )
if ( div == nil or div == '' ) or ( str == nil or str == '' ) then return {}
end
local pos, arr = 0, {}
for st, sp in function() return [Link](str, div, pos, true) end do
[Link](arr, [Link](str, pos, st - 1))
pos = sp + 1
end
[Link](arr, [Link](str, pos))
return arr
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Gives you an iterator that moves through an
ordinary table (eg. string keys) but sorted
into key sequence.
It does that by copying the table keys into
a temporary table and sorting that.
Credit:
[Link]
[Link]
If you need to sort keys other than strings, see:
See: [Link]
Modified: Yes, minor changes
function: support: This prints the math functions in key order
type: sort table
input type: table, function (optional)
returns: table
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function pairsByKeys( tbl, input_function )
debug_log( 'pairsByKeys(' .. pre_dump( tbl ) .. ", " ..
pre_dump( input_function ) .. ')')
if type( tbl ) ~= "table" then return tbl end
-- instead of creating a new table and inserting all items into it, just get
the keys
local keys = {}
for k in pairs(tbl) do keys[#keys+1] = k end
local i = 0
local iter = function ()
i = i + 1
if keys[i] == nil then
return nil
else
-- use keys[i] to get value from tbl
return keys[i], tbl[keys[i]]
end
end
return iter
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function reverseTable( tbl )
if type( tbl ) ~= "table" then return nil, "Provided variable is not valid
Table"; end
-- Determine the base of the table (0 or 1)
local base = (tbl[0] ~= nil) and 0 or 1
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function getTableBase( tbl )
if type( tbl ) ~= "table" then return nil, "Provided variable is not valid
Table"; end
-- Check if index 0 is non-nil
if tbl[0] ~= nil then
return 0
elseif tbl[1] ~= nil then
return 1
else
return nil, "Table is empty or does not have consecutive integer keys
starting from 0 or 1";
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function tableHasValue( table )
debug_log( 'tableHasValue(' .. pre_dump( table ) .. ') -- function variable
names: table ' )
if type( table ) ~= "table" then return false end
return next(table) ~= nil
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Provides the length of a table
(how many items the table contains)
Credit: midnight-studios, et al
Modified: Author
function: Create a table with unique items
type: Support
input type: table
returns: integer
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function tablelength( tbl )
debug_log( 'tablelength(' .. pre_dump(tbl) .. ') -- function variable names:
tbl ' )
local count = 0;
if type( tbl ) == "table" then -- if the input table is not of type table
return 0
for _ in pairs( tbl ) do count = count + 1 end;
end;
return count;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove duplicated values from table
Credit: midnight-studios, et al
Modified: Author
function: Create a table with unique items
type: Support
input type: table, string
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function tableHasKey( tbl, key )
debug_log( 'tableHasKey(' .. pre_dump(tbl) .. ", " .. pre_dump(key) .. ') --
function variable names: tbl, key ' )
if type( tbl ) ~= "table" or key == nil then return false end; -- if the
input table is not of type table return bool(false)
return tbl[key] ~= nil;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove duplicated values from table
Credit: midnight-studios, et al
Modified: Author
function: Create a table with unique items
type: Support
input type: table, string
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function in_table(tbl, input_value)
debug_log( 'in_table(' .. pre_dump( tbl ) .. ", " .. pre_dump(input_value) ..
') -- function variable names: tbl, input_value ' )
if type(tbl) ~= "table" or input_value == nil then
return false
end
return false
end
--[[
----------------------------------------------------------
Description: Function to connect a signal handler and store its
information
[Link]
highlight=media_started
attach event listener callback [source_signal]: Called when
media has ended.
Credit:
Modified:
function:
type:
input type:
returns:
----------------------------------------------------------
]]
function connectSignalHandler( source, signal, callback )
local sh = obs.obs_source_get_signal_handler( source )
if sh then
local sourceId = obs.obs_source_get_id( source )
Credit:
Modified:
function:
type:
input type:
returns:
----------------------------------------------------------
]]
function refresh_properties()
debug_log( 'refresh_properties() -- function variable names: ' )
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function checkTimeString( str )
debug_log( 'checkTimeString(' .. pre_dump( str ) .. ') -- function variable
names: str' )
if str == nil then return false end
-- Pattern to match the format '00:00:00'
local pattern = "^%d%d:%d%d:%d%d$"
-- Check if the string matches the pattern
if [Link]( str, pattern ) then
return true
else
return false
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function removeDuplicates( tbl )
debug_log( 'removeDuplicates(' .. pre_dump( tbl ) .. ') -- function variable
names: tbl' )
if type( tbl ) ~= "table" or tbl == nil then return tbl end; -- if the input table
is not of type table return input
local seen = {}
local result = {}
return result
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: A function named script_update will be called when settings
are changed
Credit:
Modified:
function: Called upon settings initialization and modification
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function convertToSeconds(timeString)
debug_log( 'convertToSeconds(' .. pre_dump(timeString) .. ') -- function
variable names: timeString' )
local hours, minutes, seconds = [Link](timeString, "(%d%d):(%d%d):(%d%d)")
return totalSeconds
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function get_source_type_by_name( source_name )
local source = obs.obs_get_source_by_name( source_name );
local result
if source ~= nil then
result = obs.obs_source_get_type( source )
end
obs.obs_source_release( source );
return result
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function get_source_unversioned_id_by_name( source_name )
local source = obs.obs_get_source_by_name( source_name );
local result
if source ~= nil then
result = obs.obs_source_get_unversioned_id( source )
end
obs.obs_source_release( source );
return result
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Take the provided source_name for a Scene Item and search
for it.
If the provided source name exists, find any children
sources. This applies to groups or scenes.
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function list_source_children_by_source_name( source_name, filter_unversioned_id )
--[[
we use this part more than once
]]
local function get_group_children_from_source( group, list )
local group_items_source =
obs.obs_sceneitem_get_source( group_item ) -- grab the source of the group child
item
local source_name_group =
obs.obs_source_get_name( group_items_source ) -- this is what we need,
local source_name_type =
obs.obs_source_get_unversioned_id( group_items_source )
end
end
--[[
start
]]
local list = {}
local scene_items =
obs.obs_scene_enum_items( scene ) -- check if the scene has any children
local item_source =
obs.obs_sceneitem_get_source( scene_item_source ) -- grab the source of the scene
child item
local source_name_parent =
obs.obs_source_get_name( item_source ) -- get the source name, we will save it for
later
local group =
obs.obs_group_from_source( item_source )
local source_name_type =
obs.obs_source_get_unversioned_id( item_source )
if group then
end
end
obs.sceneitem_list_release( scene_items )
end
end
end
end
obs.source_list_release( scenes )
end
reverseTable( list )
return list
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function frontend_get_current_scene()
-- Get the current scene
local current_scene = obs.obs_frontend_get_current_scene()
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function frontend_set_current_scene( scene_name )
local source = obs.obs_get_source_by_name( scene_name );
if source ~= nil then
obs.obs_frontend_remove_event_callback( on_event )
obs.obs_frontend_set_current_scene( source )
obs.obs_frontend_add_event_callback( on_event )
end
obs.obs_source_release( source );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: set source visibility
Credit: midnight-studios, et al
Modified:
function: Update Text Source
type: Support, Render
input type:
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_visible( source_name, visible )
debug_log( 'set_visible(' .. pre_dump(source_name) .. ", " .. pre_dump(visible)
.. ') -- function variable names: source_name, visible ' )
visible = visible or false;
local action_completed = false;
Credit: midnight-studios, et al
Modified:
function: Check source visibility state by name
type:
input type: source name (string)
returns: boolean
----------------------------------------------------------
]]
local function is_visible( source_name )
debug_log( 'is_visible(' .. pre_dump(source_name) .. ') -- function variable
names: source_name ' )
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function compareTimeStrings( timeString1, timeString2 )
debug_log( 'compareTimeStrings(' .. pre_dump(timeString1) .. ", " ..
pre_dump(timeString2) .. ') -- function variable names: timeString1, timeString2' )
-- Extract hours, minutes, and seconds from time strings
local hours1, minutes1, seconds1 = [Link](timeString1, "(%d%d):(%d%d):(%d
%d)")
local hours2, minutes2, seconds2 = [Link](timeString2, "(%d%d):(%d%d):(%d
%d)")
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sortTimeTable( tbl )
debug_log( 'sortTimeTable(' .. pre_dump(tbl) .. ') -- function variable names:
tbl' )
if type( tbl ) ~= "table" or tbl == nil then return tbl end; -- if the input
table is not of type table return input
[Link](tbl, compareTimeStrings)
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: custom function
we use this to get a count of essential sources
Credit:
Modified:
function:
type:
input type:
returns: interger
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function count_required_sources()
debug_log( 'count_required_sources() -- function variable names: ' )
local sources = obs.obs_enum_sources();
local i = 0;
if sources ~= nil then
for _, source in ipairs( sources ) do -- ipairs cycles auto incrimented
items
local name = obs.obs_source_get_name( source ); -- Get the source
name, this will be a unique identifier
local id = obs.obs_source_get_id( source )
if in_table( required_sources, id ) then
i = i + 1;
end
end
[Link](source); -- free memory, release source as it is no longer
needed
end;
obs.source_list_release( sources ); -- free memory, release
total_sources = i;
return i;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function getNextItemMatchingTime( tbl, currentTime )
debug_log( 'getNextItemMatchingTime(' .. pre_dump(tbl) .. ", " ..
pre_dump(currentTime) .. ') -- function variable names: tbl, currentTime ' )
if type( tbl ) ~= "table" or tbl == nil then return nil end; -- if the input
table is not of type table return input
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function getPreviousItemMatchingTime( table, currentTime )
debug_log( 'getPreviousItemMatchingTime(' .. pre_dump(table) .. ", " ..
pre_dump(currentTime) .. ') -- function variable names: table, currentTime ' )
local previousItem = nil
local currentTimeString = [Link]( "%02d:%02d:%02d",
[Link]( currentTime / 3600 ), [Link]( ( currentTime % 3600 ) / 60 ),
currentTime % 60 )
for _, value in ipairs(table) do
if value < currentTimeString then
previousItem = value
else
break
end
end
if table[#table] ~= nil and previousItem == nil then
-- loop to last item
--previousItem = table[#table]
end
return previousItem
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Function to convert OBS data array to table
obs_data_array_to_table( settings, "reference" )
Description: Grab OBS data array and return in a table
Credit: midnight-studios
Modified:
function: data array to table
type: Support
input type: Settings, property reference
returns: table
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function obs_data_array_to_table( set, item )
debug_log( 'obs_data_array_to_table(' .. pre_dump(set) .. ", " ..
pre_dump(item) .. ') -- function variable names: set, item ' )
for i = 1, count do
obs.obs_data_array_release( array );
return list;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function getMarkerTime( ref, currentTime )
debug_log( 'getMarkerTime(' .. pre_dump(ref) .. ", " ..
pre_dump(currentTime) .. ') -- function variable names: ref, currentTime ' )
--[[
Create a table for a list
]]
local result = nil
local i = 0; -- create interger variable
local list = {}; -- create temporary table variable
local data_list = obs_data_array_to_table( [Link], "text_arr_" ..
ref ); -- fetch obs userdata from property settings and return in table
--[[
Build a cycle list
We only include valid string formats '00:00:00'
any other format will be excluded
]]
for key, value in pairs( data_list ) do
if value ~= nil and value ~= "" then
if checkTimeString( value ) then
i = i + 1;
[Link]( list, value )
end
end
end
list = removeDuplicates( list ); -- Ensure there are no duplicates
sortTimeTable( list ); -- Time runs linear, so order the list to be linear
local count = tablelength( list ); -- get how many items are listed
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_exists( source_name )
debug_log( 'source_exists_alt(' .. pre_dump(source_name) .. ') -- function
variable names: source_name ' )
local sourceFound = false
if source_name == nil or in_table( ignore_list, source_name ) then
return sourceFound;
end
local sources = obs.obs_enum_sources();
local i = 0;
if sources ~= nil then
for _, source in ipairs( sources ) do -- ipairs cycles auto incrimented
items
local name = obs.obs_source_get_name( source );
if name == source_name then
sourceFound = true
end
end
[Link](source); -- free memory, release source as it is no longer
needed
end;
obs.source_list_release( sources ); -- free memory, release
debug_log( 'source_exists: ' .. pre_dump(sourceFound) )
return sourceFound
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Check source type of media if the media is set to loop
The source is referenced by name.
Credit:
Modified:
function:
type:
input type: reference (string)
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function is_valid_type_source( source_name, unversioned_id )
debug_log( 'is_valid_type_source(' .. pre_dump(source_name) .. ', ' ..
pre_dump(unversioned_id) .. ') -- function variable names: source_name ' )
local is_valid = false;
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function editable_list_has_values( property_name )
debug_log( 'editable_list_has_values(' .. pre_dump( property_name ) .. ') --
function variable names: property_name ' )
local data_list = obs_data_array_to_table( [Link], property_name )
return next(data_list) ~= nil
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function reset_group_note_sources( group_source_name )
-- Convert data array to table
local itemTable = list_source_children_by_source_name( group_source_name,
"group" )
if itemTable ~= nil and type( itemTable ) == "table" then
for _, source_name in pairs( itemTable ) do
if source_exists( source_name ) then
set_visible( source_name, false );
end
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: A single function, named
'assign_marker_note_source_name(ref)', is responsible for performing a task on
two different types of lists. This function utilizes
one String Type variable: 'ref'.
The variable 'ref' indicates the location where the
function is applied.
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function assign_marker_note_source_name( ref )
debug_log( 'assign_marker_note_source_name(' .. pre_dump( ref ) .. ') --
function variable names: property_name, ref ' )
--[[
First determin if the selected name is check if the provided name
is for user required to show items nested in the option requested is
]]
local source_name = obs.obs_data_get_string( [Link], "note_source_"..
ref );
--[[
The option selected may be 'select'
]]
if in_table( ignore_list, source_name ) or not source_exists( source_name )
then
media["note_source_".. ref] = source_name
end
--[[
We may have a 'group' or even a nested scene?
if we do not have a group, then exit
]]
if note_source_unversioned_id ~= "group" then
media["note_source_".. ref] = source_name
else
--[[
We need a list of source names
Get the group children names and
return only those that are text type
]]
-- Convert data array to table
local data_list = list_source_children_by_source_name( source_name,
"group" )
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function assign_audio_source_name( property_name, ref )
debug_log( 'assign_audio_source_name(' .. pre_dump( property_name ) .. ", " ..
pre_dump( ref ) .. ') -- function variable names: property_name, ref ' )
-- Convert data array to table
local data_list = obs_data_array_to_table( [Link], property_name )
-- Create a table to hold the purified data list
local itemTable = {}
-- Iterate over the data list and validate each source
-- Use pairs instead of ipairs because ipairs assumes 1-based array
for i, source_name in pairs( data_list ) do
if is_valid_type_source( source_name, "ffmpeg_source" ) then
[Link]( itemTable, source_name )
end
end
--[[
signal there was a change since the last orientation
this function is used by both Marker A & B, so
orientation should be individually assigned
]]
if media["last_orientation_" .. ref] ~= count_orientation then
current_index = count_orientation == "NORMAL" and current_index + 1 or
current_index - 1;
media["last_orientation_" .. ref] = count_orientation
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to cycle through a table list containing strings
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_audio_source_visibility( property_name, ref )
debug_log( 'reset_audio_source_visibility(' .. pre_dump(property_name) .. ",
" .. pre_dump(ref) .. ') -- function variable names: property_name, ref ' )
local data_list = obs_data_array_to_table( [Link], property_name ); --
fetch obs userdata from property settings and return in table
if data_list ~= nil then
for key, value in pairs( data_list ) do
if is_valid_type_source( value, "ffmpeg_source" ) then
set_visible( value, false );
end
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function reset_audio_marker_arr()
debug_log( 'reset_audio_marker_arr() -- function variable names: ' )
audio_marker_a = obs.obs_data_get_string( [Link], "audio_marker_a" );
if audio_marker_a == "list" then
reset_audio_source_visibility( "audio_marker_a_arr", "marker_a" );
end
audio_marker_b = obs.obs_data_get_string( [Link], "audio_marker_b" );
if audio_marker_b == "list" then
reset_audio_source_visibility( "audio_marker_b_arr", "marker_b" );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: This function asigns a variable to a global
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_time_markers( currentTime )
debug_log( 'update_time_markers(' .. pre_dump(currentTime) .. ') -- function
variable names: currentTime ' )
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_media_names( position_reset )
debug_log( 'update_media_names(' .. pre_dump(position_reset) .. ') -- function
variable names: position_reset ' )
-- If position_reset is not provided, set it to false
position_reset = position_reset or false
--[[
If we do not force a complete reset when required, then
media names will cycle each time the function is called
during the startup or reset stages
]]
if position_reset then
media["cycle_index_marker_a"] = 1; -- index from 1-based table
media["cycle_index_marker_b"] = 1; -- index from 1-based table
end
--[[
If Marker Audio is set to "Allow Multiple Selections"
then it will cycle any strings listed in the Marker Audio List
]]
if audio_marker_a == "list" then
assign_audio_source_name( "audio_marker_a_arr", "marker_a" );
end
if audio_marker_b == "list" then
assign_audio_source_name( "audio_marker_b_arr", "marker_b" );
end
end
--[[
----------------------------------------------------------
Description: Check if a source is a child of a group
Credit:
Modified:
function:
type:
input type:
returns:
----------------------------------------------------------
]]
end;
end
--[[
----------------------------------------------------------
Description: This is basically obs.obs_enum_sources()
but "Nested Scenes" are not listed in
"obs.obs_enum_sources()"
Credit: midnight-studios, et al
Modified: Author
function: Used to build a list from OBS source names into a table
type: Support
input type: "id", "unversioned_id", "display_name", "source_name"
returns: table default with "source_name" or define return_ref: "id"
or "unversioned_id" or "display_name" or "source_name"
----------------------------------------------------------
]]
function get_source_list( trg_key )
debug_log( 'get_source_list(' .. pre_dump(trg_key) .. ') -- function variable
names: return_ref ' )
trg_key = trg_key or "source_name"
local scenes = obs.obs_frontend_get_scenes();
local source_list = {};
--[[
]]
if scenes ~= nil then
--[[
]]
for _, value_scenesource in pairs( scenes ) do
sub["position"] = "parent";
sub["nested"] = ( type_parent ==
obs.OBS_SOURCE_TYPE_SCENE );
sub["type"] = type_parent;
sub["id"] = id_parent;
sub["unversioned_id"] = unversioned_id_parent;
sub["display_name"] = display_name_parent;
sub["source_name"] = source_name_parent;
sub["source"] = source;
if group then
local group_items =
obs.obs_scene_enum_items( group );
if group_items then
for _, group_item_value in
ipairs( group_items ) do
index = index + 1;
sub = {};
local group_item_source =
obs.obs_sceneitem_get_source( group_item_value );
local source_name_group =
obs.obs_source_get_name( group_item_source );
local id_group =
obs.obs_source_get_id( group_item_source );
local unversioned_id_group =
obs.obs_source_get_unversioned_id( group_item_source );
local display_name_group =
obs.obs_source_get_display_name( id_group );
local type_parent =
obs.obs_source_get_type( group_item_source )
sub["position"] = "child";
sub["nested"] = ( type_parent ==
obs.OBS_SOURCE_TYPE_SCENE );
sub["type"] = type_parent;
sub["id"] = id_group;
sub["unversioned_id"] =
unversioned_id_group;
sub["display_name"] = display_name_group;
sub["source_name"] = source_name_group;
sub["source_name_parent"] =
source_name_parent;
sub["source"] = group_item_source;
Credit: midnight-studios
Modified: midnight-studios, et al
function: Used to list files with target extension
type: directory path, file extension
input type:
returns: table
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function get_filenames( path, file_extension )
local filenames = {};
Credit: midnight-studios, et al
Modified: Yes, custom params to suit targeted need
function:
type: Support
input type: OBS data (Settings)
returns: json file
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function write_to_json( data, file_name )
debug_log( 'write_to_json(' .. pre_dump(data) .. ') -- function variable names:
data ' )
output_folder = backup_folder;
-- convert Windows path to UNIX path
file_name = filename() .. (file_name or output_file_name:gsub("$date_stamp",
[Link]("%Y-%m-%d-%H%M"))) .. output_file_ext
-- set output path as the script path by default
local script_path = script_path();
local output_path = script_path .. file_name;
-- if specified output path exists, then set this as the new output path
if (output_folder ~= "") then
output_path = output_folder .. "/" .. file_name;
else
output_path = script_path .. file_name;
end
output_path = output_path:gsub([[\]], "/");
obs.obs_data_erase( data, "backup_folder" );
obs.obs_data_erase( data, "backup_mode" );
return obs.obs_data_save_json( data, output_path );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Convert data to file
Credit: midnight-studios, et al
Modified: Yes, custom params to suit targeted need
function:
type: Support
input type: OBS data (Settings)
returns: json file
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function write_to_file( file_type, content, file_name )
debug_log( 'write_to_file(' .. pre_dump(data) .. ') -- function variable names:
data ' )
output_folder = backup_folder;
file_type = file_type or output_file_ext
-- convert Windows path to UNIX path
file_name = filename() .. (file_name or output_file_name:gsub("$date_stamp",
[Link]("%Y-%m-%d-%H%M"))) .. file_type
-- set output path as the script path by default
local script_path = script_path();
local output_path = script_path .. file_name;
-- if specified output path exists, then set this as the new output path
if (output_folder ~= "") then
output_path = output_folder .. "/" .. file_name;
else
output_path = script_path .. file_name;
end
output_path = output_path:gsub([[\]], "/");
-- Open file in write mode, this will create the file if it does not exist
local file = [Link]( output_path, "w" )
-- If the file has been opened successfully
content = content or 'no content'
if file then
-- Write content to the file
file:write( content )
-- Close the file
file:close()
else
-- Print error message
print("Failed to open file " .. file_name .. " for writing")
end
return output_path;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Assign a default Frequency based on the Frame Rate
video_info.base_width
video_info.base_height
video_info.fps_den
video_info.output_width
video_info.output_height
video_info.range
video_info.colorspace
Credit: midnight-studios
Modified:
function: Get obs user defined video frame rate
type: Support
input type: none
returns: double
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function assign_default_frequency()
debug_log( 'assign_default_frequency() -- function variable names: ' )
local fps = 60; -- 60 is the maximum supported frame rate
local video_info = obs.obs_video_info();
if obs.obs_get_video_info(video_info) then
fps = video_info.fps_num;
end;
time_frequency = ( 1/fps );
debug_log( 'assign default frequency: ' .. pre_dump(time_frequency) )
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Local variables format_hour, format_minutes,
format_seconds, format_mili are initialized to the strings that define the format
of hour, minutes, seconds and mili based on whether they are present or not.
"time" variable is initialized with the formatted
string using [Link] and the values of format_hour, format_minutes,
format_seconds, format_mili and the input arguments hour, minutes, seconds, and
mili.
If show_mili is false, then time is re-initialized
with the formatted string using [Link] and values of format_hour,
format_minutes, format_seconds and input arguments hour, minutes, and seconds.
Return time.
Take the time segments:
Hours, Minutes, Seconds, Millisieconds
Configure to standard format:
HH:MM:SS:FF
$function status: in service
Credit: midnight-studios
Modified:
function: Dependency / Support
type:
input type: 4 variables - "HH" "MM" "SS" "FF"
returns: formatted time string: time stamp 00:00:00,00 (HH:MM:SS,FF)
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function config_time( hour, minutes, seconds, mili )
debug_log( 'config_time(' .. pre_dump(hour) .. ", " .. pre_dump(minutes) .. ",
" .. pre_dump(seconds) .. ", " .. pre_dump(mili) .. ') -- function variable names:
hour, minutes, seconds, mili ' )
local format_hour,
format_minutes,
format_seconds,
format_mili =
( hour and "%02d" or "" ),
( minutes and ":%02d" or "" ),
( seconds and ":%02d" or "" ),
( mili and ",%02d" or "" );
local time =
[Link]( format_hour..format_minutes..format_seconds..format_mili, hour,
minutes, seconds, mili );
--[[
]]
if not show_mili then
time = [Link]( format_hour..format_minutes..format_seconds,
hour, minutes, seconds );
end;
debug_log( 'config time: ' .. pre_dump(time) )
return time;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Convert Seconds to hours:minutes:seconds:miliseconds
Credit:
Modified:
function:
type:
input type: Double (Seconds / Split Seconds)
returns: time stamp 00:00:00,00 (HH:MM:SS,FF)
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function raw_time( time, simplify )
debug_log( 'raw_time(' .. pre_dump(time) .. ", " .. pre_dump(simplify) .. ') --
function variable names: time, simplify ' )
--[[
There may be a custom hour time
]]
if hour_format ~= nil then
hours = [Link]( time/3600 );
hours = hours % hour_format;
else
--[[
If there is more than 24 hours in the time value
we need to remove the additional time value to leave only a
23:59:59
value. We will do this by calculating days
]]
-- If there is more than 24 hours, remove 23:59:59 as it will be in the
clock
if time > 86399 then -- 23:59:59
local c_time = ( [Link]( ( time ) / 86400 ) * 86400 );
time = time - c_time;
end;
]]
seconds = [Link]( time - [Link]( time/3600 )*3600 -
[Link]( ( time - [Link]( time/3600 )*3600 )/60 )*60 );
if seconds < 10 and trim then
seconds = "0"..seconds;
end;
--[[
]]
mili = [Link]( ( time - [Link]( time/3600 )*3600 - [Link]( ( time
- [Link]( time/3600 )*3600 )/60 )*60 - [Link]( time - [Link]( time/3600
)*3600 - [Link]( ( time - [Link]( time/3600 )*3600 )/60 )*60 ) )*100 );
if mili < 10 and trim then
mili = "0"..mili;
end
--[[
]]
local output = "";
if simplify then
output = config_time( hours, minutes, seconds, nil );
else
output = config_time( hours, minutes, seconds, mili );
end;
Credit: midnight-studios
Modified:
function: calculate time difference between two points in time
type: Support
input type: none
returns: double
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function get_time_lapsed()
debug_log( 'get_time_lapsed() -- function variable names: ' )
local ns = obs.os_gettime_ns();
local delta = ( ns/1000000000.0 ) - ( orig_time/1000000000.0 );
return raw_time( delta );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: The true frequency between cycles varies due to script
and system task processing, therefore a static
frequency
will produce inaccuarte results over time.
Start with a default frequency of 1 second devided by
the assigned active fps and then update the frequency
calculated from the difference between cycles for the
previous and current cycle using high-precision
system
time, in nanoseconds.
It should be noted, the frequency is based on the
script defined cycle time, which in this case is
10 miliseconds. Based on testing 10 Miliseconds is
the
fastest cycle supported in OBS lua.
Credit: midnight-studios
Modified:
function: determine the correct fraction of the split second based on
frame rate
type: Support
input type: double
returns: double
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function get_frequency( previous )
debug_log( 'get_frequency(' .. pre_dump(previous) .. ') -- function variable
names: previous ' )
local ns = obs.os_gettime_ns();
ns_last = ns;
local f = ( ns/1000000000.0 ) - ( previous/1000000000.0 );
if f > 1 then f = time_frequency end;
debug_log( 'frequency: ' .. pre_dump(f) )
return f;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit: midnight-studios
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function timer_remove( input )
debug_log( 'timer_remove(' .. pre_dump(input) .. ') -- function variable names:
input' )
if type( input ) ~= "table" then
if input ~= nil and type( input ) == "function" then
obs.timer_remove( input );
debug_log( 'removed timer (' .. pre_dump(input) .. ')' )
else
debug_log( 'requested timer for removal does not exist. Aborting.' )
end
else
debug_log( 'timer remove items: (' .. pre_dump(#input) .. ')' )
for key, value in pairs( input ) do
if value ~= nil and type( input ) == "function" then
obs.timer_remove( value );
debug_log( 'removed timer (' .. pre_dump(value) .. ')' )
else
debug_log( 'requested timer for removal does not exist.
Aborting.' )
end
end;
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit: midnight-studios
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function timer_add( input, ms )
debug_log( 'timer_add(' .. pre_dump(input) .. ", " .. pre_dump(ms) .. ') --
function variable names: input' )
obs.timer_add( input, ms );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit: midnight-studios
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function remove_all_timers()
debug_log( 'remove_all_timers() -- function variable names: ' )
local timerNames = {}
[Link]( timerNames, timer_callback );
[Link]( timerNames, sal_timer_callback );
[Link]( timerNames, ssl_timer_callback );
[Link]( timerNames, timer_end_media_end_callback );
[Link]( timerNames, frontend_recording_start_callback );
[Link]( timerNames, reset_text_a_colour_timer_callback );
[Link]( timerNames, reset_text_b_colour_timer_callback );
[Link]( timerNames, hide_note_a_timer_callback );
[Link]( timerNames, hide_note_b_timer_callback );
[Link]( timerNames, marker_a_media_end_callback );
[Link]( timerNames, marker_b_media_end_callback );
timer_remove( timerNames )
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: This was developed because some tasks were not completing
Credit: midnight-studios
Modified:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function frontend_recording_start_callback( )
debug_log( 'frontend_recording_start_callback() -- function variable names:
' )
if not record_timer_set then return end;
if not obs.obs_frontend_recording_active() then
obs.obs_frontend_recording_start();
end;
timer_remove( frontend_recording_start_callback );
record_timer_set = false;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: "Timer Expires" = 1
"Marker A Time" = 2
"Marker B Time" = 3
"Timer Visible" = 4
"Timer Start" = 5
Credit: midnight-studios
Modified:
function: Start obs call obs_frontend_recording_start()
type:
input type: reference, milliseconds
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function record( mark, ms )
debug_log( 'record(' .. pre_dump(mark) .. ", " .. pre_dump(ms) .. ') --
function variable names: mark, ms ' )
if not enable_property_start_recording then return end;
if obs.obs_frontend_recording_active() then -- if already recording, remove
and reset timer
frontend_recording_start_callback( );
return;
end;
if timer_mode ~= 2 or obs.obs_frontend_recording_active() then return end; --
if not countdown or timer active, then exit
if start_recording ~= 1 and start_recording == mark then
if not record_timer_set then
timer_remove( frontend_recording_start_callback ); -- Remove any
existing callbacks if they exist before assigning a new callback
timer_add( frontend_recording_start_callback, ms ); --<
milliseconds
record_timer_set = true;
end;
end;
debug_log( 'record [End]' )
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Convert hours:minutes:seconds to Seconds
Credit: midnight-studios
Modified:
function: convert date, hour, minutes and secods to seconds
type:
input type: interger for date, time
returns: interger (seconds)
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function delta_time( year, month, day, hour, minute, second )
debug_log( 'delta_time(' .. pre_dump(year) .. ", " .. pre_dump(month) .. ",
" .. pre_dump(day) .. ", " .. pre_dump(hour) .. ", " .. pre_dump(minute) .. ", " ..
pre_dump(second) .. ') -- function variable names: year, month, day, hour, minute,
second ' )
local now = [Link]();
if ( year == -1 ) then
year = [Link]( "%Y", now );
end;
if ( month == -1 ) then
month = [Link]( "%m", now );
end;
if ( day == -1 ) then
day = [Link]( "%d", now );
end;
local future = [Link]{year=year, month=month, day=day, hour=hour,
min=minute, sec=second};
local seconds = [Link]( future, now );
if ( seconds < 0 ) then
seconds = 0;
end;
return seconds;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Take the raw time format "HH:MM:SS:FF" and allow the user
to
define a custom format.
$function status: in service
Credit:
Modified: midnight-studios
function: The timestamp is what we put in, the format is what we want
this little princess to be transformed into
type:
input type: 00:00:00,00
returns: Whatever the format incleded: $T $D $H $M $S $F and
anything inbetween
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function format_time( timestamp, format )
debug_log( 'format_time(' .. pre_dump(timestamp) .. ", " .. pre_dump(format) ..
') -- function variable names: timestamp, format ' )
local days, hours, minutes, seconds, mili = "00", "00", "00", "00", "00";
local timeTable = explode( timestamp, ":" ) or {timestamp}; -- reference ":"
4 parts
local trim = format:find("$T");
local replacements = {}
if #timeTable == 4 then
days, hours, minutes, seconds = unpack(timeTable)
seconds, mili = unpack(explode(seconds, ","))
elseif #timeTable == 3 then
hours, minutes, seconds = unpack(timeTable)
seconds, mili = unpack(explode(seconds, ","))
elseif #timeTable == 2 then
minutes, seconds = unpack(timeTable)
seconds, mili = unpack(explode(seconds, ","))
elseif #timeTable == 1 then
seconds = unpack(timeTable)
seconds, mili = unpack(explode(seconds, ","))
end
if tonumber(days) < 10 then
days = "0"..days;
end;
if show_mili then
replacements["$F"]=mili
else
timestamp = timestamp:gsub("$F", "")
end
for k, v in pairs(replacements) do
timestamp = timestamp:gsub(k, v)
end
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function long_time( time )
debug_log( 'long_time(' .. pre_dump(time) .. ') -- function variable names:
time ' )
local c_time = time;
-- If there is more than 24 hours, remove 23:59:59 as it will be in the clock
if time > 86399 then -- 23:59:59
c_time = [Link]( ( time ) / 86400 );
end;
if time < 86400 then
c_time = 0;
end;
return c_time;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function extract_from_brackets( str, reg )
-- Find the first occurrence of a balanced pair of braces in the string
reg = reg or "{.-%}" -- "%b{}"-- "{.-%}"
Credit:
Modified: Asking if miliseconds property must be shown or hidden and
this is for back end UI
function: yer, no
type: Support, UI
input type: properties, settings
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function get_unit_allocation(str, target_char)
-- Find the first occurrence of the target character followed by one or more
digits
local pattern = target_char .. "%d+"
local match = instructions:match(pattern)
-- If the target character and numeric value are not found, return nil
if match == nil then
return nil
end
return tonumber(number)
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Check if there are instructions included in the text for
additional supported behaviour.
Instructions must be provided in '{}' and may contain
two paramaters for example {param1:param2}
param1 may be one of three possible designations. It
must be a numeric value of either 1 or 2 or a time stamp matching the format for
HH:MM:SS. If param1 is set to 1 it will pull time
markers entries from the list for Marker A
and if param1 is set to 2 to it will pull time
markers entries from the list for Marker B.
If param1 is defined with a time marker matching the
format HH:MM:SS it will use this time marker instead.
Credit:
Modified:
function: accepts string, string
type:
input type:
returns: 3 variable [boolean, String, Interger] true or false if
input contains a match to the pattern, param 1, param 2
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function get_presuf_allocation( str, reg )
-- Find the first occurrence of a balanced pair of braces in the string
reg = reg or "{.-%}" -- "%b{}"-- "{.-%}"
if instructions then
if instructions == "1" then -- only referencing 1
return true, "a", nil
elseif instructions == "2" then -- only referencing 2
return true, "b", nil
end
Description:
Credit:
Modified:
function: yer, no
type: Support, UI
input type: properties, settings
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function hasBrackets( str )
debug_log( 'hasBrackets(' .. pre_dump( str ) .. ') -- function variable names:
str' )
local start_index, end_index = [Link]( str, "%b{}" )
return start_index ~= nil
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Credit:
Modified: Asking if miliseconds property must be shown or hidden and
this is for back end UI
function: yer, no
type: Support, UI
input type: properties, settings
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function removeBrackets( str )
debug_log( 'removeBrackets(' .. pre_dump( str ) .. ') -- function variable
names: str' )
local start_index, end_index = [Link]( str, "%b{}" )
if start_index == nil then
return str
end
return [Link](str, 1, start_index - 1) .. [Link](str, end_index + 1)
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit: et al
Modified:
function:
type: Support, Render
input type: Integer
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function get_text_color( source_name )
debug_log( 'get_timer_text_color(' .. pre_dump(int) .. ') -- function variable
names: int ' )
local color
if source_name == nil or in_table( ignore_list, source_name ) then return
color end; -- if timer_source not defined, then return
local source = obs.obs_get_source_by_name( source_name ); -- get source by
name
if source ~= nil then -- continue if we have a source
local source_id = obs.obs_source_get_unversioned_id( source ); -- get
source id
if source_id == text_source_unversioned_id then -- identify text type
sources only
if settings ~= nil then
--[[
Operating compatibility MacOSX / Windows
The settings key for color
Win = "color"
Mac = "color2" and "color3"
]]
if osType == "Windows" then
color = obs.obs_data_get_int( settings, "color",
color ); -- update source settings
else
color = obs.obs_data_get_int( settings, "color1",
color ); -- update source settings
if not color then
color = obs.obs_data_get_int( settings,
"color2", color ); -- update source settings
end
if not color then
color = 4294967295 -- default is white
end
end
end
end
end
obs.obs_source_update( source, settings ); -- save source new settings
obs.obs_data_release( settings ); -- release settings
obs.obs_source_release( source ); -- release source
return color
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Change color of font for text source
Credit: et al
Modified:
function: Update Text Source (timer text source)
type: Support, Render
input type: Integer
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_timer_text_color( color )
debug_log( 'set_timer_text_color(' .. pre_dump(color) .. ') -- function
variable names: int ' )
if in_table( {"Select", "select"}, timer_source ) then return end; -- if
timer_source not defined, then return
local source = obs.obs_get_source_by_name( timer_source ); -- get source by
name
if source ~= nil then -- continue if we have a source
local settings = obs.obs_source_get_settings( source ); -- get source
settings
if settings ~= nil then
--[[
Operating compatibility MacOSX / Windows
The settings key for color
Win = "color"
Mac = "color2" and "color3"
]]
obs.obs_data_set_int( settings, "color", color ); --
compatibility for settings transfer
obs.obs_data_set_int( settings, "color1", color ); -- update
source settings
obs.obs_data_set_int( settings, "color2", color ); -- update
source settings
end
obs.obs_source_update( source, settings ); -- save source new settings
obs.obs_data_release( settings ); -- release settings
obs.obs_source_release( source ); -- release source
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_text_a_colour_timer_callback()
debug_log( 'reset_text_a_colour_timer_callback() -- function variable names:
' )
set_timer_text_color( media["color_normal"] );
timer_remove( reset_text_a_colour_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_text_a_colour_end_timer()
debug_log( 'reset_text_a_colour_end_timer() -- function variable names: ' )
timer_remove( reset_text_a_colour_timer_callback ); -- Removing the callback
stops the timer
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_text_b_colour_timer_callback()
debug_log( 'reset_text_b_colour_timer_callback() -- function variable names:
' )
set_timer_text_color( media["color_normal"] );
timer_remove( reset_text_b_colour_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_text_b_colour_end_timer()
debug_log( 'reset_text_b_colour_end_timer() -- function variable names: ' )
timer_remove( reset_text_b_colour_timer_callback ); -- Removing the callback
stops the timer
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hide_note_a_timer_callback()
debug_log( 'hide_note_a_timer_callback() -- function variable names: ' )
if media["note_source_unversioned_id_marker_a"] == text_source_unversioned_id
then
set_visible( media["note_source_marker_a"], false ); -- Set hiden the
source for the note for marker a
end
if media["note_source_unversioned_id_marker_a"] == "group" then -- Hide
Sources from a list
local source_to_use = media["used_note_source_marker_a"]:popright()
if source_to_use ~= nil then set_visible( source_to_use, false ); end
-- Set hiden the source for the note for marker b
end
timer_remove( hide_note_a_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hide_note_a_colour_end_timer()
debug_log( 'hide_note_a_colour_end_timer() -- function variable names: ' )
timer_remove( hide_note_a_timer_callback ); -- Removing the callback stops
the timer
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hide_note_b_timer_callback()
debug_log( 'hide_note_b_timer_callback() -- function variable names: ' )
if media["note_source_unversioned_id_marker_b"] == text_source_unversioned_id
then
set_visible( media["note_source_marker_b"], false ); -- Set hiden the
source for the note for marker b
end
if media["note_source_unversioned_id_marker_b"] == "group" then
local source_to_use = media["used_note_source_marker_b"]:popright()
if source_to_use ~= nil then set_visible( source_to_use, false ); end
-- -- Set hiden the source for the note for marker b
end
timer_remove( hide_note_b_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hide_note_b_colour_end_timer()
debug_log( 'hide_note_b_colour_end_timer() -- function variable names: ' )
timer_remove( hide_note_b_timer_callback ); -- Removing the callback stops
the timer
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_marker_text_colour_start_timer( int, ref )
debug_log( 'reset_marker_text_colour_start_timer(' .. pre_dump(int) .. ", " ..
pre_dump(ref) .. ') -- function variable names: int, ref ' )
if int ~= 0 then
if ref == "marker_a" then
timer_remove( reset_text_a_colour_timer_callback ); -- Remove any
existing callbacks if they exist before assigning a new callback
timer_add( reset_text_a_colour_timer_callback, int ); --<-
milliseconds
end
if ref == "marker_b" then
timer_remove( reset_text_b_colour_timer_callback ); -- Remove any
existing callbacks if they exist before assigning a new callback
timer_add( reset_text_b_colour_timer_callback, int ); --<-
milliseconds
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hide_note_start_timer( int, ref )
debug_log( 'hide_note_start_timer(' .. pre_dump(int) .. ", " ..
pre_dump(ref) .. ') -- function variable names: int, ref ' )
if int ~= 0 then
if ref == "marker_a" then
timer_remove( hide_note_a_timer_callback ); -- Remove any
existing callbacks if they exist before assigning a new callback
timer_add( hide_note_a_timer_callback, int ); --<- milliseconds
end
if ref == "marker_b" then
timer_remove( hide_note_b_timer_callback ); -- Remove any
existing callbacks if they exist before assigning a new callback
timer_add( hide_note_b_timer_callback, int ); --<- milliseconds
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Credit:
Modified: Asking if miliseconds property must be shown or hidden and
this is for back end UI
function: yer, no
type: Support, UI
input type: properties, settings
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function show_split( props, settings )
debug_log( 'show_split(' .. pre_dump(props) .. ", " .. pre_dump(settings) .. ')
-- function variable names: props, settings ' )
local layout_value = obs.obs_data_get_int( settings, "layout" );
local mode = obs.obs_data_get_int( settings, "timer_mode" );
local shw = false;
shw = ( layout_value == 2 and mode == 2 and in_table( {1, 2},
timer_format ) );
if ( timer_format == 5 and layout_value == 2 and mode == 2 ) then
if ( [Link]( custom_time_format, "$F" ) ~= nil ) then
shw = true;
else
shw = false;
end;
end;
return shw;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to set the source text
Credit: et al
Modified:
function: Update Text Source
type: Support, Render
input type: target source by name, contents to be added to text
contents
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_text( source_name, text )
debug_log( 'set_text(' .. pre_dump(source_name) .. ", " .. pre_dump(text) .. ')
-- function variable names: source_name, text ' )
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
]]
local source = obs.obs_get_source_by_name( source_name );
if source ~= nil then
local settings = obs.obs_source_get_settings( source );
obs.obs_data_set_string( settings, "text", text );
end;
obs.obs_source_update( source, settings );
obs.obs_data_release( settings );
obs.obs_source_release( source );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Set source visibility to hidden
Credit:
Modified:
function: a callback for a timer used to set a source visibility to
hidden
type:
input type: none
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function marker_a_media_end_callback( )
debug_log( 'marker_a_media_end_callback() -- function variable names: ' )
set_visible( media["source_name_audio_marker_a"], false );
timer_remove( marker_a_media_end_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Set source visibility to hidden
Credit:
Modified:
function: a callback for a timer used to set a source visibility to
hidden
type:
input type: none
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function marker_b_media_end_callback( )
debug_log( 'marker_b_media_end_callback() -- function variable names: ' )
set_visible( media["source_name_audio_marker_b"], false );
timer_remove( marker_b_media_end_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function signal_media_ended( cd )
debug_log( 'signal_media_ended(' .. pre_dump(cd) .. ') -- function variable
names: cd ' )
--[[
]]
local source = obs.calldata_source( cd, "source" );
--[[
Found Source?
]]
if source ~= nil then
local name = obs.obs_source_get_name( source );
--[[
Set Source Visibility to Hidden
]]
set_visible( name, false );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function start_media_action( source_name, ref )
debug_log( 'start_media_action(' .. pre_dump(source_name) .. ", " ..
pre_dump(ref) .. ') -- function variable names: source_name, ref ' )
if in_table( ignore_list, source_name ) then return end;
--[[
]]
disconnect_after_media_end( ref );
media["activated_media_".. ref] = true;
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function start_media( source_name, ref )
debug_log( 'start_media(' .. pre_dump(source_name) .. ", " .. pre_dump(ref) ..
') -- function variable names: source_name, ref ' )
start_media_action( source_name, ref );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Change color of font for text source
Credit: et al
Modified:
function: Update Text Source
type: Support, Render
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_text_note_color( ref )
if disable_script then return; end;
debug_log( 'set_text_note_color(' .. pre_dump(ref) .. ') -- function variable
names: ref ' )
--[[
Only control colour if source is a text source
]]
if media["note_source_unversioned_id_" .. ref] ~= text_source_unversioned_id
then return end
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function roundSeconds()
debug_log( 'roundSeconds() -- function variable names: ' )
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function prep_presuf()
if hasBrackets( text_prefix ) then
local text_prefix_cleaned = removeBrackets( text_prefix )
text_prefix_validated = ""
else
text_prefix_validated = text_prefix;
end
if hasBrackets( text_suffix ) then
local text_suffix_cleaned = removeBrackets( text_suffix )
text_suffix_validated = ""
else
text_suffix_validated = text_suffix;
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: validate instructions
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function validate_presuf()
debug_log( 'validate_presuf() -- function variable names: ' )
local p1,p2,p3 = get_presuf_allocation( text_prefix )
local s1,s2,s3 = get_presuf_allocation( text_suffix )
local text_prefix_cleaned = removeBrackets( text_prefix )
local text_suffix_cleaned = removeBrackets( text_suffix )
local round_seconds = roundSeconds();
local function get_seconds_from_timestamp( timeString )
local result
if timeString ~= nil and checkTimeString( timeString ) then
result = convertToSeconds( timeString )
end
return result
end
local function isSecondsInRange( min, max )
if min == nil and max == nil then
return false
elseif min == nil then
return round_seconds < max
elseif max == nil then
return round_seconds >= min
else
return min <= round_seconds and round_seconds < max
end
end
local function get_set_seconds( set, text )
local seconds
if set == "a" then
if text == "" then
presuf["text_marker_a"] = media["text_marker_a"];
end
seconds = get_seconds_from_timestamp( presuf["text_marker_a"] );
elseif set == "b" then
if text == "" then
presuf["text_marker_b"] = media["text_marker_b"];
end
seconds = get_seconds_from_timestamp( presuf["text_marker_b"] );
elseif set ~= "a" and set ~= "b" then
seconds = get_seconds_from_timestamp( set );
end
return seconds
end
local min, max = nil, nil
if p1 then -- nothing required, add available text
s = get_set_seconds( p2, text_prefix_validated )
if s ~= nil then
if current_count_direction == "UP" then
min = s
if p3 ~= nil then
max = ( s + p3 )
end
else
max = s
if p3 ~= nil then
min = ( s - p3 )
end
end
end
local in_range = isSecondsInRange( min, max )
if in_range then
text_prefix_validated = text_prefix_cleaned
else
text_prefix_validated = ""
end
end
min, max = nil, nil
if s1 then -- nothing required, add available text
s = get_set_seconds( s2, text_suffix_validated )
if s ~= nil then
if current_count_direction == "UP" then
min = s
if s3 ~= nil then
max = ( s + s3 )
end
else
max = s
if s3 ~= nil then
min = ( s - s3 )
end
end
end
local in_range = isSecondsInRange( min, max )
if in_range then
text_suffix_validated = text_suffix_cleaned
else
text_suffix_validated = ""
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function time_mark_check( ref )
debug_log( 'time_mark_check(' .. pre_dump(ref) .. ') -- function variable
names: ref ' )
if not timer_active then return end; -- only allow mark checks if the timer
is active
--[[
Make sure the trigger is as accurate as possible depending
if the timer is counting up or down.
]]
local round_seconds = roundSeconds();
local activation_time = media["activated_time_".. ref];
local text_marker = media["text_".. ref];
validate_presuf()
--[[
]]
start_media( media["source_name_audio_".. ref], ref );
--[[
if the user wants OBS to start recording when the marker
activates
check the reference and activate the timer to initiate recording
start_recording:
1 = "Disabled"
2 = "Timer Expires",
3 = "Marker A Time",
4 = "Marker B Time",
5 = "Timer Visible",
6 = "Timer Start"
]]
--[[
There may be more markers, if so check if there are and upddate
variables
]]
update_time_markers( round_seconds );
update_media_names(); -- we don't reset because here the list must
cycle
Credit:
Modified:
function:
type: tasks
input type: ref (string)
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function stop_media_action( ref )
debug_log( 'stop_media_action(' .. pre_dump(ref) .. ') -- function variable
names: ref ' )
]]
if media["duration_".. ref] ~= 0 and media_playback_limit ~= 1 then
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
local time_currently =
[Link]( current_seconds ); -- round to nearset upper value
local media_time_remaining = 0; -- set integer
variable with default value
local time_end = false; -- set bool variable
with default value
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function stop_looping_media( ref )
debug_log( 'stop_looping_media(' .. pre_dump(ref) .. ') -- function variable
names: ref ' )
local source_name = media["source_name_audio_".. ref];
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function stop_media( ref, bypass )
bypass = bypass or false;
debug_log( 'stop_media(' .. pre_dump(ref) .. ", " .. pre_dump(bypass) .. ') --
function variable names: ref, bypass ' )
if bypass then -- No checks, just stop it
set_visible( media["source_name_audio_".. ref], false ); -- Set the
media source state to hidden
else -- do some checks
stop_media_action( ref ); -- handle this request elsewhere
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to cycle through a list for sources or scenes
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function get_cycle_source_list( source_type )
--[[
]]
local list = {}; -- create temporary table variable
local item_list = {}; -- A list containing the available source names
local data_list = obs_data_array_to_table( [Link], "cycle_list" ); --
fetch obs userdata from property settings and return in table (the list source name
list the user defined)
--[[
Create a list with either all the scene or source names
]]
if source_type ~= "source" then -- string is not equal to "source" as it
should be "scene"
local scenes = obs.obs_frontend_get_scene_names(); -- List Scenes names
if scenes ~= nil then
for _, scene in ipairs( scenes ) do -- cycle through list items
one at a time
item_list[scene] = scene; -- add scene name
(string) to the table
end
[Link]( scene ); -- free memory, release source as it is no
longer needed
end
else -- List Source names
local sources = get_source_list(); -- "id" or "unversioned_id" or
"display_name" or "source_name"
for key, value in pairsByKeys( sources ) do
item_list[value] = value;
end
end
--[[
Create a clean list, compare the user name list with the available
source name list
if the source exist (it must be listed in item_list) then add it to the
output list and disregard
all other items. This will filter out all mispelled or non existent
items that are listed
]]
for key, value in pairs( data_list ) do
if in_table( item_list, value ) then
[Link]( list, value )
end
end
return list
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to cycle through a list for sources or scenes
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_list_set_by_index( source_list, source_type, index, visible )
debug_log( 'source_list_set_by_index(' .. pre_dump(source_type) .. ', '..
pre_dump(index).. ') -- function variable names: source_type, index ' )
--[[
The list contains all available sources.
The value targets the sources requested.
Check if the requested source is available
]]
local source_name = source_list[index]
if source_name ~= nil then
--[[
Type is "Scene"
]]
if source_type == "scene" and visible then
frontend_set_current_scene( source_name )
end
end;
return source_name;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to cycle through a list for sources or scenes
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function cycle_source_list_by_source_type( source_list, source_type,
ctrl_index )
debug_log( 'cycle_source_list_by_source_type(' .. pre_dump(source_type) ..
',' .. pre_dump(ctrl) .. ') -- function variable names: source_type ' )
if source_list == nil then
return ctrl_index, nil
end
local source_name;
for index = 1, #source_list do
local visible = ( index == ctrl_index );
local temp_name = source_list_set_by_index( source_list, source_type,
index, visible )
if visible then source_name = temp_name end
end;
--[[
1: Ascending
2: Desceneding
Depending on the 'cycle_direction', set the next index.
]]
if cycle_direction == 2 then --
ctrl_index = ( ctrl_index % #source_list ) + 1
else
ctrl_index = ( ctrl_index - 2 + #source_list ) % #source_list + 1
end
return ctrl_index, source_list
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to cycle through a list for sources or scenes
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function cycle_source_list_by_source_name( source_list, ctrl_index )
debug_log( 'cycle_source_list_by_source_name(' .. pre_dump(source_name) .. ', '
.. pre_dump(ctrl) .. ') -- function variable names: source_name ' )
if source_list == nil then
return ctrl_index, nil
end
--[[
1: Ascending
2: Desceneding
Depending on the 'cycle_direction', set the next index.
]]
if cycle_direction == 2 then --
ctrl_index = ( ctrl_index % #source_list ) + 1
else
ctrl_index = ( ctrl_index - 2 + #source_list ) % #source_list + 1
end
Credit:
Modified:
function:
type:
input type: string
returns: nothing
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_cycle_source_list()
debug_log( 'reset_cycle_source_list(' .. pre_dump(source_type) .. ') --
function variable names: source_type ' )
local source_list
if in_table( {"Source List", "Scene List"}, timer_expire_event ) then
source_list = get_cycle_source_list( source_type );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Check if a scene with a specific name has a source with a
specific name
Credit: midnight-studios, et al
Modified:
function: check true or false
type: Dependency / Support
input type: string, string
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function scene_name_has_source_name( scene_name, source_name )
debug_log('scene_name_has_source_name(' .. pre_dump(scene_name) .. ", " ..
pre_dump(source_name) .. ') -- function variable names: scene_name, source_name ')
local result = false;
local scene_source = obs.obs_get_source_by_name( scene_name )
local scene = obs.obs_scene_from_source( scene_source )
local scene_items = obs.obs_scene_enum_items( scene )
Credit: midnight-studios, et al
Modified:
function: make a source visible
type: Dependency / Support
input type: source, bool, timer_activation (global),
scene_name_has_source_name()
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function activate_timer_on_scene( source, activating )
debug_log( 'activate_timer_on_scene(' .. pre_dump(source) .. ", " ..
pre_dump(activating) .. ') -- function variable names: source, activating ' )
--[[
Reset to starting point
if, timer_activation == 2 then set to visible
]]
if timer_activation == 3 and activating then
local source_id = obs.obs_source_get_id( source );
local current_scene_name = frontend_get_current_scene()
if source_id == "scene" then
if scene_name_has_source_name( current_scene_name,
timer_source ) then
if not is_visible( timer_source ) then
set_visible( timer_source, true );
end;
end;
end;
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Update Properties
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function update_properties_setting_int( reference, value )
debug_log( 'update_properties_setting_int(' .. pre_dump(reference) .. ", " ..
pre_dump(value) .. ') -- function variable names: reference, value ' )
--[[
When this is updated it will trigger a
callback "property_onchange", let's
disable that for a moment.
]]
--prevent_callback = true;
return true
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Update Properties
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function update_prop_settings_current_seconds( value )
debug_log( 'update_prop_settings_current_seconds(' .. pre_dump(value) .. ') --
function variable names: value ' )
--[[
When this is updated it will trigger a
callback "property_onchange", let's
disable that for a moment.
]]
prevent_callback = true;
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Everytime the timer value is updated,
it will happen here
Credit:
Modified:
function: update the timer value
type: Dependency / Support
input type: double
returns: current_seconds
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_value( value )
debug_log( 'timer_value(' .. pre_dump(value) .. ') -- function variable names:
value ' )
current_seconds = value;
return current_seconds;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Assign the correct frequency value to the timer incriment
depending on if timer is counting up or down
Credit:
Modified:
function: update the timer value
type: Dependency / Support
input type:
returns: calls timer_value()
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_time_direction( )
debug_log( 'set_time_direction() -- function variable names: ' )
--[[
]]
local t = 0;
--[[
]]
if direction_changed then -- normal function suspended
if current_count_direction == "UP" then
t = ( current_seconds + time_frequency ); -- value
else
t = ( current_seconds - time_frequency ); -- value
end
else -- normal function active
--[[
]]
if timer_mode ~= 2 then
t = ( current_seconds + time_frequency ); -- value
else
t = ( current_seconds - time_frequency ); -- value
end
end
--[[
update the timer value
]]
timer_value( t ); -- value
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to set the defined time text source value
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_timer_display( source_name, text )
debug_log( 'update_timer_display(' .. pre_dump(source_name) .. ", " ..
pre_dump(text) .. ') -- function variable names: source_name, text ' )
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
]]
if source_name == nil or in_table( ignore_list, source_name ) then
return
end
local source = obs.obs_get_source_by_name( source_name );
if source ~= nil then
local settings = obs.obs_source_get_settings( source );
if settings ~= nil then
if not media["activated_media_marker_a"] and not
media["activated_media_marker_b"] and not color_normal_updated then
--[[
Operating compatibility MacOSX / Windows
The settings key for color
Win = "color"
Mac = "color2" and "color3"
]]
obs.obs_data_set_int( settings, "color",
media["color_normal"] ); -- compatibility for settings transfer
obs.obs_data_set_int( settings, "color1",
media["color_normal"] ); -- update source settings
obs.obs_data_set_int( settings, "color2",
media["color_normal"] ); -- update source settings
color_normal_updated = true;
end
time_mark_check( "marker_a" );
time_mark_check( "marker_b" );
obs.obs_data_set_string( settings, "text", text );
end
end
obs.obs_source_update( source, settings );
obs.obs_data_release( settings );
obs.obs_source_release( source );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to toggle milliseconds
Credit:
Modified:
function: mili_toggle
type:
input type: globals: toggle_mili_trigger, timer_mode,
mili_toggle_triggered, raw_time()
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function toggle_mili()
debug_log( 'toggle_mili() -- function variable names: ' )
if not enable_property_toggle_mili_trigger then return end
--[[
This feature will only activate if "Trigger Value" is defined
and if "Trigger Value" matches "Current Time" and if
"Timer Type" is "Count Down"
]]
if toggle_mili_trigger ~= "" and timer_mode == 2 and not
mili_toggle_triggered then
local time_offset = 1; -- offset by 1 second to allow user to achieve
accurate setting
if raw_time( ( current_seconds + time_offset ), true ) ==
toggle_mili_trigger then
--[[
The action trigger a toggle, so if the
active state at the time of the trigger
is "Show" the toggle will "Hide" and
Vicas Versa.
Should we force a state?
To force define: show_mili = false
]]
mili( true );
mili_toggle_triggered = true;
end;
end;
--return true
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to set the defined time text source value
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_time_text( source_name )
debug_log( 'set_time_text(' .. pre_dump(source_name) .. ') -- function variable
names: source_name ' )
--[[
First Check we have a source reference
]]
if source_name == nil or in_table( ignore_list, source_name ) then
return
end
--[[
Force absolute zero at this point
]]
if current_seconds <= 0.01 and ( timer_mode ~= 1 or ( direction_changed and
current_count_direction == "DOWN" and prevent_negative_time ) ) then
timer_value( 0 ); -- value, update_settings
end;
--[[
Timer Format Type: Full Format
]]
local text = tostring( raw_time( current_seconds ) );
--[[
Timer Format Type: Remove Leading Zeros
]]
if timer_format == 2 then
local system_time_format = "$T$H:$M:$S,$F";
text = format_time( ( l_time ~= 0 ) and [Link]( "%s:%s", l_time,
t_time ) or [Link]( "%s", t_time ), system_time_format );
end
--[[
Timer Format Type: No Leading Zeros, No Split Seconds
]]
if timer_format == 3 then
local system_time_format = "$T$H:$M:$S";
text = format_time( ( l_time ~= 0 ) and [Link]( "%s:%s", l_time,
t_time ) or [Link]( "%s", t_time ), system_time_format );
end
--[[
Timer Format Type: No Leading Zeros, No Split Seconds
]]
if timer_format == 4 then
local system_time_format = "$H:$M:$S";
text = format_time( ( l_time ~= 0 ) and [Link]( "%s:%s", l_time,
t_time ) or [Link]( "%s", t_time ), system_time_format );
end
if timer_format ~= 5 then
--[[
Format the Text "Day/Days"
]]
if timer_mode == 2 and countdown_type == 1 and current_seconds ~= 0
then
local longtimetext = longtimetext_p;
if [Link]( current_seconds / 86400 ) <= 1 then
longtimetext = longtimetext_s;
end
if [Link]( current_seconds / 86400 ) <= 0 then
longtimetext = longtimetext_p;
end
text = [Link](longtimetext .. text, "[#]",
long_time( current_seconds ));
end
end
--[[
Timer Format Type: Custom Time Format
]]
if timer_format == 5 then
text = format_time( ( l_time ~= 0 ) and [Link]( "%s:%s", l_time,
t_time ) or [Link]( "%s", t_time ), removeBrackets(custom_time_format) );
end
if timer_mode ~= 2 then
--text_prefix = ""
-- text_suffix = ""
end
if not enable_property_text_prefix then text_prefix_validated = "" end
if not enable_property_text_suffix then text_suffix_validated = "" end
text = text_prefix_validated .. text .. text_suffix_validated ;
if text ~= last_text then
update_timer_display( timer_source, text );
end
--[[
]]
stop_media( "marker_a" );
stop_media( "marker_b" );
last_text = text;
--[[
Timer Ended
]]
local epsilon = 0.0001 -- tolerance value
if [Link](current_seconds) <= epsilon and ( timer_mode ~= 1 or
( direction_changed and current_count_direction == "DOWN" and prevent_negative_time
) ) then
--[[
]]--
if enable_marker_notes ~= 1 then
set_visible( media["note_source_marker_a"], false );
set_visible( media["note_source_marker_b"], false );
end
--[[
]]--
if timer_active then timer_ended( source_name ) end;
--[[
Credit:
Modified:
function: split time
type: Dependency / Support
input type: globals
returns: updates global split_data
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function split_unpack()
debug_log( 'split_unpack() -- function variable names: ' )
local data = nil;
local c = [Link]( split_itm );
local text = "";
local title = "";
local subtitle = "";
local line = "______________________________";
for i = 1, c do
local mark = split_itm[i];
local interval = mark;
if i > 1 then
local j = i - 1;
interval = split_itm[i] - split_itm[j];
end
--[[
"Interval" = 1
"Mark" = 2
"Mark Interval" = 3
"Interval Mark" = 4
]]
if split_type == 1 then
title = "Interval";
--subtitle = ""
text = tostring( raw_time( interval ) );
elseif split_type == 2 then
title = "Mark";
--subtitle = ""
text = tostring( raw_time( mark ) );
elseif split_type == 3 then
title = "Mark ";
subtitle = "Interval";
text = tostring( raw_time( mark ).."
"..raw_time( interval ) );
else -- "Interval Mark"
title = "Interval ";
subtitle = "Mark";
text = tostring( raw_time( interval ).."
"..raw_time( mark ) );
end;
-- data collection here
local n = i --formatting the index number
if i < 10 then n = "0"..tostring( i ) end;
if data ~= nil then
data = data .. "\n" .. n.." ) "..text;
else
data = "# "..title..subtitle.."\n"..line.."\n\n"..n.." )
"..text;
end
end -- end for
split_data = data;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Decide if current_seconds needs to reset to default_seconds
Credit:
Modified:
function: Check if current_seconds needs to reset to default_seconds
type: check
input type: timer_expire_event
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function update_default_time()
debug_log( 'update_default_time() -- function variable names: ' )
if timer_expire_event == "Source List" or timer_expire_event == "Scene List"
or timer_expire_event == "Auto List" then
return true;
end
return false;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Function to set the split time text
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_split_text( source_name )
debug_log( 'set_split_text(' .. pre_dump(source_name) .. ') -- function
variable names: source_name ' )
if source_name == nil or in_table( ignore_list, source_name ) then
return
end
local text = split_data;
if text ~= last_split_data then
set_text( source_name, text );
if backup_split_time then
write_to_file( '.txt', text, '-split-time' )
end
end
last_split_data = text;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Used when we need to set some globals for the timer to
default state
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function default_timer_globals( set_to_default )
debug_log( 'default_timer_globals(' .. pre_dump(set_to_default) .. ') --
function variable names: set_to_default ' )
--[[
if set_to_default == true
and timer_mode == 2 (Count Down)
]]
if set_to_default then
--[[
Used for source cycling
default_seconds: Default Seconds
the default timer state
This is the state of the timer that will set or
reset the time ( current_seconds )
If the timer expires because current_seconds == 0,
then the time ( current_seconds ) will be be restarted
from default_seconds for another function such as source cycling.
Every instance that a timer time is defined, we must record it to
default_seconds
THIS WILL UPDATE current_seconds to the value current_seconds
]]
--if set_to_default and timer_mode == 2 and update_default_time() then
--timer_value( default_seconds ) -- value, update_settings
--end
--[[
If timer is Count Up type and user pressed "reset" the timer must
always be reset to zero
]]
if timer_mode == 1 and reset_activated then
timer_value( 0 );
update_prop_settings_current_seconds( 0 );
end
color_normal_updated = false;
media["activated_media_marker_a"] = false;
media["activated_media_marker_b"] = false;
media["activated_marker_a"] = false;
media["activated_marker_b"] = false;
media["activated_time_marker_a"] = 0;
media["activated_time_marker_b"] = 0;
end
timer_expired = true;
completed_cycles = 0;
split_count = 0;
split_itm = {};
split_data = nil;
set_split_text( split_source );
orig_time = obs.os_gettime_ns();
if media["note_source_unversioned_id_marker_a"] == text_source_unversioned_id
then
set_visible( media["note_source_marker_a"], false );
end
if media["note_source_unversioned_id_marker_b"] == text_source_unversioned_id
then
set_visible( media["note_source_marker_b"], false );
end
--[[
-- TODO hide all note sources if nested in group
-- TODO do we need to show the group here?
]]
if media["note_source_unversioned_id_marker_a"] == "group" then
-- TODO set_visible( media["note_source_marker_a"], false );
end
if media["note_source_unversioned_id_marker_b"] == "group" then
-- TODO set_visible( media["note_source_marker_b"], false );
end
mili_toggle_triggered = false;
media["last_state_marker_a"] = obs.OBS_MEDIA_STATE_NONE;
media["last_state_marker_b"] = obs.OBS_MEDIA_STATE_NONE;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type: toggle_mili_trigger, set_time_text, timer_mode
returns: show_mili (bool)
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_mili( )
debug_log( 'reset_mili() -- function variable names: ' )
if not enable_property_toggle_mili_trigger then return end
if timer_mode ~= 2 then
return true;
end
--[[
]]
if toggle_mili_trigger ~= "" then
show_mili = false;
else
show_mili = true;
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Called if the timer setting change and needsto be updated.
default_seconds is used for source cycling
default_seconds: Default Seconds
the default timer state
This is the state of the timer that will set or
reset the time ( current_seconds )
If the timer expires because current_seconds == 0,
then the time ( current_seconds ) will be be
restarted
from default_seconds for another function such as
source cycling.
Every instance that a timer time is defined, we must
record it to default_seconds
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function update_timer_settings( set_to_default, new_settings ) -- optional
inputs: set_to_default(bool), new_settings(obs_property_data/obs_userdata)
debug_log( 'update_timer_settings(' .. pre_dump(set_to_default) .. ", " ..
pre_dump(new_settings) .. ') -- function variable names: set_to_default,
new_settings ' )
local update_timer_display = false;
set_to_default = set_to_default or false; -- incase not defined, set default
new_settings = new_settings or [Link]; -- incase not defined, set
default
--[[
]]
reset_mili( );
--[[
STOPWATCH
update_timer_display = true;
--[[
Count Down and a specific date.
The specific date will be converted
to seconds.
]]
local calculated_time = 0;
if countdown_type == 1 then
calculated_time = ( delta_time( timer_year, timer_month,
timer_day, timer_hours, timer_minutes, timer_seconds ) );
timer_value( calculated_time );
else
calculated_time = (
( obs.obs_data_get_int( new_settings, "hours" )*60*60 ) +
( obs.obs_data_get_int( new_settings, "minutes" )*60 ) +
obs.obs_data_get_int( new_settings, "seconds" )
);
end
--[[
This setting must only be applied in the following conditions:
]]
local do_update =
(
timer_expired
and
not timer_active
and
not activated
and
not set_to_default
or
in_table( {"Source List", "Scene List", "Auto List"},
timer_expire_event )
or
timer_mode_changed
);
--[[
]]
if do_update then
--[[
update timer time
]]
timer_value( calculated_time ); --
--[[
Used for countdown only
NB: This must always be called
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_callback()
debug_log( 'timer_callback() -- function variable names: ' )
time_frequency = get_frequency( ns_last );
set_time_direction( );
completed_cycles = completed_cycles + 1; -- we just keeping track of these
for debugging, if needed.
--[[
We need to update the timer display here to create the timer
animation,
technically the timer updates the text source every x seconds to
create
the animation effect.
]]
set_time_text( timer_source );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Remove timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function end_timer()
debug_log( 'end_timer() -- function variable names: ' )
timer_active = false;
timer_remove( timer_callback ); -- Removing the callback stops the timer
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Add timer here so we have a global setting
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function start_timer()
debug_log( 'start_timer() -- function variable names: ' )
record( 6, 100 ); -- wait 100 miliseconds
timer_active = true;
timer_remove( timer_callback ); -- Remove any existing callbacks if they
exist before assigning a new callback
timer_add( timer_callback, timer_cycle ); --<- milliseconds
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function activate( activating )
debug_log( 'activate(' .. pre_dump(activating) .. ') -- function variable
names: activating ' )
--[[
We skip/cancel anything requested if the
Script was disabled by the user.
]]
if disable_script then
return;
end
]]
if activating then
--[[
if timer is activating, it has not expired
]]
timer_expired = false;
--[[
Once the timer started, this setting will default
]]
set_timer_activated = false;
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function start( pressed )
debug_log( 'start(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not pressed then
return;
end
--[[
Set timer source visibility to visible
]]
set_visible( timer_source, true );
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function pause( pressed )
debug_log( 'pause(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not pressed then
return;
end
--[[
Set timer source visibility to visible
]]
set_visible( timer_source, true );
if timer_active then
activate( false );
end;
pause_play_media( media["source_name_audio_marker_a"], not timer_active );
pause_play_media( media["source_name_audio_marker_b"], not timer_active );
return;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Usually called by a button or hotkey press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function startpause( pressed, force_activate )
debug_log( 'startpausepause(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
if not pressed then
return;
end
force_activate = force_activate or false
--[[
Set timer source visibility to visible
]]
if not is_visible( timer_source ) then
set_visible( timer_source, true );
end
if timer_active then
activate( false );
else
if activated == false and ( not split_startpause or force_activate )
then
activate( true );
end;
end;
pause_play_media( media["source_name_audio_marker_a"], not timer_active );
pause_play_media( media["source_name_audio_marker_b"], not timer_active );
return;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_start( pressed )
debug_log( 'hotkey_send_start(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_pause( pressed )
debug_log( 'hotkey_send_pause(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function: Used to manually set stopwatch
type: Dependency / Support
input type: none
returns: calls set_time_text()
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function set_stopwatch()
debug_log( 'set_stopwatch() -- function variable names: ' )
time_frequency = get_frequency( ns_last );
local dd = ( sw_days_saved * 86400 )
local hh = ( sw_hours_saved * 3600 );
local mm = ( sw_minutes_saved * 60 );
local ss = ( sw_seconds_saved );
local ff = ( sw_milliseconds_saved / ( 99 + time_frequency ) );
local time = ( dd + hh + mm + ss + ff );
timer_value( time ); -- Update the last saved time here
set_time_text( timer_source );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: A leap year comes once in four years,
in which February month has 29 days.
With this additional day in February,
a year becomes a Leap year.
on every year that is evenly divisible by 4
except every year that is evenly divisible by 100
unless the year is also evenly divisible by 400
Credit: et al
Modified:
function: A leap year is a year with 366 days instead of 365
type: Dependency / Support, UI
input type: integer
returns: bool
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function is_leap_year( year )
debug_log( 'is_leap_year(' .. pre_dump(year) .. ') -- function variable names:
year ' )
if year % 4 == 0 then -- A leap year comes once in four years
if year % 100 == 0 then
if year % 400 == 0 then
return true;
else
return false;
end;
else
return true;
end;
else
return false;
end;
--return year%4==0 and (year%100~=0 or year%400==0) -- shorthand
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Callback for button press
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function mili_button_clicked( props, p, settings )
debug_log( 'mili_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p) ..
", " .. pre_dump(settings) .. ') -- function variable names: props, p, settings
' )
if not enable_property_toggle_mili_trigger then return end
mili( true );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function update_button_label( props )
debug_log( 'update_button_label(' .. pre_dump(props) .. ') -- function variable
names: props ' )
--[[
A button has it's own callback so we can not action anything
on the button press through the Properties Callback, instead
we will action it on the button Callback directly.
]]
local mode = obs.obs_data_get_int( [Link], "timer_mode" );
local direction_button_prop = obs.obs_properties_get( props,
"direction_button" );
--[[
We are only setting the button label depending if the timer is active
and on the timer type.
]]
if current_count_direction == "DOWN" then
obs.obs_property_set_description( direction_button_prop, "Toggle: Count
Up" );
else
obs.obs_property_set_description( direction_button_prop, "Toggle: Count
Down" );
end
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Callback for button press
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function direction_button_clicked( props, p, settings )
debug_log( 'direction_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ", " .. pre_dump(settings) .. ') -- function variable names: props,
p, settings ' )
--[[
Only allow if enable
]]
if not enable_direction_toggle then
return;
end
update_timer_direction( true );
update_button_label( props );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_timer_direction( pressed )
debug_log( 'update_timer_direction(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
if not pressed and not enable_direction_toggle then
return;
end
--[[
Signal that the feature is in use, this will indicate that 'normal
operation'
is suspended. It will be reset if 'Reset' is called.
]]
--[[
Change direction each time the feature is activated
]]
current_count_direction = ( current_count_direction == "UP" and "DOWN" or
"UP")
--[[
Make sure the trigger is as accurate as possible depending
if the timer is counting up or down.
]]
if timer_mode == 1 then
count_orientation = current_count_direction == "UP" and "NORMAL" or
"INVERTED"
end
if timer_mode == 2 then
count_orientation = current_count_direction == "DOWN" and "NORMAL" or
"INVERTED"
end
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function mili( pressed )
debug_log( 'mili(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not pressed then
return;
end
if show_mili then
show_mili = false;
else
show_mili = true;
end
--[[
The timer text will update if the timer is active
but not if it is paused. Lets update it if in the
paused (inactive) state.
]]
if not timer_active then
set_time_text( timer_source );
end
--[[
A button has it's own callback so we can not action anything
on the button press through the Properties Callback, instead
we will action it on the button Callback directly.
]]
local mode = obs.obs_data_get_int( [Link], "timer_mode" );
local mili_button_prop = obs.obs_properties_get( props, "mili_button" ); --
should it not be [Link]
--[[
We are only setting the button label depending if the timer"s
milliseconds
value visibility state.
]]
if show_mili then
obs.obs_property_set_description( mili_button_prop, "Hide Milliseconds"
);
else
obs.obs_property_set_description( mili_button_prop, "Show Milliseconds"
);
end
return true
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_mili( pressed )
debug_log( 'hotkey_send_mili(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_direction( pressed )
debug_log( 'hotkey_send_direction(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function sal_timer_callback()
debug_log( 'sal_timer_callback() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
set_visible( add_limit_note_source, false );
timer_remove( sal_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function start_sal_timer()
debug_log( 'start_sal_timer() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
set_visible( add_limit_note_source, true );
if add_limit_note_source_visible == 0 then return end;
timer_remove( sal_timer_callback ); -- Remove any existing callbacks if they
exist before assigning a new callback
timer_add( sal_timer_callback, add_limit_note_source_visible );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sal_check( )
debug_log( 'sal_check() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_add_limit == 0 then return end;
if sec_add_limit_used >= sec_add_limit then
start_sal_timer();
else
set_visible( add_limit_note_source, false );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_1_update( )
debug_log( 'sec_add_1_update() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_add_limit ~= 0 and sec_add_limit_used >= sec_add_limit then
-- do nothing
else
timer_value( current_seconds + sec_add_1 );
local update_value = sec_add_limit_used + 1;
sec_add_limit_used = update_value;
update_properties_setting_int( "sec_add_limit_used", update_value );
end;
sal_check( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_2_update( )
debug_log( 'sec_add_2_update() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_add_limit ~= 0 and sec_add_limit_used >= sec_add_limit then
-- do nothing
else
timer_value( current_seconds + sec_add_2 );
local update_value = sec_add_limit_used + 1;
sec_add_limit_used = update_value;
update_properties_setting_int( "sec_add_limit_used", update_value );
end;
sal_check( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_3_update( )
debug_log( 'sec_add_3_update() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_add_limit ~= 0 and sec_add_limit_used >= sec_add_limit then
-- do nothing
else
timer_value( current_seconds + sec_add_3 );
local update_value = sec_add_limit_used + 1;
sec_add_limit_used = update_value;
update_properties_setting_int( "sec_add_limit_used", update_value );
end;
sal_check( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function ssl_timer_callback()
debug_log( 'ssl_timer_callback() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
set_visible( sub_limit_note_source, false );
timer_remove( ssl_timer_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function start_ssl_timer()
debug_log( 'start_ssl_timer() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
set_visible( sub_limit_note_source, true );
if sub_limit_note_source_visible == 0 then return end;
timer_remove( ssl_timer_callback ); -- Remove any existing callbacks if they
exist before assigning a new callback
timer_add( ssl_timer_callback, sub_limit_note_source_visible );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function ssl_check( )
debug_log( 'ssl_check() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_sub_limit == 0 then return end;
if sec_sub_limit_used >= sec_sub_limit then
start_ssl_timer();
else
set_visible( sub_limit_note_source, false );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_sub_1_update( )
debug_log( 'sec_sub_1_update() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_sub_limit ~= 0 and sec_sub_limit_used >= sec_sub_limit then
-- do nothing
else
timer_value( current_seconds - sec_sub_1 );
local update_value = sec_sub_limit_used + 1;
sec_sub_limit_used = update_value;
update_properties_setting_int( "sec_sub_limit_used", update_value );
end;
ssl_check( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_sub_2_update( )
debug_log( 'sec_sub_2_update() -- function variable names: ' )
if not enable_property_timer_manipulation then return end
if timer_manipulation == 3 then return end;
if sec_sub_limit ~= 0 and sec_sub_limit_used >= sec_sub_limit then
-- do nothing
else
timer_value( current_seconds - sec_sub_2 );
local update_value = sec_sub_limit_used + 1;
sec_sub_limit_used = update_value;
update_properties_setting_int( "sec_sub_limit_used", update_value );
end;
ssl_check( );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_add_1( pressed )
debug_log( 'hotkey_send_sec_add_1(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_add_2( pressed )
debug_log( 'hotkey_send_sec_add_2(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_add_3( pressed )
debug_log( 'hotkey_send_sec_add_3(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_sub_1( pressed )
debug_log( 'hotkey_send_sec_sub_1(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_sub_2( pressed )
debug_log( 'hotkey_send_sec_sub_2(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_sec_sub_3( pressed )
debug_log( 'hotkey_send_sec_sub_3(' .. pre_dump(pressed) .. ') -- function
variable names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset( pressed )
debug_log( 'reset(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not script_ready then return end
reset_activated = true; -- notify timer settings a reset call is in process
--[[
For hotkeys: This is called on key down & key up. A bool check:
]]
--obs.obs_properties_apply_settings( [Link], [Link] ); -- BUG>
Failed to call timer_cb for timer_call: attempt to call a nil value
sec_add_limit_used = 0;
sec_sub_limit_used = 0;
--[[
Set bool to first position
]]
media["media_ended_marker_a"] = false;
media["media_ended_marker_b"] = false;
color_normal_updated = false;
set_timer_activated = false;
direction_changed = false;
media["activated_media_marker_a"] = false;
media["activated_media_marker_b"] = false;
media["activated_marker_a"] = false;
media["activated_marker_b"] = false;
media["activated_time_marker_a"] = 0;
media["activated_time_marker_b"] = 0;
set_text_note_color( "marker_a" );
set_text_note_color( "marker_b" );
media["used_note_source_marker_a"] = [Link]()
media["used_note_source_marker_b"] = [Link]()
reset_group_note_sources( note_source_marker_a )
reset_group_note_sources( note_source_marker_b )
--[[
Reset the current_count_direction
If the timer is in Count Up mode the
timer is counting up
]]
count_orientation = "NORMAL"
last_orientation = "NORMAL"
if timer_mode == 1 then
current_count_direction = "UP";
else
current_count_direction = "DOWN";
end
--[[
]]
last_text = tostring( obs.os_gettime_ns() );
--[[
timer_mode: eiher
timer_active: either
define > set_to_default: (true) * User requested a reset, so we do not
want to set the settings to default.
define > new_settings: not required here because we will use the global
([Link])
purpose: User is resetting the timer settings and we need to provide
instant feedback output to the timer display (timer text source)
]]
update_timer_settings( true ); -- optional inputs: set_to_default(bool),
new_settings(obs_property_data/obs_userdata) -- based on UI Settings
--[[
Handle Timer Callback
]]
activate( false ); -- start or stop the timer, in this case, stop the timer
and get it ready start again
--[[
]]
set_split_text( split_source );
--[[
]]
if active_source ~= "Select" then
--[[
Make sure the trigger is as accurate as possible depending
if the timer is counting up or down.
]]
reset_audio_marker_arr();
local round_seconds = roundSeconds();
update_time_markers( round_seconds );
update_media_names( true );
reset_activated = false; -- notify timer settings a reset call ended
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_activation_source_activate_signal( cd, connected )
debug_log( 'timer_activation_source_activate_signal(' .. pre_dump(cd) .. ",
" .. pre_dump(connected) .. ') -- function variable names: cd, connected ' )
--[[
Capture / Retrieve Callback Data
]]
if timer_activation_source == "select" then return end
if timer_activation == 5 then
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function activate_signal( cd, connected )
debug_log( 'activate_signal(' .. pre_dump(cd) .. ", " .. pre_dump(connected) ..
') -- function variable names: cd, connected ' )
--[[
]]
local source = obs.calldata_source( cd, "source" );
--[[
Do we have a Source?
]]
if source ~= nil then
]]
if ( name == timer_source ) then
if connected then record( 5, 300 ) end;
if connected then
activate( true );
else
activate( false );
end;
end;
end;
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function activate_reset( pressed )
debug_log( 'activate_reset(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_reset( pressed )
debug_log( 'hotkey_send_reset(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function: Update start/puase button label
type:
input type: mode, timer_active
returns: props
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function property_button_update_start( props )
debug_log( 'property_button_update_start(' .. pre_dump(props) .. ') -- function
variable names: props ' )
--[[
A button has it's own callback so we can not action anything
on the button press through the Properties Callback, instead
we will action it on the button Callback directly.
]]
local mode = obs.obs_data_get_int( [Link], "timer_mode" );
local pause_button_prop = obs.obs_properties_get( props, "pause_button" );
local start_button_prop = obs.obs_properties_get( props, "start_button" );
local direction_button_prop = obs.obs_properties_get( props,
"direction_button" );
--[[
We are only setting the button label depending if the timer is active
and on the timer type.
]]
if mode == 2 then
obs.obs_property_set_description( direction_button_prop, "Toggle:
Count Up" );
if timer_active then
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Down Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Down Timer" );
else
obs.obs_property_set_description( pause_button_prop,
"Start/Pause Count Down Timer" );
end
else
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Down Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Down Timer" );
else
obs.obs_property_set_description( pause_button_prop, "Start
Count Down Timer" );
end
end;
else
obs.obs_property_set_description( direction_button_prop, "Toggle:
Count Down" );
if timer_active then
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Up Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Up Timer" );
else
obs.obs_property_set_description( pause_button_prop,
"Start/Pause Count Up Timer" );
end
else
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Up Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Up Timer" );
else
obs.obs_property_set_description( pause_button_prop, "Start
Count Up Timer" );
end
end;
end;
return props;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function start_button_clicked( props, p )
debug_log( 'start_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p) ..
') -- function variable names: props, p ' )
start( true );
property_button_update_start( props );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function pause_button_clicked( props, p )
debug_log( 'pause_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p) ..
') -- function variable names: props, p ' )
startpause( true );
property_button_update_start( props );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_1_button_clicked( props, p )
debug_log( 'sec_add_1_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_add_1_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_2_button_clicked( props, p )
debug_log( 'sec_add_2_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_add_2_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_add_3_button_clicked( props, p )
debug_log( 'sec_add_3_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_add_3_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_sub_1_button_clicked( props, p )
debug_log( 'sec_sub_1_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_sub_1_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_sub_2_button_clicked( props, p )
debug_log( 'sec_sub_2_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_sub_2_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sec_sub_3_button_clicked( props, p )
debug_log( 'sec_sub_3_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
sec_sub_3_update( );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Usually called by a button or hotkey press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function export( pressed )
debug_log( 'export(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not pressed then
return;
end;
local file_exported = write_to_json( [Link] );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function export_button_clicked( props, p )
debug_log( 'export_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(p) .. ') -- function variable names: props, p ' )
export( true );
return false;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback on property modification
Credit:
Modified:
function: Callback for Settings import
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function import_properties( props, property, settings )
debug_log( 'import_properties(' .. pre_dump(props) .. ", " ..
pre_dump(property) .. ", " .. pre_dump(settings) .. ') -- function variable names:
props, property, settings ' )
local property_name = obs.obs_property_name( property );
local import_folder = backup_folder
-- convert Windows path to UNIX path
import_folder = import_folder .. "/" .. import_list .. ".json"
import_folder = import_folder:gsub([[\]], "/");
if obs.os_file_exists( import_folder ) then
data = obs.obs_data_create_from_json_file( import_folder )
if data ~= nil then
obs.obs_data_apply( settings, data )
obs.obs_data_set_string( settings, "import_list", "select")
[Link] = settings
end
end
-- IMPORTANT: returns true to trigger refresh of the properties
return true
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function import_button_clicked( props, property, settings )
debug_log( 'import_button_clicked(' .. pre_dump(props) .. ", " ..
pre_dump(property) .. ", " .. pre_dump(settings) .. ') -- function variable names:
props, p, settings ' )
local property_name = obs.obs_property_name( property );
-- IMPORTANT: returns true to trigger refresh of the properties
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function sw_saved_button_clicked( props, p, settings )
debug_log( 'sw_saved_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p)
.. ", " .. pre_dump(settings) .. ') -- function variable names: props, p, settings
' )
if timer_mode == 1 then
set_stopwatch();
set_timer_activated = true;
end;
return false;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback for button press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function reset_button_clicked( props, p, settings )
debug_log( 'reset_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p) ..
", " .. pre_dump(settings) .. ') -- function variable names: props, p, settings
' )
activate_reset( true );
return true;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Usually called by a button or hotkey press
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function split_time( pressed )
debug_log( 'split_time(' .. pre_dump(pressed) .. ') -- function variable names:
pressed ' )
if not pressed then
return;
end;
if timer_active then
split_count = split_count + 1;
split_itm[split_count] = current_seconds;
split_unpack();
set_split_text( split_source );
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function: reset timer
type:
input type:
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function hotkey_send_split( pressed )
debug_log( 'hotkey_send_split(' .. pre_dump(pressed) .. ') -- function variable
names: pressed ' )
--[[
For hotkeys: This is called on key down & key up. A bool check:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function split_button_clicked( props, p )
debug_log( 'split_button_clicked(' .. pre_dump(props) .. ", " .. pre_dump(p) ..
') -- function variable names: props, p ' )
split_time( true );
return false;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function load_settings_globals( settings )
debug_log( 'load_settings_globals(' .. pre_dump(settings) .. ') -- function
variable names: settings ' )
--[[
"Default"
"Timer Source Visible"
"Timer Scene Active"
"Specific Scene Active"
"Manual"
"Auto"
]]
update_source_list();
--[[
Make sure the trigger is as accurate as possible depending
if the timer is counting up or down.
]]
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function init()
debug_log( 'init' )
obs.obs_data_set_bool( [Link], "script_ready", true ); -- set to
signal ready state.
debug_log( 'loaded set script_ready (' .. pre_dump(true) .. ') ' )
--[[
load any property values available to globals
]]
load_settings_globals( [Link] );
timer_value( 0 );
reset( true ); -- <BUG signal handler crash on startup?
end;
else
reset( true ); -- <BUG signal handler crash on startup?
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: custom function
we use this to get a signal handler for a specific
source once
it is loaded to ensure it is connected when OBS
starts up
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function loaded( cd )
debug_log( 'loaded(' .. pre_dump(cd) .. ') -- function variable names: cd ' )
--[[
Some of the functions included requires the source to be loaded,
so check that all sources are loaded before continuing
]]
if all_sources_loaded then
debug_log( 'all_sources_loaded are now loaded!' )
init();
end;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_show( cd )
debug_log( 'source_show(' .. pre_dump(cd) .. ') -- function variable names: cd
' )
activate_signal( cd, false );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_hide( cd )
debug_log( 'source_hide(' .. pre_dump(cd) .. ') -- function variable names:
cd ' )
activate_signal( cd, true );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_activated( cd )
debug_log( 'source_activated(' .. pre_dump(cd) .. ') -- function variable
names: cd ' )
activate_signal( cd, true );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function source_deactivated( cd )
debug_log( 'source_deactivated(' .. pre_dump(cd) .. ') -- function variable
names: cd ' )
activate_signal( cd, false );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_activation_source_activated( cd )
debug_log( 'timer_activation_source_activated(' .. pre_dump(cd) .. ') --
function variable names: cd ' )
timer_activation_source_activate_signal( cd, true );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_activation_source_deactivated( cd )
debug_log( 'timer_activation_source_deactivated(' .. pre_dump(cd) .. ') --
function variable names: cd ' )
timer_activation_source_activate_signal( cd, false );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Called when a source is activated/deactivated
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_activation_source_media( cd )
debug_log( 'timer_activation_source_media(' .. pre_dump(cd) .. ", " ..
pre_dump(connected) .. ') -- function variable names: cd, connected ' )
--[[
Capture / Retrieve Callback Data
]]
if timer_activation_source == "select" then return end
if timer_activation == 6 then
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function timer_activation_source_media_started( cd )
debug_log( 'timer_activation_source_media_started(' .. pre_dump(cd) .. ') --
function variable names: cd ' )
timer_activation_source_media( cd );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description:
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function timer_activation_signals()
debug_log( 'timer_activation_signals(' .. pre_dump(settings) .. ') -- function
variable names: settings ' )
if timer_activation_source ~= "select" then
if timer_activation == 5 then
local source =
obs.obs_get_source_by_name( timer_activation_source ); -- Increments the source
reference counter, use obs_source_release() to release it when complete.
--[[
Found Source?
]]
if source ~= nil then
connectSignalHandler( source, "activate",
timer_activation_source_activated )
connectSignalHandler( source, "deactivate",
timer_activation_source_deactivated )
end;
obs.obs_source_release( source );
end
if timer_activation == 6 then
local source =
obs.obs_get_source_by_name( timer_activation_source ); -- Increments the source
reference counter, use obs_source_release() to release it when complete.
--[[
Found Source?
]]
if source ~= nil then
connectSignalHandler( source, "media_started",
timer_activation_source_media_started ) -- Called when media has started.
end;
obs.obs_source_release( source );
end
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Callback on property modification
Credit:
Modified:
function:
type: property event
input type: props, property, settings
returns: true to update properties
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
local function property_onchange( props, property, settings )
if disable_script then return; end;
debug_log( 'property_onchange(' .. pre_dump(props) .. ", " ..
pre_dump(property) .. ", " .. pre_dump(settings) .. ') -- function variable names:
props, property, settings ' )
--[[
]]
local property_name = obs.obs_property_name( property );
if prevent_callback then return end
--[[
PROPERTY VALUE
]]
local script_ready_value = obs.obs_data_get_bool( settings,
"script_ready" );-- -- Retrieves property value from reference
--[[
let's make sure we are not responding to nil values during a
script refresh
The form has been marked as ready, this happens during script
load, so if
the Property script_ready_value is equal to nil then we return.
]]
if script_ready and not script_ready_value then
return
end
BACKUP PROPERTIES
]]
local backup_mode_prop = obs.obs_properties_get( props, "backup_mode" );
local backup_split_time_prop = obs.obs_properties_get( props,
"backup_split_time" );
local debug_enabled_prop = obs.obs_properties_get( props, "debug_enabled" );
local import_list_prop = obs.obs_properties_get( props, "import_list" );
--[[
TIMER PROPERTIES
]]
local sec_add_1_prop = obs.obs_properties_get( props, "sec_add_1" );
local sec_add_2_prop = obs.obs_properties_get( props, "sec_add_2" );
local sec_add_3_prop = obs.obs_properties_get( props, "sec_add_3" );
local sec_sub_1_prop = obs.obs_properties_get( props, "sec_sub_1" );
local sec_sub_2_prop = obs.obs_properties_get( props, "sec_sub_2" );
local sec_sub_3_prop = obs.obs_properties_get( props, "sec_sub_3" );
local sec_add_limit_prop = obs.obs_properties_get( props, "sec_add_limit" );
local sec_sub_limit_prop = obs.obs_properties_get( props, "sec_sub_limit" );
local timer_manipulation_prop = obs.obs_properties_get( props,
"timer_manipulation" );
local mili_button_prop = obs.obs_properties_get( props, "mili_button" );
local timer_source_prop = obs.obs_properties_get( props, "timer_source" );
local timer_activation_prop = obs.obs_properties_get( props,
"timer_activation" );
local timer_activation_source_prop = obs.obs_properties_get( props,
"timer_activation_source" );
local timer_reset_prop = obs.obs_properties_get( props, "timer_reset" );
local start_button_prop = obs.obs_properties_get( props, "start_button" );
local pause_button_prop = obs.obs_properties_get( props, "pause_button" );
local reset_button_prop = obs.obs_properties_get( props, "reset_button" );
local direction_button_prop = obs.obs_properties_get( props,
"direction_button" );
local timer_options_prop = obs.obs_properties_get( props, "timer_options" );
local custom_time_format_prop = obs.obs_properties_get( props,
"custom_time_format" );
local toggle_mili_trigger_prop = obs.obs_properties_get( props,
"toggle_mili_trigger" );
local add_limit_note_source_visible_prop = obs.obs_properties_get( props,
"add_limit_note_source_visible" );
local sub_limit_note_source_visible_prop = obs.obs_properties_get( props,
"sub_limit_note_source_visible" );
--[[
STOPWATCH PROPERTIES
]]
local _group_1_prop = obs.obs_properties_get( props, "_group_1" );
local _group_2_prop = obs.obs_properties_get( props, "_group_2" );
local _group_3_prop = obs.obs_properties_get( props, "_group_3" );
local sw_hours_saved_prop = obs.obs_properties_get( props,
"sw_hours_saved" );
local sw_minutes_saved_prop = obs.obs_properties_get( props,
"sw_minutes_saved" );
local set_stopwatch_prop = obs.obs_properties_get( props, "set_stopwatch" );
--[[
COUNTDOWN PROPERTIES
]]
local day_prop = obs.obs_properties_get( props, "day" );
local year_prop = obs.obs_properties_get( props, "year" );
local month_prop = obs.obs_properties_get( props, "month" );
local day_text_prop = obs.obs_properties_get( props, "day_text" );
local days_text_prop = obs.obs_properties_get( props, "days_text" );
local stop_text_prop = obs.obs_properties_get( props, "stop_text" );
local cycle_list_prop = obs.obs_properties_get( props, "cycle_list" );
local text_prefix_prop = obs.obs_properties_get( props, "text_prefix" );
local text_suffix_prop = obs.obs_properties_get( props, "text_suffix" );
local active_source_prop = obs.obs_properties_get( props, "active_source" );
PROPERTIES
]]
local hours_prop = obs.obs_properties_get( props, "hours" );
local minutes_prop = obs.obs_properties_get( props, "minutes" );
local seconds_prop = obs.obs_properties_get( props, "seconds" );
local split_type_prop = obs.obs_properties_get( props, "split_type" );
local timer_expire_event_prop = obs.obs_properties_get( props,
"timer_expire_event" );
local cycle_source_children_prop = obs.obs_properties_get( props,
"cycle_source_children" );
local split_button_prop = obs.obs_properties_get( props, "split_button" );
local split_source_prop = obs.obs_properties_get( props, "split_source" );
local timer_format_prop = obs.obs_properties_get( props, "timer_format" );
local color_normal_prop = obs.obs_properties_get( props, "color_normal" );
local countdown_type_prop = obs.obs_properties_get( props,
"countdown_type" );
local start_recording_prop = obs.obs_properties_get( props, "start_recording"
);
local select_features_prop = obs.obs_properties_get( props, "select_features"
);
local _group_4_prop = obs.obs_properties_get( props, "_group_4" );
--[[
PROPERTIES
]]
local export_button_prop = obs.obs_properties_get( props, "export_button" );
local import_button_prop = obs.obs_properties_get( props, "import_button" );
local export_folder_prop = obs.obs_properties_get( props, "backup_folder" );
local disable_script_prop = obs.obs_properties_get( props,
"disable_script" );
local enable_direction_toggle_prop = obs.obs_properties_get( props,
"enable_direction_toggle" );
local prevent_negative_time_prop = obs.obs_properties_get( props,
"prevent_negative_time" );
--[[
]]
local to_prop = obs.obs_properties_get( props, "trigger_options" );
local a_note_prop = obs.obs_properties_get( props, "note_marker_a" );
local b_note_prop = obs.obs_properties_get( props, "note_marker_b" );
local enable_marker_notes_prop = obs.obs_properties_get( props,
"enable_marker_notes" );
local text_marker_tip_prop = obs.obs_properties_get( props, "text_marker_tip"
);
local text_arr_marker_a_prop = obs.obs_properties_get( props,
"text_arr_marker_a" );
local text_arr_marker_b_prop = obs.obs_properties_get( props,
"text_arr_marker_b" );
local color_marker_a_prop = obs.obs_properties_get( props,
"color_marker_a" );
local color_marker_b_prop = obs.obs_properties_get( props,
"color_marker_b" );
local audio_marker_a_prop = obs.obs_properties_get( props,
"audio_marker_a" );
local audio_marker_b_prop = obs.obs_properties_get( props,
"audio_marker_b" );
local audio_marker_a_arr_prop = obs.obs_properties_get( props,
"audio_marker_a_arr" );
local audio_marker_b_arr_prop = obs.obs_properties_get( props,
"audio_marker_b_arr" );
local audio_marker_end_prop = obs.obs_properties_get( props,
"audio_marker_end" );
local a_source_prop = obs.obs_properties_get( props,
"note_source_marker_a" );
local b_source_prop = obs.obs_properties_get( props,
"note_source_marker_b" );
local duration_marker_a_prop = obs.obs_properties_get( props,
"duration_marker_a" );
local duration_marker_b_prop = obs.obs_properties_get( props,
"duration_marker_b" );
local reset_text_marker_a_prop = obs.obs_properties_get( props,
"reset_text_marker_a" );
local reset_text_marker_b_prop = obs.obs_properties_get( props,
"reset_text_marker_b" );
local hide_note_marker_a_prop = obs.obs_properties_get( props,
"hide_note_marker_a" );
local hide_note_marker_b_prop = obs.obs_properties_get( props,
"hide_note_marker_b" );
local duration_marker_end_prop = obs.obs_properties_get( props,
"duration_marker_end" );
local media_playback_limit_prop = obs.obs_properties_get( props,
"media_playback_limit" );
--[[
TIMER INPUTS
]]
obs.obs_property_set_visible( timer_options_prop, layout_value == 2 );
obs.obs_property_set_visible( timer_manipulation_prop,
enable_property_timer_manipulation and layout_value == 2 and timer_options_value ==
2 and not in_table( ignore_list, timer_source_value ) );
obs.obs_property_set_visible( direction_button_prop, layout_value == 2 and
enable_direction_toggle and ( timer_mode_value == 2 and countdown_type_value == 2
or timer_mode_value == 1 ) and not in_table( ignore_list, timer_source_value ) );
--
obs.obs_property_set_visible( custom_time_format_prop, timer_format == 5 and
not in_table( ignore_list, timer_source_value ) and layout_value == 2 and
timer_options_value == 2 );
obs.obs_property_set_visible( add_limit_note_source_visible_prop,
add_limit_note_source ~= "select" and not in_table( ignore_list, timer_source_value
) );
obs.obs_property_set_visible( timer_activation_prop,
enable_property_timer_activation and layout_value == 2 and timer_options_value == 2
and not in_table( ignore_list, timer_source_value ) );
obs.obs_property_set_visible( timer_reset_prop,
enable_property_timer_activation and layout_value == 2 and timer_options_value == 2
and timer_activation ~= 1 and not in_table( ignore_list, timer_source_value ) );
obs.obs_property_set_visible( timer_activation_source_prop,
enable_property_timer_activation and layout_value == 2 and timer_options_value == 2
and in_table( {4,5,6}, timer_activation ) and not in_table( ignore_list,
timer_source_value ) );
--[[
]]
obs.obs_property_set_visible( debug_enabled_prop, enable_property_debug and (
layout_value == 2 ) and timer_options_value == 2 );
obs.obs_property_set_visible( backup_mode_prop, enable_property_backup and
( layout_value == 2 ) and not in_table( ignore_list, timer_source_value ) and
timer_options_value == 2 );
obs.obs_property_set_visible( backup_split_time_prop, enable_property_backup
and ( layout_value == 2 ) and backup_mode_value and not in_table( ignore_list,
timer_source_value ) and timer_options_value == 2 );
obs.obs_property_set_visible( import_list_prop, enable_property_backup and
backup_mode_value and backup_folder ~= "" and backup_folder ~= nil and layout_value
== 2 and not in_table( ignore_list, timer_source_value ) and timer_options_value ==
2 );
obs.obs_property_set_visible( export_button_prop, enable_property_backup and
backup_mode_value and backup_folder ~= "" and backup_folder ~= nil and
layout_value == 2 and not in_table( ignore_list, timer_source_value ) );
obs.obs_property_set_visible( import_button_prop, enable_property_backup and
backup_mode_value and layout_value == 2 and not in_table( ignore_list,
timer_source_value ) and timer_options_value == 2 );
obs.obs_property_set_visible( export_folder_prop, enable_property_backup and
backup_mode_value and layout_value == 2 and not in_table( ignore_list,
timer_source_value ) and timer_options_value == 2 );
obs.obs_property_set_visible( import_button_prop, import_list_value ~=
"select" and import_list_value ~= "none" and import_list_value ~= "" and
layout_value == 2 and not in_table( ignore_list, timer_source_value ) and
timer_options_value == 2 );
--[[
OTHER INPUTS
]]
obs.obs_property_set_visible( disable_script_prop, layout_value == 2 );
obs.obs_property_set_visible( enable_direction_toggle_prop, layout_value == 2
and timer_options_value == 2 and ( timer_mode_value == 2 and countdown_type_value
== 2 or timer_mode_value == 1 ) and not in_table( ignore_list, timer_source_value )
);
obs.obs_property_set_visible( prevent_negative_time_prop,
enable_direction_toggle and layout_value == 2 and ( timer_mode_value == 2 and
countdown_type_value == 2 or timer_mode_value == 1 ) and not in_table( ignore_list,
timer_source_value ) and timer_options_value == 2 );
]]
if ( in_table( {timer_source_value, split_source_value, active_source_value,
note_source_marker_b_value}, note_source_marker_a_value ) ) then
obs.obs_data_set_string( settings, "note_source_marker_a", "select" );
-- Don"t allow timer and marker_a note text source to be the same
end
if ( in_table( {timer_source_value, split_source_value, active_source_value,
note_source_marker_a_value}, note_source_marker_b_value ) ) then
obs.obs_data_set_string( settings, "note_source_marker_b", "select" );
-- Don"t allow timer and marker_b note text source to be the same
end
if ( in_table( {timer_source_value, split_source_value,
note_source_marker_a_value, note_source_marker_b_value}, active_source_value ) )
then
obs.obs_data_set_string( settings, "active_source", "select" ); --
Don"t allow timer and active text source to be the same
end
if countdown_type_value == 1 and month_value ~= 1 and day_value == 0 then
obs.obs_data_set_int( settings, "day", 1 ); -- set to at least 1, else
the timer won"t know it is at zero
end
--[[
]]
]]
if show_mili then
obs.obs_property_set_description( mili_button_prop, "Hide Milliseconds"
);
else
obs.obs_property_set_description( mili_button_prop, "Show Milliseconds"
);
end;
--[[
]]
--[[
]]
if timer_mode_value == 2 then
obs.obs_property_set_description( reset_button_prop, "Reset Count Down
Timer" );
else
--[[
Timer type is Count Up?
Set button labels
]]
obs.obs_property_set_description( reset_button_prop, "Reset Count Up
Timer" );
end;
--[[
Set button labels
]]
if timer_mode_value == 2 then
obs.obs_property_set_description( direction_button_prop, "Count
Up" );
if timer_active then
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Down Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Down Timer" );
else
obs.obs_property_set_description( pause_button_prop,
"Start/Pause Count Down Timer" );
end
else
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Down Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Down Timer" );
else
obs.obs_property_set_description( pause_button_prop, "Start
Count Down Timer" );
end
end;
else
obs.obs_property_set_description( direction_button_prop, "Toggle:
Count Down" );
if timer_active then
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Up Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Up Timer" );
else
obs.obs_property_set_description( pause_button_prop,
"Start/Pause Count Up Timer" );
end
else
if split_startpause then
obs.obs_property_set_description( start_button_prop, "Start
Count Up Timer" );
obs.obs_property_set_description( pause_button_prop, "Pause
Count Up Timer" );
else
obs.obs_property_set_description( pause_button_prop, "Start
Count Up Timer" );
end
end;
end;
--[[
Rebuild timer activation source lists
]]
obs.obs_property_list_clear( timer_activation_source_prop );
obs.obs_property_list_add_string( timer_activation_source_prop, "Select",
"select" );
--[[
Returns an array of reference-incremented sources.
Release with source_list_release().
]]
local all_sources = get_source_list( "*" );
--[[
Rebuild text source lists
]]
if tableHasKey( selected_source_list, property_name ) then
for i,v in pairs( {timer_source_prop, split_source_prop,
active_source_prop, sub_limit_note_source_prop, note_source_marker_a_prop,
note_source_marker_b_prop, add_limit_note_source_prop} ) do
local reference = obs.obs_property_name( v )
obs.obs_property_list_clear( v );
obs.obs_property_list_add_string( v, "Select", "select" );
list = {} -- Reset / clear a defined table variable to be
used to build lists that will be passed to the property list
if tableHasValue( all_sources ) then
for _, sub in ipairs( all_sources ) do
local source_id = sub["unversioned_id"];
local source_nested = sub["nested"];
local name = sub["source_name"]
if source_id == text_source_unversioned_id or
source_id == "text_ft2_source" then -- identify text type sources only
if not source_selected( name, reference )
then
--[[
add it to list so that it can
be reordered
]]
list[name] = name;
else
--continue
end;
end;
if in_table( {"note_source_marker_a",
"note_source_marker_b"}, reference ) and in_table( { "group", "scene" },
source_id ) and source_nested then -- identify text type sources only
list[name] = name .. " [Group]";
end;
end;
[Link](sub); -- free memory, release source as it
is no longer needed
--[[
This property list will be a type of string
referenced items with a string value.
The string reference must be unique or it
will/may be overriden.
Being string referenced the list will be
compiled chronologically, thus the list
names (values) may appear unordered and
random. To reorganise and arrange the list
alphabetically we will use pairsByKeys(). This
will make it easier for the user to
review and select the desired item from the
list.
]]
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( v, value, key
);
end
end
end
end
--[[
Other fancy stuff
]]
if sec_add_limit > 1 then
obs.obs_property_int_set_suffix( sec_add_limit_prop, " Calls" );
end
if sec_add_limit == 1 then
obs.obs_property_int_set_suffix( sec_add_limit_prop, " Call" );
end
if sec_add_limit == 0 then
obs.obs_property_int_set_suffix( sec_add_limit_prop, " Zero allow
infinite calls" );
end
--[[
The folowing section will only update cycle_index
this is used to determine what the next item must be
]]
if timer_mode == 2 and source_type == "auto" and not in_table( ignore_list,
cycle_source_children ) then
local source_name = cycle_source_children
source_list = list_source_children_by_source_name( source_name )
if source_list ~= nil and tableHasValue( source_list ) and not
in_table( ignore_list, source_name ) then
set_visible( cycle_source_children, true );
cycle_index, source_list =
cycle_source_list_by_source_name( source_list, cycle_index );
end
end
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function timer_end_media_end_callback( )
if disable_script then return; end;
debug_log( 'timer_end_media_end_callback() -- function variable names: ' )
set_visible( media['source_name_audio_marker_end'], false );
timer_remove( timer_end_media_end_callback );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: Only used in Count Down mode
Credit:
Modified:
function:
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function timer_ended( source_name )
if disable_script then return; end;
debug_log( 'timer_ended(' .. pre_dump(source_name) .. ') -- function variable
names: source_name ' )
--[[
Timer expired and a scene change is requested.
]]
if timer_mode == 2 and not in_table( {"TIMER END TEXT", "Source List", "Scene
List", "Auto List", "Select"}, timer_expire_event ) then
--[[
The timer expired and the timer will not restart.
]]
set_visible( timer_source, false ); -- last thing, set visibility of
timer to hide because we are changing to another scene
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
]]
--[[
used to be fresh_start
set_to_default: true false
timer_active: true false
activated: true false
timer_expired: false true
update_timer_settings ---> set_time_text ---> timer_ended
---> update_timer_settings -- death loop
]]
update_timer_settings( true ); -- optional inputs:
set_to_default(bool), new_settings(obs_property_data/obs_userdata)
end
--[[
The timer expired and the timer will not restart.
]]
timer_expired = true;
timer_active = false;
end
timer_expire_event_cycle_source_list( source_type );
end
--[[
for now, only limit the timer end media playback
for these settings:
]]
if timer_mode == 2 and in_table( {"TIMER END TEXT", "Select"},
timer_expire_event ) then
--[[
--[[
Returns table with all sources, including nested scenes.
]]
local all_sources = get_source_list( "*" );
--[[
Option list: User select <text-source> to be used as visual feedback
indicating a time stamp.
This provides function options that will impact on visual feedback to
the user.
Changing this setting will impact on the function or end result.
]]
local p_4 = obs.obs_properties_add_list( [Link], "timer_source",
"<i>Timer Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_list_add_string( p_4, "Select", "select" ); -- Adds a
default option to the list. First (top-most) list item. If selected the option is
ignored.
local list = {}; -- Define a table variable to be used to build lists that
will be passed to the property list
if sources ~= nil then
for _, source in ipairs( sources ) do -- ipairs cycles auto incrimented
items
source_id = obs.obs_source_get_unversioned_id( source ); --
unversioned_id will not be affected by language settings
if source_id == text_source_unversioned_id then -- identify text
type sources only
local name = obs.obs_source_get_name( source ); -- Get the
source name, this will be a unique identifier
--[[
boolean check, is the source (name) already selected
for another item?
This will help to limit conflicts to prevent using a
single source for two sperate functions
]]
local reference = "timer_source";
if not source_selected( name, reference ) then -- boolean
check
--[[
add it to the (temp) table (list)
]]
list[name] = name;
else
-- continue to skip potential conflicts
end
end
end
[Link](source); -- free memory, release source as it is no
longer needed
--[[
This property list will be a type of string referenced items
with a string value.
The string reference must be unique or it will/may be overriden.
Being string referenced the list will be compiled
chronologically, thus the list
names (values) may appear unordered and random. To reorganise
and arrange the list
alphabetically we will use pairsByKeys(). This will make it
easier for the user to
review and select the desired item from the list.
]]
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_4, value, value ); -- add the
item to the property list using a string reference with a string value
end
end
--[[
Option list: User select a reference to be used as control to switch
the timer between countup and countdown.
This provides function options that will impact operation and
behaviour.
Changing this setting will impact on the function or end result.
--[[
Option list: User select to show or hide available features.
This provides UI layout options to enhance the user experience.
Changing this setting does not impact any function or result.
--[[
Option list: User select <option> to be used.
]]
local p_65_a = obs.obs_properties_add_list( [Link],
"timer_activation_source", "<i>Activation Source</i>", obs.OBS_COMBO_TYPE_LIST,
obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_list_add_string( p_65_a, "Select", "select" ); -- Adds a
default option to the list. First (top-most) list item. If selected the option is
ignored.
obs.obs_property_set_long_description( p_65_b, "\nSelect a trigger source
that activates the timer upon its visibility or display.\n" ); -- User Tip
--[[
Option list: User select to show or hide available features.
This provides UI layout options to enhance the user experience.
Changing this setting does not impact any function or result.
--[[
Text Field
--[[
Editable Option list: User adds a text time stamp that will trigger
time Marker functions.
This provides function options to change feature behaviour.
Changing this setting will impact on feature behaviour.
]]
local p_22 = obs.obs_properties_add_editable_list( [Link],
"text_arr_marker_b", "Marker B Time", obs.OBS_EDITABLE_LIST_TYPE_STRINGS, nil,
nil );
--*props, *name, *description, min, max, step
obs.obs_properties_add_int_slider( [Link], "reset_text_marker_a",
"Reset Marker A Text", 0, 10800, 1 );
obs.obs_properties_add_int_slider( [Link], "reset_text_marker_b",
"Reset Marker B Text", 0, 10800, 1 );
--[[
Option list: User select <media-source> to be used as audio visual at a
defined time.
This provides function options that will impact on audio visual
feedback to the user.
Changing this setting will impact on a function or end result.
]]
local p_23 = obs.obs_properties_add_list( [Link], "audio_marker_a",
"<font color=".. font_dimmed ..">Marker A Audio</font>", obs.OBS_COMBO_TYPE_LIST,
obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_set_long_description( p_23, "\nSelect available media source
to activate on defined time stamp.\n" ); -- User Tip
obs.obs_property_list_add_string( p_23, "None", "none" ); -- Add options to
the list
obs.obs_property_list_add_string( p_23, "Allow Multiple Selections",
"list" ); -- Add options to the list
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source ); --
unversioned_id will not be affected by language settings
if source_id == "ffmpeg_source" then -- identify media type
sources only
local name = obs.obs_source_get_name( source );
obs.obs_property_list_add_string( p_23, name, name );
end
end
[Link](source); -- free memory, release source as it is no
longer needed
end
--[[
]]
--[[
Option list: User select a reference to be used as control to enable an
auto start recording feature.
This provides function options to change a function behaviour.
Changing this setting will impact on features and operation.
--[[
Option list: User select a reference to be used as control to enable an
action que task once the timer expires.
This provides function options to change a function behaviour.
Changing this setting will impact on features and operation.
This property is referenced to trigger an onchange event listener.
]]
local p_37 = obs.obs_properties_add_list( [Link], "timer_expire_event",
"<i>Timer Expire Event</i>", obs.OBS_COMBO_TYPE_LIST,
obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_set_long_description( p_37, "\nDefine what happens afater
timer ends\n" ); -- User Tip
obs.obs_property_list_add_string( p_37, "Select", "select" ); -- Adds a
default options
obs.obs_property_list_add_string( p_37, "TIMER END TEXT", "TIMER END TEXT" );
-- Adds a default options
obs.obs_property_list_add_string( p_37, "--[ Select Lists ]--", "invalid" );
-- Adds a default option to the list. First (top-most) list item. If selected the
option is ignored.
t_type = {"Source List", "Scene List", "Auto List"}; -- Add options to the
list
--[[
Option list: User select <text-source> to be used as visual feedback
indicating a source name that is targeted.
This provides function options that will impact on visual feedback to
the user.
Changing this setting will impact on the function or end result.
]]
local p_33 = obs.obs_properties_add_list( [Link],
"cycle_source_children", "<i>Auto List</i>", obs.OBS_COMBO_TYPE_LIST,
obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_set_long_description( p_33, "\nSelect a source, that have
items (children) to be used in cycle list.\n" ); -- User Tip
obs.obs_property_list_add_string( p_33, "Select", "select" ); -- Adds a
default option to the list. First (top-most) list item. If selected the option is
ignored.
list = {} -- Reset / clear a defined table variable to be used to build lists
that will be passed to the property list
if tableHasValue( all_sources ) then
for _, sub in pairs( all_sources ) do
local source_id = sub["id"];
local source_nested = sub["nested"];
local name = sub["source_name"]
--[[
Text Field
]]
local p_38 = obs.obs_properties_add_text( [Link], "stop_text", "<font
color=#fef1eb>Timer Expired Text</font>", obs.OBS_TEXT_DEFAULT );
obs.obs_property_set_long_description( p_38, "\nDefine text displayed when
timer ended\n" ); -- User Tip
--[[
Editable Option list: User adds a text name as an entry used as a
reference to be used as inditification of a source.
This provides function options to change feature behaviour.
Changing this setting will impact on feature options and behaviour.
]]
local p_39 = obs.obs_properties_add_editable_list( [Link],
"cycle_list", "Cycle List", obs.OBS_EDITABLE_LIST_TYPE_STRINGS, nil, nil );
--[[
Option list: User select a reference to be used as control to determine
a cycling direction.
This provides function options to change feature behaviour.
Changing this setting will impact on feature options.
]]
local p_40 = obs.obs_properties_add_list( [Link], "cycle_direction",
"<i>Cycle Direction</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT );
t_type = {"Ascending", "Descending"}; -- Add options to the list
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_40, v, i )
end; -- This list is auto indexed thus have an interger reference containing a
string value
obs.obs_property_set_long_description( p_40, "\nSelect the rotation direction
of lists.\n" ); -- User Tip
--[[
Option list: User select to show or hide available features.
This provides UI layout options to enhance the user experience.
Changing this setting does not impact any function or result.
end;
local p_b7 = obs.obs_properties_add_int( group_props_2,
"add_limit_note_source_visible", "Note visible", 0, 36000, 1 );
obs.obs_property_int_set_suffix( p_b7, " milliseconds visible, 0 is
infinite" );
local p_a8 = obs.obs_properties_add_button( group_props_2, "sec_add_refresh",
"Refresh to update form", refresh_properties );
--[[
Wrap and group properties together.
Thise group provides options to the user to define a custom time value
used as a start point for a stopwatch to continue from
]]
local group_props_3 = obs.obs_properties_create();
obs.obs_properties_add_group( [Link], "_group_3", "Subtract Seconds
from time (Initiate with Hotkey)", obs.OBS_GROUP_NORMAL, group_props_3 );
-- obs_properties_t *props, const char *name, const char *description, int
min, int max, int step
local p_b1 = obs.obs_properties_add_int( group_props_3, "sec_sub_1", "Set 1",
5, 259200, 15 );
obs.obs_property_int_set_suffix( p_b1, " Seconds subtracted from time per
call" );
local p_b2 = obs.obs_properties_add_int( group_props_3, "sec_sub_2", "Set 2",
15, 259200, 15 );
obs.obs_property_int_set_suffix( p_b2, " Seconds subtracted from time per
call" );
local p_b3 = obs.obs_properties_add_int( group_props_3, "sec_sub_3", "Set 3",
30, 259200, 15 );
obs.obs_property_int_set_suffix( p_b3, " Seconds subtracted from time per
call" );
local p_b4 = obs.obs_properties_add_int( group_props_3, "sec_sub_limit",
"Limit", 0, 1000, 1 );
obs.obs_property_int_set_suffix( p_b4, " Zero allow infinite calls" );
local p_b5 = obs.obs_properties_add_int( group_props_3, "sec_sub_limit_used",
"Used", 0, 1000, 1 );
obs.obs_property_int_set_suffix( p_b5, " Refesh to update form" );
obs.obs_property_set_long_description( p_b5, "\nClick the refresh button the
update and show the used limits.\n" ); -- User Tip
local p_b6 = obs.obs_properties_add_list( group_props_3,
"sub_limit_note_source", "<i>Limit Note</i>", obs.OBS_COMBO_TYPE_LIST,
obs.OBS_COMBO_FORMAT_STRING );
obs.obs_property_set_long_description( p_b6, "\nSelect a text source, that
will be used to show a message when the limit was reached.\n" ); -- User Tip
obs.obs_property_list_add_string( p_b6, "Select", "select" ) -- Adds a
default option to the list. First (top-most) list item. If selected the option is
ignored.
list = {} -- Reset / clear a defined table variable to be used to build lists
that will be passed to the property list
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source ); --
unversioned_id will not be affected by language settings
if source_id == text_source_unversioned_id then -- identify text
type sources only
local name = obs.obs_source_get_name( source );
local reference = "sub_limit_note_source";
if not source_selected( name, reference ) then
--[[
add it to list so that it can be reordered
]]
list[name] = name;
else
--continue
end;
end;
end;
[Link](source); -- free memory, release source as it is no
longer needed
--[[
This property list will be a type of string referenced items
with a string value.
The string reference must be unique or it will/may be overriden.
Being string referenced the list will be compiled
chronologically, thus the list
names (values) may appear unordered and random. To reorganise
and arrange the list
alphabetically we will use pairsByKeys(). This will make it
easier for the user to
review and select the desired item from the list.
]]
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_b5, value, value ); -- Add
options to the list
end;
end;
local p_b7 = obs.obs_properties_add_int( group_props_3,
"sub_limit_note_source_visible", "Note visible", 0, 36000, 1 );
obs.obs_property_int_set_suffix( p_b7, " milliseconds visible, 0 is
infinite" );
--[[
Property Button: User interaction that will export all property
settings to a json file.
This provides function interaction to change feature behaviour.
Interacting with this property will complete a feature task.
]]
local p_60 = obs.obs_properties_add_button( [Link], "export_button",
"Export Settings", export_button_clicked );
--[[
SCRIPT READY
MUST BE HIDDEN
]]
local p_61 = obs.obs_properties_add_bool( [Link], "script_ready",
"Script Ready" );
obs.obs_property_set_visible( p_61 , set_visible_properties );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
obs.obs_properties_add_bool( [Link], "disable_script", "Disable
Script" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_63 = obs.obs_properties_add_bool( [Link], "select_features",
"Disable Featues" );
--[[
Wrap and group properties together.
Thise group provides options to the user to define a custom time value
used as a start point for a stopwatch to continue from
]]
local group_props_4 = obs.obs_properties_create();
local p_64 = obs.obs_properties_add_group( [Link], "_group_4", "Disable
or Enable Plugin Features - Check [x] = enabled", obs.OBS_GROUP_NORMAL,
group_props_4 );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_0 = obs.obs_properties_add_bool( group_props_4,
"enable_property_toggle_mili_trigger", "Split Seconds Toggle" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_1 = obs.obs_properties_add_bool( group_props_4,
"enable_property_split_source", "Timer Time Split/Lap" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_2 = obs.obs_properties_add_bool( group_props_4,
"enable_property_trigger_options", "Marker Settings" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_3 = obs.obs_properties_add_bool( group_props_4,
"enable_property_color_normal", "Text Colour [Normal]" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_4 = obs.obs_properties_add_bool( group_props_4,
"enable_property_color_marker_a", "Text Colour [Marker A]" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_5 = obs.obs_properties_add_bool( group_props_4,
"enable_property_color_marker_b", "Text Colour [Marker B]" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_6 = obs.obs_properties_add_bool( group_props_4,
"enable_property_start_recording", "Recording" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_7 = obs.obs_properties_add_bool( group_props_4,
"enable_property_text_prefix", "Timer Text Prefix" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_8 = obs.obs_properties_add_bool( group_props_4,
"enable_property_text_suffix", "Timer Text Suffix" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_9 = obs.obs_properties_add_bool( group_props_4,
"enable_property_timer_activation", "Timer Activation" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_10 = obs.obs_properties_add_bool( group_props_4,
"enable_property_timer_manipulation", "Timer Manipulation" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_11 = obs.obs_properties_add_bool( group_props_4,
"enable_property_debug", "Debugging" );
--[[
Property Checkbox: User interaction that will disable the plugin.
This provides function interaction to change feature behaviour.
Interacting with this property will impact on feature options and
behaviour.
]]
local p_64_12 = obs.obs_properties_add_bool( group_props_4,
"enable_property_backup", "Backup" );
]]--
obs.obs_property_set_modified_callback( p_ab, property_onchange );
-- timer_manipulation
obs.obs_property_set_modified_callback( p_a4, property_onchange );
-- sec_add_limit
obs.obs_property_set_modified_callback( p_b4, property_onchange );
-- sec_sub_limit
obs.obs_property_set_modified_callback( p_a6, property_onchange );
-- add_limit_note_source
obs.obs_property_set_modified_callback( p_b6, property_onchange );
-- sub_limit_note_source
obs.obs_property_set_modified_callback( p_1, property_onchange );
-- timer_mode
obs.obs_property_set_modified_callback( p_2, property_onchange );
-- layout
obs.obs_property_set_modified_callback( p_3, property_onchange );
-- timer_options
obs.obs_property_set_modified_callback( p_4, property_onchange );
-- timer_source
obs.obs_property_set_modified_callback( p_5, property_onchange );
-- countdown_type
obs.obs_property_set_modified_callback( p_8, property_onchange );
-- month
obs.obs_property_set_modified_callback( p_9, property_onchange );
-- year
obs.obs_property_set_modified_callback( p_11, property_onchange );
-- hours
obs.obs_property_set_modified_callback( p_12, property_onchange );
-- minutes
obs.obs_property_set_modified_callback( p_13, property_onchange );
-- seconds
obs.obs_property_set_modified_callback( p_14, property_onchange );
-- timer_format
obs.obs_property_set_modified_callback( p_15, property_onchange );
-- custom_time_format
obs.obs_property_set_modified_callback( p_16, property_onchange );
-- toggle_mili_trigger
obs.obs_property_set_modified_callback( p_18, property_onchange );
-- split_source
obs.obs_property_set_modified_callback( p_20, property_onchange );
-- text_arr_marker_a
obs.obs_property_set_modified_callback( p_21, property_onchange );
-- text_arr_marker_b
obs.obs_property_set_modified_callback( p_22, property_onchange );
-- trigger_options
obs.obs_property_set_modified_callback( p_23, property_onchange );
-- audio_marker_a
obs.obs_property_set_modified_callback( p_24, property_onchange );
-- audio_marker_b
obs.obs_property_set_modified_callback( p_26, property_onchange );
-- media_playback_limit
obs.obs_property_set_modified_callback( p_27, property_onchange );
-- enable_marker_notes
obs.obs_property_set_modified_callback( p_28, property_onchange );
-- note_source_marker_a
obs.obs_property_set_modified_callback( p_29, property_onchange );
-- note_source_marker_b
obs.obs_property_set_modified_callback( p_32, property_onchange );
-- start_recording
obs.obs_property_set_modified_callback( p_33, property_onchange );
-- cycle_source_children
obs.obs_property_set_modified_callback( p_36, property_onchange );
-- active_source
obs.obs_property_set_modified_callback( p_37, property_onchange );
-- timer_expire_event
obs.obs_property_set_modified_callback( p_52, property_onchange );
-- set_stopwatch
obs.obs_property_set_modified_callback( p_gp_6, property_onchange );
-- load_saved_time
obs.obs_property_set_modified_callback( p_55, property_onchange );
-- enable_direction_toggle
obs.obs_property_set_modified_callback( p_56, property_onchange );
-- backup_mode
obs.obs_property_set_modified_callback( p_57, property_onchange );
-- backup_folder
obs.obs_property_set_modified_callback( p_58, property_onchange );
-- import_list
obs.obs_property_set_modified_callback( p_59, import_properties );
-- import_button
obs.obs_property_set_modified_callback( p_62, property_onchange );
-- split_startpause
obs.obs_property_set_modified_callback( p_63, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_0, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_1, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_2, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_3, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_4, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_5, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_6, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_7, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_8, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_9, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_10, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_11, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_64_12, property_onchange );
-- select_features
obs.obs_property_set_modified_callback( p_65, property_onchange );
-- timer_activation
obs.obs_property_set_modified_callback( p_65_a, property_onchange );
-- timer_activation_source
obs.obs_property_set_modified_callback( p_65_b, property_onchange );
-- timer_reset
-- Calls the callback once to set-up current visibility
obs.obs_properties_apply_settings( [Link], [Link] );
return [Link];
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: We use this to keep track of what text type sources was
assigned/selected in properties
Credit:
Modified:
function: Called upon settings initialization and modification
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function update_source_list()
if disable_script then return; end;
debug_log( 'update_source_list() -- function variable names: ' )
selected_source_list["timer_source"] = timer_source;
selected_source_list["split_source"] = split_source;
selected_source_list["active_source"] = active_source;
selected_source_list["note_source_marker_a"] = note_source_marker_a;
selected_source_list["note_source_marker_b"] = note_source_marker_b;
selected_source_list["sub_limit_note_source"] = sub_limit_note_source;
selected_source_list["add_limit_note_source"] = add_limit_note_source;
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: We use this to keep track of what text type sources was
assigned/selected in properties
Credit:
Modified:
function: Called upon settings initialization and modification
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function source_selected( input_value, reference )
if disable_script then return; end;
debug_log( 'source_selected(' .. pre_dump(input_value) .. ", " ..
pre_dump(reference) .. ') -- function variable names: input_value, reference ' )
if in_table( {'Select, select'}, input_value ) or
selected_source_list[reference] == input_value then return false end;
return in_table( selected_source_list, input_value );
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
Description: A function named script_update will be called when settings
are changed
Credit:
Modified:
function: Called upon settings initialization and modification
type:
input type:
returns:
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function script_update( settings )
debug_log( 'script_update(' .. pre_dump(settings) .. ') -- function variable
names: settings ' )
--[[
something changed, remove all timers.
]]
remove_all_timers();
--[[
Update a gloabl in case something changed.
]]
count_required_sources();
--[[
Get the correct frequency for splitseconds when the script loads.
]]
assign_default_frequency();
--[[
load any property values available to globals
]]
load_settings_globals( settings ); -- load all property settings to globals
reset_mili( ); -- ensure mili hide/show settings are updated
Credit:
Modified:
function: Called when the script is started for the first time or
when the script settings
is set to default
type: settings
input type: Called when the Script is loaded thr first time or
returns: None
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function script_defaults( settings )
debug_log( 'script_defaults(' .. pre_dump(settings) .. ') -- function variable
names: settings ' )
--[[
Get the correct frequency for splitseconds when the script loads.
]]
assign_default_frequency();
--[[
Set property value by provided property reference.
Credit:
Modified:
function: Called when script is saved
type: OBS
input type: settings
returns: none
-----------------------------------------------------------------------------------
-----------------------------------------------------
]]
function script_save( settings )
debug_log( 'script_save(' .. pre_dump(settings) .. ') -- function variable
names: settings ' )
--[[
script save
Reset (Timer)
]]
local hotkey_save_array_reset = obs.obs_hotkey_save( hotkey_id_reset );
obs.obs_data_set_array( settings, "reset_hotkey", hotkey_save_array_reset );
obs.obs_data_array_release( hotkey_save_array_reset );
--[[
script save
Start Timer
]]
local hotkey_save_array_start = obs.obs_hotkey_save( hotkey_id_start );
obs.obs_data_set_array( settings, "start_hotkey", hotkey_save_array_start );
obs.obs_data_array_release( hotkey_save_array_start );
--[[
script save
script save
]]
local hotkey_save_array_mili = obs.obs_hotkey_save( hotkey_id_mili );
obs.obs_data_set_array( settings, "mili_hotkey", hotkey_save_array_mili );
obs.obs_data_array_release( hotkey_save_array_mili );
--[[
]]
local hotkey_save_array_direction =
obs.obs_hotkey_save( hotkey_id_direction );
obs.obs_data_set_array( settings, "direction_hotkey",
hotkey_save_array_direction );
obs.obs_data_array_release( hotkey_save_array_direction );
--[[
]]
local hotkey_save_array_sec_add_1 =
obs.obs_hotkey_save( hotkey_id_sec_add_1 );
obs.obs_data_set_array( settings, "sec_add_1_hotkey",
hotkey_save_array_sec_add_1 );
obs.obs_data_array_release( hotkey_save_array_sec_add_1 );
--[[
]]
local hotkey_save_array_sec_add_2 =
obs.obs_hotkey_save( hotkey_id_sec_add_2 );
obs.obs_data_set_array( settings, "sec_add_2_hotkey",
hotkey_save_array_sec_add_2 );
obs.obs_data_array_release( hotkey_save_array_sec_add_2 );
--[[
]]
local hotkey_save_array_sec_add_3 =
obs.obs_hotkey_save( hotkey_id_sec_add_3 );
obs.obs_data_set_array( settings, "sec_add_3_hotkey",
hotkey_save_array_sec_add_3 );
obs.obs_data_array_release( hotkey_save_array_sec_add_3 );
--[[
]]
local hotkey_save_array_sec_sub_1 =
obs.obs_hotkey_save( hotkey_id_sec_sub_1 );
obs.obs_data_set_array( settings, "sec_sub_1_hotkey",
hotkey_save_array_sec_sub_1 );
obs.obs_data_array_release( hotkey_save_array_sec_sub_1 );
--[[
]]
local hotkey_save_array_sec_sub_2 =
obs.obs_hotkey_save( hotkey_id_sec_sub_2 );
obs.obs_data_set_array( settings, "sec_sub_2_hotkey",
hotkey_save_array_sec_sub_2 );
obs.obs_data_array_release( hotkey_save_array_sec_sub_2 );
--[[
]]
local hotkey_save_array_sec_sub_3 =
obs.obs_hotkey_save( hotkey_id_sec_sub_3 );
obs.obs_data_set_array( settings, "sec_sub_3_hotkey",
hotkey_save_array_sec_sub_3 );
obs.obs_data_array_release( hotkey_save_array_sec_sub_3 );
--[[
It is really important that this the last item in this routine
]]
--obs.obs_properties_set_flags( [Link],
obs.obs_properties_get_flags( [Link] ) or obs.OBS_PROPERTIES_DEFER_UPDATE)
if load_saved_time then
obs.obs_data_set_double( [Link], "sw_current_seconds",
current_seconds );
obslua.obs_data_apply( settings, [Link] );
end
end
--[[
-----------------------------------------------------------------------------------
-----------------------------------------------------
--[[
Reset (Timer)
]]
hotkey_name = "timer_reset_" .. filename():lower():gsub("[%W%p%c%s]", "");
hotkey_id_reset = obs.obs_hotkey_register_frontend( hotkey_name, "Reset " ..
filename(), hotkey_send_reset );
local hotkey_save_array_reset = obs.obs_data_get_array( settings,
"reset_hotkey" );
obs.obs_hotkey_load( hotkey_id_reset, hotkey_save_array_reset );
obs.obs_data_array_release( hotkey_save_array_reset );
--[[
script is loading. register and assign hotkeys
--[[
Define Hotkeys
]]
assign_hotkeys( settings, true )
--[[
If the user is not loading saved time, clear it
]]
end
--[[
--------------------------------------------------------------------
custom function