Skip to content
Permalink
main
Switch branches/tags
Go to file
1 contributor

Users who have contributed to this file

--[[
----------------------------------------------------------
Open Broadcaster Software®️
OBS > Tools > Scripts
@midnight-studios
Stopwatch
----------------------------------------------------------
]]
--Globals
obs = obslua
gversion = "3.4"
luafile = "StopWatch.lua"
obsurl = "simple-stopwatch.1364/"
icon="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAENElEQVQ4jY1UTUgjZxh+ksl/JuMkMYb4F40bNZqK0KJFqBZqS9ddyl76dyhdKPRQShH2sNDSnnopCz11D10KS/dSKNiDoD2I7KXFQ0XSSGpM1llFMYn5mZiMY2IymfIOhgazXfaDj5n53u975vme531fnaqqeMHxJYCvAOgAlABcAyA1jxLO1tYW1tbWoL+Kd3x8jGg0imw2C0VRWkMEYgNgBeAFYKTFRqOh7aVnE9xwFTSZTGJ7exszMzPQ6XSQZRk8z9P7YrVa/Y5hmKLBYHCpqirW63Wcn5/j7OwMHo9HA6bvNqY2mw1Op1N70qaTkxPkcjmbLMsDZrN5hOO4NxuNhlMUxTFiSCA0FEW5GQ6H/wmHwzfamDavUKlUYDKZAoFA4Gue52/r9f/9v6OjQ5uKojwpFAr3RFF8UCwWjW63OzQ/P/9yGyiBnZ6eEtN3eZ7/9XJZrlQqP2cymcf5fL4QDAbHdTrd2yzLXvd4PD9yHHdLEISFXC7nsdvtuTb3c7kcEokEJiYmhliWtaiqWs5ms4f1el0lE2lOTU0hn8/DYrF09vb23jebze9JkvRXNBqdMpvNaIJaLh1tHScAzpvsSd+joyOkUimEQiFNa4vFAlEU4Xa7HwYCgduFQuHRxsbGx5p+qqq+o/7/SF7uQSaTwcHBgZYdgiBMqKqa2dnZ8S8tLaFcLicIIR6PjzU13Qew+gzPKNEj9JJOp5tag+O41/v7+x/v7u7+sLOzc8BxHN1icXR0dMXlcn3xQhW1v7+PSCSC6enptxwOx3WWZRcbjcbTjY2NAJ1nWRYGgwHj4+OqoigFYnr/UlPlClYFwJ1arVYjU8bGxhZ8Pt9KMxiLxd5gGEbTlTSv1WqQJOmJw+G4RqCfPYfkN4qiFDs7O9HT0/Nqa4BhmKd2u10DrFaruLi4oJmncibQSUCrLHJabDlHzItGo1E7FIvFvg+FQjMmkykkCMK9eDwOivl8PvqhBspxXJAOEujfz2HazzBMdXh4OJNMJoupVGre7/cbBEGor6+vY2RkROsLlwY6jUajS5KkSGvtf0oVemUeAPiDgsFgUHMeQJ3MmZycxNzcnMZWkiT4/f67FJRl+UFrmcYB/N7y3UyLSHOBzNjb20MgEMDg4CC6urqwublJZo12d3ffVRRFEQTh4TNTqlQqaawoTShOVdOsqMPDQ8zOzmqFQK3PZrO91NPTs2U0GkmWG4lEYrWt9cViMSwvL1Ntvw9gRafT/aTX6z8AwFKcuhU5zjDMkNfr/XZgYCBKgMfHx3eSyeSqw+Fob9LEipxMp9MRp9P5uclkWuB5/hOKWa3Wvb6+vjLP8wNer5fXUkRRLkql0ofZbPY3ug019TZQ6jKU0AzD7Iqi+Josy6+4XK6P7Hb7LbvdPkS5SXpXKpU/ZVn+5ezs7FG9Xi9brVZNLr1ej38BVDs6EbSfFQsAAAAASUVORK5CYII="
desc = [[
<hr/><center><h2>Advanced Stopwatch</h2>( Version: %s )</center>
<br><center><img width=38 height=42 src=']] .. icon .. [['/></center>
<br><center><a href="https://github.com/midnight-studios/obs-lua/blob/main/]] .. luafile ..[[">Find it on GitHub</a></center>
<br><p>The Properties for this script will adjust visibility as needed. Some advanced properties will only be visible if the Configuration is set to "Advanced". If the Configuration is set to "Basic" the defined values will still be used, so ensure you define those correctly.</p><p>Find help on the <a href="https://obsproject.com/forum/resources/]] .. obsurl ..[[">OBS Forum Thread</a>.</p><hr/>]]
last_text = ""
custom_time_format = ""
font_normal = "#ffffff"
font_dimmed = "#bfbbbf"
timer_source = ""
countdown_type = ""
backup_folder = ""
import_list = ""
output_file_name = "-backup($date_stamp).json";
longtimetext_s = ""
longtimetext_p = ""
last_split_data = ""
split_type = ""
split_source = ""
active_source = ""
next_scene = ""
stop_text = ""
cur_seconds = 0
def_seconds = 0
split = 0
timer_year = 0
timer_month = 0
timer_day = 0
timer_hours = 0
timer_minutes = 0
timer_seconds = 0
timer_type = 0
start_recording = 0
recording_type = 0
trigger_text = 1
orig_time = 0
time_frequency = 0
completed_cycles = 0
ns_last = 0
cycle_index = 0
timer_cycle = 10 --milliseconds
split_itm = {}
split_data = nil
script_settings = nil
props = nil
activated = false
timer_active = false
reset_activated = false
start_on_visible = false
disable_script = false
media = {
warning_text = "",
caution_text = "",
source_name_audio_warning = "",
source_name_audio_caution = "",
caution_note_source = "",
warning_note_source = "",
caution_note = "",
warning_note = "",
warning_activated = false,
caution_activated = false,
cur_seconds_caution = 0,
cur_seconds_warning = 0,
caution_duration = 0,
warning_duration = 0,
normal_color = 0xFFFFFFFF,
caution_color = 0x40f3ed,
warning_color = 0x05055a,
last_state_caution = obs.OBS_MEDIA_STATE_NONE,
last_state_warning = obs.OBS_MEDIA_STATE_NONE
}
hotkey_id_reset = obs.OBS_INVALID_HOTKEY_ID
hotkey_id_pause = obs.OBS_INVALID_HOTKEY_ID
hotkey_id_split = obs.OBS_INVALID_HOTKEY_ID
--[[
----------------------------------------------------------
-- Use this to create a Script Log Output used in testing
----------------------------------------------------------
]]
function log( name, msg )
if msg ~= nil then
msg = " > " .. tostring( msg )
else
msg = ""
end
obs.script_log( obs.LOG_DEBUG, name .. msg )
end
--[[
----------------------------------------------------------
-- Get the name of this script
----------------------------------------------------------
]]
function filename()
local str = debug.getinfo(2).source:sub(2)
return str:match("^.*/(.*).lua$") or str
end
--[[
----------------------------------------------------------
A function named script_description returns the description shown to
the user
----------------------------------------------------------
]]
function script_description()
return string.format( desc, tostring( gversion ) )
end
--[[
----------------------------------------------------------
--
----------------------------------------------------------
]]
function get_filenames( path )
local filenames = {}
local dir = obs.os_opendir( path )
local entry
repeat
entry = obs.os_readdir(dir)
if entry then
local ext = obs.os_get_path_extension( entry.d_name )
if ext == ".json" then
local filename = string.gsub( entry.d_name, ext, "" )
table.insert( filenames, filename )
end
end
until not entry
obs.os_closedir( dir )
return filenames
end
--[[
----------------------------------------------------------
--
----------------------------------------------------------
]]
function write_to_json( data )
output_folder = backup_folder
-- convert Windows path to UNIX path
local file_name = filename() .. output_file_name:gsub("$date_stamp", os.date("%Y-%m-%d-%H%M"))
-- 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
--[[
----------------------------------------------------------
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
----------------------------------------------------------
]]
function assign_default_frequency()
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 )
end
--[[
----------------------------------------------------------
Used this in testing to measure accuracy
The Text Source and the Log should produce the same value
The Text source is updated by the time function while the debug
uses start and end time stamps to get a value
----------------------------------------------------------
]]
function get_time_lapsed()
local ns = obs.os_gettime_ns()
local delta = ( ns/1000000000.0 ) - ( orig_time/1000000000.0 )
return TimeFormat( delta )
end
--[[
----------------------------------------------------------
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.
----------------------------------------------------------
]]
function get_frequency( 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
return f
end
--[[
----------------------------------------------------------
Convert Seconds to hours:minutes:seconds:miliseconds
----------------------------------------------------------
]]
function delta_time(year, month, day, hour, minute, second)
local now = os.time()
if (year == -1) then
year = os.date("%Y", now)
end
if (month == -1) then
month = os.date("%m", now)
end
if (day == -1) then
day = os.date("%d", now)
end
local future = os.time{year=year, month=month, day=day, hour=hour, min=minute, sec=second}
local seconds = os.difftime(future, now)
if (seconds < 0) then
seconds = 0
end
return seconds
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function trim_time( hour, minutes, seconds, mili, trim )
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 = string.format( format_hour..format_minutes..format_seconds..format_mili, hour, minutes, seconds, mili )
if trim then
return time
end
if hour == 0 then
time = string.format( "%02d:%02d"..format_mili, minutes, seconds, mili )
end
if hour == 0 and minutes == 0 then
time = string.format( "%02d"..format_mili, seconds, mili )
end
if hour == 0 and minutes == 0 and seconds == 0 then
format_mili = ( mili and "%02d" or "" )
time = string.format( format_mili, mili )
end
return trim_zero( time )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function trim_zero( int )
while true do
if int:sub( 1,1 ) == '0' then
int = int:sub( 2 )
else
break
end
end
return int
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function wait( ms )
if ms ~= nil then
local start = math.floor( ( obs.os_gettime_ns()/1000000 ) )
repeat until ( math.floor( ( obs.os_gettime_ns()/1000000 ) )-start ) >= ms
end
end
--[[
----------------------------------------------------------
"Timer Expires" = 1
"Caution Time" = 2
"Warning Time" = 3
"Timer Visible" = 4
"Timer Start" = 5
----------------------------------------------------------
]]
function record( mark, ms )
if timer_type ~= 2 then return end
if start_recording == 1 and mark == recording_type then
obs.obs_frontend_recording_start()
end
if ms ~= nil then wait( ms ) end
end
--[[
----------------------------------------------------------
Only used in Countdown mode
----------------------------------------------------------
]]
function timer_ended( source_name )
delayed_recording()
if next_scene == "" or next_scene == "Select" then
return
end
if next_scene ~= "TIMER END TEXT" and next_scene ~= "Source List" and next_scene ~= "Scene List" then
set_visible( timer_source, false ) -- last thing, set visibility of timer to hide
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
]]
local source = obs.obs_get_source_by_name( next_scene )
obs.obs_frontend_set_current_scene( source )
obs.obs_source_release( source )
fresh_start( true )
--obs.remove_current_callback()
end
if next_scene == "Source List" then
reset( true )
cycle_list_activate( 'source' )
on_pause( true )
end
if next_scene == "Scene List" then
reset( true )
cycle_list_activate( 'scene' )
on_pause( true )
end
if next_scene == "TIMER END TEXT" then
local text = stop_text
set_text( source_name, text )
end
end
--[[
----------------------------------------------------------
Function
----------------------------------------------------------
]]
function cycle_list_activate( source_type )
local list = {}
if source_type ~= "source" then
local scenes = obs.obs_frontend_get_scene_names( )
if scenes ~= nil then
for _, scene in pairs( scenes ) do
if name ~= scene then
list[scene] = scene
end
end
obs.bfree( scene )
end
else
list = {}
local sources = obs.obs_enum_sources()
if sources ~= nil then
for _, source in pairs( sources ) do
local name = obs.obs_source_get_name( source )
list[name] = name
end
end
obs.source_list_release( sources )
end
cycle_list = obs.obs_data_get_array( script_settings, "cycle_list" )
local count = obs.obs_data_array_count(cycle_list) - 1;
for i = 0, count do
local item = obs.obs_data_array_item(cycle_list, cycle_index);
local value = obs.obs_data_get_string(item, "value");
cycle_index = cycle_index + 1
if cycle_index > count then
cycle_index = 0
end
if list[value] ~= nil then
if source_type ~= "source" then
local scene_source = obs.obs_frontend_get_current_scene()
local name = obs.obs_source_get_name( scene_source )
obs.obs_source_release( scene_source )
if name == list[value] then
-- goto next
else
local source = obs.obs_get_source_by_name( list[value] )
if source ~= nil then
obs.obs_frontend_set_current_scene( source )
end
obs.obs_source_release( source )
set_text( active_source, list[value] )
break
end
else
if is_visible(list[value]) then
-- goto next
else
set_visible( list[value], true )
set_text( active_source, list[value] )
break
end
end
end
end
obs.obs_data_array_release(cycle_list)
end
--[[
----------------------------------------------------------
Convert Seconds to hours:minutes:seconds:miliseconds
----------------------------------------------------------
]]
function TimeFormat( time, notrim )
if time == nil then
return
end
local trim = ( timer_trim == 1 )
local hour, minutes, seconds, mili = 0, 0, 0, 0
--[[
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 = ( math.floor( (time ) / 86400 ) * 86400 )
time = time - c_time
end
hour = math.floor( time/3600 )
if hour < 10 and trim then
hour = "0"..hour
end
minutes = math.floor( ( time - math.floor( time/3600 )*3600 )/60 )
if minutes < 10 and trim then
minutes = "0"..minutes
end
seconds = math.floor( time - math.floor( time/3600 )*3600 - math.floor( ( time - math.floor( time/3600 )*3600 )/60 )*60 )
if seconds < 10 and trim then
seconds = "0"..seconds
end
mili = math.floor( ( time - math.floor( time/3600 )*3600 - math.floor( ( time - math.floor( time/3600 )*3600 )/60 )*60 - math.floor( time - math.floor( time/3600 )*3600 - math.floor( ( time - math.floor( time/3600 )*3600 )/60 )*60 ) )*100 )
if mili < 10 and trim then
mili = "0"..mili
end
if notrim or ( timer_trim == 4 ) then
return trim_time( hour, minutes, seconds, nil, true )
end
if ( timer_trim == 5 ) then
return trim_time( hour, minutes, seconds, mili, true )
end
return trim_time( hour, minutes, seconds, ( ( timer_trim ~= 3 ) and mili or nil ), trim )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function LongTimeFormat( 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 = math.floor( ( time ) / 86400)
end
if time < 86400 then
c_time = 0
end
return c_time
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function explode(str,delim)
local t, ll
t={}
ll=0
if(#str == 1) then
return {str}
end
while true do
l = string.find(str, delim, ll, true) -- find the next d in the string
if l ~= nil then -- if "not not" found then..
table.insert(t, string.sub(str,ll,l-1)) -- Save it in our array.
ll = l + 1 -- save just after where we found it for searching next time.
else
table.insert(t, string.sub(str,ll)) -- Save what's left in our array.
break -- Break at end, as it should be, according to the lua manual.
end
end
return t
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function format_time_stamp( timestamp, format )
local table1 = explode( timestamp, ':' )
if table1 == nil then return timestamp end
local c = tablelength( table1 )
local _, d = timestamp:gsub(":","")
local _, t = format:gsub("$T","")
local day, hour, minute, seconds, mili = 0, 0, 0, 0, 0
if d == 3 then
if tableHasKey( table1, 1 ) then
day = table1[1]
end
if tableHasKey( table1, 2 ) then
hour = table1[2]
end
if tableHasKey( table1, 3 ) then
minute = table1[3]
end
if tableHasKey( table1, 4 ) then
seconds = table1[4]
local table2 = explode( table1[4], ',' )
if tableHasKey( table2, 1 ) and tableHasKey( table2, 2 ) then
seconds = table2[1]
mili = table2[2]
end
end
end
if d == 2 then
if tableHasKey( table1, 1 ) then
hour = table1[1]
end
if tableHasKey( table1, 2 ) then
minute = table1[2]
end
if tableHasKey( table1, 3 ) then
seconds = table1[3]
local table2 = explode( table1[3], ',' )
if tableHasKey( table2, 1 ) and tableHasKey( table2, 2 ) then
seconds = table2[1]
mili = table2[2]
end
end
end
if d == 1 then
if tableHasKey( table1, 1 ) then
minute = table1[1]
end
if tableHasKey( table1, 2 ) then
seconds = table1[2]
local table2 = explode( table1[2], ',' )
if tableHasKey( table2, 1 ) and tableHasKey( table2, 2 ) then
seconds = table2[1]
mili = table2[2]
end
end
end
if tonumber(day) < 10 then
day = "0"..day
end
timestamp = format:gsub("$T", ""):gsub("$D", day):gsub( "$H", hour):gsub("$M", minute):gsub("$S", seconds):gsub("$F", mili)
if t ~= 0 and cur_seconds > 0.01 then
--local reg = '^[0]+[:]?[0]+[:]?[0]+[:]?[0]?'
local reg = "^[0:,]*" -- close, but misses 1 instance
timestamp = timestamp:gsub(reg,"")
end
if cur_seconds < 0.01 then -- else it will show 00:00:00
timestamp = ""
end
return timestamp
end
--[[
----------------------------------------------------------
Function to set the time text
----------------------------------------------------------
]]
function set_time_text( source_name )
if reset_activated then
reset_activated = false
fresh_start( true )
end
if cur_seconds <= 0.01 and timer_type ~= 1 then cur_seconds = 0 end
local text = tostring( TimeFormat( cur_seconds ) )
if timer_trim ~= 5 then
--[[
Format the Text 'Day/Days'
]]
if timer_type == 2 and countdown_type == 1 and cur_seconds ~= 0 then
local longtimetext = longtimetext_p
if math.floor( cur_seconds / 86400 ) <= 1 then
longtimetext = longtimetext_s
end
if math.floor( cur_seconds / 86400 ) <= 0 then
longtimetext = longtimetext_p
end
text = string.gsub(longtimetext .. text, "[#]", LongTimeFormat( cur_seconds ))
end
else
local l_time = LongTimeFormat( cur_seconds )
local t_time = TimeFormat( cur_seconds )
text = format_time_stamp( ( l_time ~= 0 ) and string.format("%s:%s", l_time, t_time ) or string.format("%s", t_time ), custom_time_format )
end
if timer_type ~= 2 then
--text_prefix = ""
-- text_suffix = ""
end
text = text_prefix .. text .. text_suffix
if text ~= last_text then
--[[
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 )
if not media['caution_activated'] and not media['warning_activated'] then
obs.obs_data_set_int( settings, "color", media['normal_color'] )
end
media_activate( settings, 'caution' )
media_activate( settings, 'warning' )
end
obs.obs_source_update( source, settings )
obs.obs_data_release( settings )
obs.obs_source_release( source )
end
stop_media( 'caution' )
stop_media( 'warning' )
last_text = text
if cur_seconds <= 0.01 and timer_type ~= 1 then
activate( false, true )
--[[
Timer Ended
]]--
if trigger_text ~= 1 then
set_visible( media["caution_note_source"], false )
set_visible( media["warning_note_source"], false )
end
timer_ended( source_name )
end
end
--[[
----------------------------------------------------------
Function to set the split time text
----------------------------------------------------------
]]
function set_split_text( source_name )
if source_name == 'Select' then
return
end
if reset_activated then
reset_activated = false
fresh_start( true )
end
local text = split_data
if text ~= last_split_data then
set_text( source_name, text )
end
last_split_data = text
end
--[[
----------------------------------------------------------
Function to set the source text
----------------------------------------------------------
]]
function set_text( source_name, text )
if source_name == 'Select' or source_name == 'select'then
return
end
--[[
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
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function set_text_note_color( ref )
if media[ref .. "_note_source"] == 'Select' then return end
local source = obs.obs_get_source_by_name( media[ref .. "_note_source"] )
if source ~= nil then
local settings = obs.obs_source_get_settings( source )
obs.obs_data_set_string( settings, "text", media[ref..'_note'] )
obs.obs_data_set_int( settings, "color", media[ref..'_color'] )
end
obs.obs_source_update( source, settings )
obs.obs_data_release( settings )
obs.obs_source_release( source )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function media_activate( settings, ref )
if TimeFormat( cur_seconds, true ) == media[ref..'_text'] then
if trigger_text ~= 1 and ref == 'caution' then
set_visible( media[ref .. "_note_source"], true )
set_visible( media["warning_note_source"], false )
set_text_note_color( ref )
end
if trigger_text ~= 1 and ref == 'warning' then
set_visible( media[ref .. "_note_source"], true )
set_visible( media["caution_note_source"], false )
set_text_note_color( ref )
end
obs.obs_data_set_int( settings, "color", media[ref..'_color'] )
media['cur_seconds_'..ref] = cur_seconds
media[ref..'_activated'] = true
start_media( media['source_name_audio_'..ref], ref )
if ref == 'caution' then record( 2 ) end
if ref == 'warning' then record( 3 ) end
end
return settings
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function start_media( source_name, ref )
start_media_action( source_name, ref )
end
--[[
----------------------------------------------------------
Set source visble = true
----------------------------------------------------------
]]
function start_media_action( source_name, ref )
if source_name == nil or source_name == "None" then
return
end
if media[ref..'_activated'] then set_visible( source_name, true ) end
end
--[[
----------------------------------------------------------
Stop Media is designed to reset the Source to the
starting state. In other words, make the source
invisible again. This sould only happen if the media
ended, or if it is looped, end the media after a
defined time.
----------------------------------------------------------
]]
function stop_media( ref, bypass )
if bypass then -- No checks, just stop it
set_visible( media['source_name_audio_'..ref], false )
else -- do some checks
stop_media_action( ref )
end
end
--[[
----------------------------------------------------------
Check if the source state changed,
if so, set source visble = false
----------------------------------------------------------
]]
function stop_media_action( ref )
local source_name = media['source_name_audio_'..ref]
if source_name == nil or source_name == "None" then
return
end
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
we got a source name, let's see if it exist...
]]
local source = obs.obs_get_source_by_name( source_name )
if source ~= nil then -- source is valid
local state = obs.obs_source_media_get_state( source ) -- get the current state for the source
if media['last_state_'..ref] ~= state then -- The state has changed
if get_source_looping( source_name ) then
--log( 'is looped', source_name )
if state == obs.OBS_MEDIA_STATE_PLAYING then
-- The source is looping, it will never stop
if source_name == media['source_name_audio_'..ref] then
local time_remaining = math.floor( media['cur_seconds_'..ref] ) + math.floor( media[ref..'_duration'] ) - math.floor( cur_seconds )
local time_end = ( time_remaining <= 0 )
if time_end then
media['last_state_'..ref] = state
set_visible( source_name, false )
end
end
end
else
--log( 'not looped', source_name )
media['last_state_'..ref] = state
if state == obs.OBS_MEDIA_STATE_STOPPED or state == obs.OBS_MEDIA_STATE_ENDED then
set_visible( source_name, false )
end
end
end
end
obs.obs_source_release( source )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function get_source_looping( source_name )
local property = "looping"
--[[
Increments the source reference counter,
use obs_source_release() to release it when complete.
we got a source name, let's see if it exist...
]]
local source = obs.obs_get_source_by_name( source_name )
local enabled = false
if source ~= nil then
local source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "ffmpeg_source" then
local s = obs.obs_source_get_settings( source )
--local prop = obs.obs_data_get_string( s, property )
enabled = obs.obs_data_get_bool( s, property )
obs.obs_data_release( s )
end
end
obs.obs_source_release( source )
return enabled
end
--[[
----------------------------------------------------------
set source visibility
----------------------------------------------------------
]]
function set_visible( target_name, visible )
if in_table( {'','none', 'select'}, target_name ) then return end
local scenes = obs.obs_frontend_get_scenes()
if scenes ~= nil then
for i, scn in ipairs( scenes ) do
local scene = obs.obs_scene_from_source( scn )
local sceneitem = obs.obs_scene_find_source_recursive( scene, target_name )
if sceneitem ~= nil then
obs.obs_sceneitem_set_visible( sceneitem, visible )
break
end
end --end for
obs.bfree( scn )
obs.source_list_release( scenes )
end
end
--[[
----------------------------------------------------------
check source visibility
----------------------------------------------------------
]]
function is_visible( target_name )
local isvisible = false
local scenes = obs.obs_frontend_get_scenes()
if scenes ~= nil then
for i, scn in ipairs( scenes ) do
local scene = obs.obs_scene_from_source( scn )
local sceneitem = obs.obs_scene_find_source_recursive( scene, target_name )
if sceneitem ~= nil then
isvisible = obs.obs_sceneitem_visible( sceneitem )
break
end
end --end for
obs.bfree( scn )
obs.source_list_release( scenes )
end
return isvisible
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function delayed_recording()
obs.timer_add( recording_callback, 100 ) --<- milliseconds
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function recording_callback()
obs.timer_remove( recording_callback )
record( 1 )
end
--[[
----------------------------------------------------------
Add timer here so we have a global setting
----------------------------------------------------------
]]
function start_timer()
record( 5, 100 ) -- wait 100 miliseconds
timer_active = true
fresh_start( false )
obs.timer_add( timer_callback, timer_cycle ) --<- milliseconds
end
--[[
----------------------------------------------------------
Add timer here so we have a global setting
----------------------------------------------------------
]]
function timer_callback()
time_frequency = get_frequency( ns_last )
calculate()
completed_cycles = completed_cycles + 1
set_time_text( timer_source )
--log( 'Applied frequency', time_frequency )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function calculate()
if timer_type ~= 2 then
cur_seconds = cur_seconds + time_frequency
else
cur_seconds = cur_seconds - time_frequency
end
end
--[[
----------------------------------------------------------
Called if the counter is starting fresh
----------------------------------------------------------
]]
function fresh_start( reset_curent )
if timer_type == 2 and countdown_type == 1 then
cur_seconds = delta_time( timer_year, timer_month, timer_day, timer_hours, timer_minutes, timer_seconds)
def_seconds = cur_seconds
end
if reset_curent ~= nil then
if reset_curent then
cur_seconds = def_seconds
completed_cycles = 0
split = 0
split_itm = {}
split_data = nil
media['caution_activated'] = false
media['warning_activated'] = false
end
end
orig_time = obs.os_gettime_ns()
set_visible( media["caution_note_source"], false )
set_visible( media["warning_note_source"], false )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function timer_caution_media_end_callback()
set_visible( media['source_name_audio_caution'], false )
obs.remove_current_callback()
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function timer_warning_media_end_callback()
set_visible( media['source_name_audio_warning'], false )
obs.remove_current_callback()
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function disconnect_after_media_end( ref )
local source_name = media['source_name_audio_'..ref]
source = obs.obs_get_source_by_name( source_name ) -- Increments the source reference counter, use obs_source_release() to release it when complete. --[[
--[[
Found Source:
]]
if source ~= nil then
local state = obs.obs_source_media_get_state( source ) -- get the current state for the source
if get_source_looping( source_name ) then -- The source is looping, it will never stop
if ref == "caution" then
obs.timer_add( timer_caution_media_end_callback, math.floor( media[ref..'_duration'] * 1000 ) ) --<- milliseconds
end
if ref == "warning" then
obs.timer_add( timer_warning_media_end_callback, math.floor( media[ref..'_duration'] * 1000 ) ) --<- milliseconds
end
else
--[[
Create a signal handler for the source
]]
local sh = obs.obs_source_get_signal_handler( source )
--[[
https://obsproject.com/docs/reference-sources.html?highlight=media_started
attach event listener callback [source_signal]: Called when media has ended.
]]
obs.signal_handler_connect( sh, "media_ended", signal_media_ended )
end
end
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function signal_media_ended( cd )
--[[
Get source from CallData
]]
local source = obs.calldata_source( cd, "source" )
--[[
Found Source:
]]
if source ~= nil then
local name = obs.obs_source_get_name( source )
set_visible( name, false )
obs.remove_current_callback()
end
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function activate( activating, timer_expired )
if disable_script then
return
end
activated = activating
if activating then
--obs.obs_frontend_recording_start()
start_timer()
else
if timer_expired then
obs.timer_remove( timer_callback )
disconnect_after_media_end( 'caution' )
disconnect_after_media_end( 'warning' )
else
timer_active = false
obs.timer_remove( timer_callback )
stop_media( 'caution',true )
stop_media( 'warning',true )
end
end
end
--[[
----------------------------------------------------------
Called when a source is activated/deactivated
----------------------------------------------------------
]]
function activate_signal( cd, activating )
local source = obs.calldata_source( cd, "source" )
if source ~= nil then
local name = obs.obs_source_get_name( source )
if ( name == timer_source ) then
if activating then record( 4, 300 ) end
if start_on_visible then
fresh_start( true )
activate( activating )
end
end
end
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function source_activated( cd )
if disable_script then
return
end
activate_signal( cd, true )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function source_deactivated( cd )
activate_signal( cd, false )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function reset( pressed )
if not pressed then
return
end
reset_activated = true
set_time_text( timer_source )
activate( false )
set_split_text( split_source )
set_text( active_source, "" )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function reset_button_clicked( props, p )
reset( true )
return false
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function pause_button_clicked( props, p )
on_pause( true )
return false
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function on_pause( pressed )
if not pressed then
return
end
set_visible( timer_source, true )
if timer_active then
timer_active = false
activate( false )
split_unpack()
set_split_text( split_source )
--log( 'OBS Video Frame Time', obs.obs_get_video_frame_time() )
--log( completed_cycles..' Cycles', get_time_lapsed() )
else
if activated == false then
activate( true )
end
end
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function split_button_clicked( props, p )
on_split( true )
return false
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function export_button_clicked( props, p )
print("export_button_clicked")
on_export( true )
return false
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function on_export( pressed )
if not pressed then
return
end
local file_exported = write_to_json( script_settings )
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function import_button_clicked( props, p, settings )
return false
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function import_properties( props, property, settings )
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')
script_settings = settings
end
end
return true
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function on_split( pressed )
if not pressed then
return
end
if timer_active then
split = split + 1
split_itm[split] = cur_seconds
split_unpack()
set_split_text( split_source )
end
end
--[[
----------------------------------------------------------
This captures the split times and unpack it in the
correct format.
The text source only permits linebreaks ( '\n' ) this
limitation affects how the data can be formated ):
----------------------------------------------------------
]]
function split_unpack()
local data = nil
local c = table.getn( 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
if split_type == 'Interval' then
title = 'Interval'
--subtitle = ''
text = tostring( TimeFormat( interval ) )
elseif split_type == 'Mark' then
title = 'Mark'
--subtitle = ''
text = tostring( TimeFormat( mark ) )
elseif split_type == 'Mark Interval' then
title = 'Mark '
subtitle = 'Interval'
text = tostring( TimeFormat( mark )..' '..TimeFormat( interval ) )
else -- "Interval Mark"
title = 'Interval '
subtitle = 'Mark'
text = tostring( TimeFormat( interval )..' '..TimeFormat( 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
--[[
--------------------------------------------------------------------
--------------------------------------------------------------------
]]
function pairsByKeys( t, f )
local a = {}
for n in pairs( t ) do table.insert( a, n ) end
table.sort( a, f )
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then return nil
else return a[i], t[a[i]]
end
end
return iter
end
--[[
--------------------------------------------------------------------
custom function: helper
----------------------------------------------------------
]]
function tableHasKey(table,key)
return table[key] ~= nil
end
--[[
--------------------------------------------------------------------
custom function: helper
----------------------------------------------------------
]]
function in_table( tbl, value )
local found = false
for k, v in pairs( tbl ) do
if value == v then
found = true
break
end
end
return found
end
--[[
----------------------------------------------------------
----------------------------------------------------------
]]
function is_leap_year( year )
if year % 4 == 0 then
if year % 100 == 0 then
if year % 400 == 0 then
return true
else
return false
end
else
return true
end
else
return false
end
end
--[[
----------------------------------------------------------
Callback on list modification
----------------------------------------------------------
]]
function property_onchange( props, property, settings )
local filenames = get_filenames( backup_folder )
local has_file_list = (table.getn( filenames ) > 0)
-- Retrieves value selected in list
backup_folder = obs.obs_data_get_string( settings, "backup_folder" )
local custom_time_format = obs.obs_data_get_string( settings, "custom_time_format" )
local timer_trim = obs.obs_data_get_int( settings, "timer_trim" )
local import_list = obs.obs_data_get_string( settings, "import_list" )
local backup_m = obs.obs_data_get_bool( settings, "backup_mode" )
local config = obs.obs_data_get_int( settings, "config" )
local mode = obs.obs_data_get_int( settings, "timer_type" )
local rec = obs.obs_data_get_int( settings, "start_recording" )
local scene = obs.obs_data_get_string( settings, "next_scene" )
local t_source = obs.obs_data_get_string( settings, "timer_source" )
local s_source = obs.obs_data_get_string( settings, "split_source" )
local a_source = obs.obs_data_get_string( settings, "active_source" )
local mth = obs.obs_data_get_int( settings, "month" )
local yr = obs.obs_data_get_int( settings, "year" )
local d = obs.obs_data_get_int( settings, "day" )
local c_type = obs.obs_data_get_int( settings, "countdown_type" )
local t_text = obs.obs_data_get_int( settings, "trigger_text" )
local cn_source = obs.obs_data_get_string( settings, "caution_note_source" )
local wn_source = obs.obs_data_get_string( settings, "warning_note_source" )
-- Retrieves property reference
local import_list_prop = obs.obs_properties_get( props, "import_list" )
local custom_time_format_prop = obs.obs_properties_get( props, "custom_time_format" )
local t_text_prop = obs.obs_properties_get( props, "trigger_text" )
local cn_source_prop = obs.obs_properties_get( props, "caution_note_source" )
local wn_source_prop = obs.obs_properties_get( props, "warning_note_source" )
local c_note_prop = obs.obs_properties_get( props, "caution_note" )
local w_note_prop = obs.obs_properties_get( props, "warning_note" )
local stop_text_prop = obs.obs_properties_get( props, "stop_text" )
local text_prefix_prop = obs.obs_properties_get( props, "text_prefix" )
local text_suffix_prop = obs.obs_properties_get( props, "text_suffix" )
local recording_type_prop = obs.obs_properties_get( props, "recording_type" )
local cycle_list_prop = obs.obs_properties_get( props, "cycle_list" )
local active_source_prop = obs.obs_properties_get( props, "active_source" )
local day_text_prop = obs.obs_properties_get( props, "day_text" )
local days_text_prop = obs.obs_properties_get( props, "days_text" )
local month_prop = obs.obs_properties_get( props, "month" )
local day_prop = obs.obs_properties_get( props, "day" )
local year_prop = obs.obs_properties_get( props, "year" )
local countdown_type_prop = obs.obs_properties_get( props, "countdown_type" )
local pause_button_prop = obs.obs_properties_get( props, "pause_button" )
local reset_button_prop = obs.obs_properties_get( props, "reset_button" )
local start_recording_prop = obs.obs_properties_get( props, "start_recording" )
local next_scene_prop = obs.obs_properties_get( props, "next_scene" )
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_button_prop = obs.obs_properties_get( props, "split_button" )
local split_type_prop = obs.obs_properties_get( props, "split_type" )
local split_source_prop = obs.obs_properties_get( props, "split_source" )
local timer_trim_prop = obs.obs_properties_get( props, "timer_trim" )
local audio_caution_prop = obs.obs_properties_get( props, "audio_caution" )
local audio_warning_prop = obs.obs_properties_get( props, "audio_warning" )
local caution_duration_prop = obs.obs_properties_get( props, "caution_duration" )
local warning_duration_prop = obs.obs_properties_get( props, "warning_duration" )
local normal_color_prop = obs.obs_properties_get( props, "normal_color" )
local caution_color_prop = obs.obs_properties_get( props, "caution_color" )
local warning_color_prop = obs.obs_properties_get( props, "warning_color" )
local caution_text_prop = obs.obs_properties_get( props, "caution_text" )
local warning_text_prop = obs.obs_properties_get( props, "warning_text" )
local start_on_visible_prop = obs.obs_properties_get( props, "start_on_visible" )
local disable_script_prop = obs.obs_properties_get( props, "disable_script" )
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" )
if timer_trim ~= 5 then
obs.obs_property_set_visible( custom_time_format_prop, false )
else
obs.obs_property_set_visible( custom_time_format_prop, true )
end
if backup_m then
obs.obs_property_set_visible( import_list_prop, true )
obs.obs_property_set_visible( export_button_prop, true )
obs.obs_property_set_visible( import_button_prop, true )
obs.obs_property_set_visible( export_folder_prop, true )
else
obs.obs_property_set_visible( import_list_prop, false )
obs.obs_property_set_visible( export_button_prop, false )
obs.obs_property_set_visible( import_button_prop, false )
obs.obs_property_set_visible( export_folder_prop, false )
end
if import_list ~= "select" then
obs.obs_property_set_visible( import_button_prop, true )
else
obs.obs_property_set_visible( import_button_prop, false )
end
if ( in_table( {t_source, s_source, a_source, wn_source}, cn_source ) ) then
obs.obs_data_set_string(settings, "caution_note_source", 'select') -- Don't allow timer and caution note text source to be the same
end
if ( in_table( {t_source, s_source, a_source, cn_source}, wn_source ) ) then
obs.obs_data_set_string(settings, "warning_note_source", 'select') -- Don't allow timer and warning note text source to be the same
end
if ( in_table( {t_source, s_source, cn_source, wn_source}, a_source ) ) then
obs.obs_data_set_string(settings, "active_source", 'select') -- Don't allow timer and active text source to be the same
end
obs.obs_property_set_visible( t_text_prop, ( config == 2 ))
obs.obs_property_set_visible( cn_source_prop, ( config == 2 and ( t_text ~= 1 ) ))
obs.obs_property_set_visible( wn_source_prop, ( config == 2 and ( t_text ~= 1 ) ))
obs.obs_property_set_visible( c_note_prop, ( config == 2 and ( t_text ~= 1 ) ))
obs.obs_property_set_visible( w_note_prop, ( config == 2 and ( t_text ~= 1 ) ))
obs.obs_property_set_visible( stop_text_prop, false )
obs.obs_property_set_visible( text_prefix_prop, false )
obs.obs_property_set_visible( text_suffix_prop, false )
obs.obs_property_set_visible( recording_type_prop, false )
obs.obs_property_set_visible( cycle_list_prop, ( (scene == 'Source List' or scene == 'Scene List') and config == 2 ) )
obs.obs_property_set_visible( active_source_prop, ( (scene == 'Source List' or scene == 'Scene List') and config == 2 ) )
obs.obs_property_set_visible( day_text_prop, ( c_type == 1 and config == 2 and mode == 2 and timer_trim ~= 5 ) )
obs.obs_property_set_visible( days_text_prop, ( c_type == 1 and config == 2 and mode == 2 and timer_trim ~= 5 ) )
obs.obs_property_set_visible( month_prop, ( c_type == 1 and config == 2 and mode == 2 ) )
obs.obs_property_set_visible( day_prop, ( c_type == 1 and config == 2 and mode == 2 ) )
obs.obs_property_set_visible( year_prop, ( c_type == 1 and config == 2 and mode == 2 ) )
if mth ~= 1 then
obs.obs_property_set_enabled( day_prop, true )
obs.obs_property_set_enabled( year_prop, true )
else
obs.obs_property_set_enabled( day_prop, false )
obs.obs_property_set_enabled( year_prop, false )
end
if c_type == 1 and mth ~= 1 and d == 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
obs.obs_property_int_set_limits( day_prop, 1, 31, 1 )
if ( mth == 5 or mth == 7 or mth == 10 or mth == 12 ) then
obs.obs_property_int_set_limits( day_prop, 1, 30, 1 )
elseif ( mth == 3 ) then
local leap = 28
if is_leap_year(yr) then
leap = 29
else
leap = 28
end
obs.obs_property_int_set_limits( day_prop, 1, leap, 1 )
end
obs.obs_property_set_visible( countdown_type_prop, false )
obs.obs_property_set_visible( countdown_type_prop, (config == 2 and mode == 2 ) )
if scene == 'TIMER END TEXT' and mode == 2 then
obs.obs_property_set_visible( stop_text_prop, true )
end
-- Preset parameters
if rec == 1 and mode == 2 then
obs.obs_property_set_visible( recording_type_prop, config == 2 )
end
obs.obs_property_set_visible( text_prefix_prop, config == 2 )
obs.obs_property_set_visible( text_suffix_prop, config == 2 )
if mode == 2 then
obs.obs_property_set_visible( start_recording_prop, config == 2 )
obs.obs_property_set_visible( next_scene_prop, config == 2 )
obs.obs_property_set_visible( hours_prop, (config == 2 ) )
obs.obs_property_set_visible( minutes_prop, (config == 2 ) )
obs.obs_property_set_visible( seconds_prop, (config == 2 ) )
obs.obs_property_set_description( pause_button_prop, "Start/Pause Countdown" )
obs.obs_property_set_description( reset_button_prop, "Reset Countdown" )
else
obs.obs_property_set_visible( start_recording_prop, false )
obs.obs_property_set_visible( next_scene_prop, false )
obs.obs_property_set_visible( hours_prop, false )
obs.obs_property_set_visible( minutes_prop, false )
obs.obs_property_set_visible( seconds_prop, false )
obs.obs_property_set_description( pause_button_prop, "Start/Pause Stopwatch" )
obs.obs_property_set_description( reset_button_prop, "Reset Stopwatch" )
end
obs.obs_property_set_visible( split_button_prop, mode==1 )
obs.obs_property_set_visible( split_type_prop, false )
obs.obs_property_set_visible( split_source_prop, false )
obs.obs_property_set_visible( timer_trim_prop, config==2 )
obs.obs_property_set_visible( audio_caution_prop, config==2 )
obs.obs_property_set_visible( audio_warning_prop, config==2 )
obs.obs_property_set_visible( caution_duration_prop, config==2 )
obs.obs_property_set_visible( warning_duration_prop, config==2 )
obs.obs_property_set_visible( normal_color_prop, config==2 )
obs.obs_property_set_visible( caution_color_prop, config==2 )
obs.obs_property_set_visible( warning_color_prop, config==2 )
obs.obs_property_set_visible( caution_text_prop, config==2 )
obs.obs_property_set_visible( warning_text_prop, config==2 )
obs.obs_property_set_visible( start_on_visible_prop, config==2 )
obs.obs_property_set_visible( disable_script_prop, config==2 )
if mode == 1 then
obs.obs_property_set_visible( split_type_prop, config == 2 )
obs.obs_property_set_visible( split_source_prop, config == 2 )
end
if obs.os_file_exists( backup_folder ) then
obs.obs_property_list_clear( import_list_prop )
obs.obs_property_list_add_string( import_list_prop, 'Select', 'select' )
if has_file_list then
for i,v in pairs( filenames ) do
obs.obs_property_list_add_string( import_list_prop, v, v )
end
end
end
-- IMPORTANT: returns true to trigger refresh of the properties
return true
end
--[[
----------------------------------------------------------
A function named script_properties defines the properties that the user
can change for the entire script module itself
----------------------------------------------------------
]]
function script_properties()
props = obs.obs_properties_create()
local p_1 = obs.obs_properties_add_list( props, "timer_type", "<b>Timer Type</b>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Stopwatch", "Countdown"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_1, v, i ) end
local p_2 = obs.obs_properties_add_list( props, "config", "<font color=".. font_dimmed ..">Configuration</font>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Basic", "Advanced"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_2, v, i ) end
--[[
Returns an array of reference-incremented sources.
Release with source_list_release().
]]
local sources = obs.obs_enum_sources()
local p_3 = obs.obs_properties_add_list( props, "timer_source", "<i>Timer Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_3, "Select", "select" )
local list = {}
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name( source )
if not in_table( {split_source, active_source, media["caution_note_source"], media["warning_note_source"]}, name ) then
--[[
add it to list so that it can be reordered
]]
list[name] = name
else
--continue
end
end
end
obs.bfree(source)
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_3, value, value )
end
end
local p_4 = obs.obs_properties_add_list( props, "countdown_type", "<font color=".. font_dimmed ..">Countdown Type</font>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Specific Date & Time", "Hours, Minutes, Seconds"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_4, v, i ) end
local p_5 = obs.obs_properties_add_text( props, "day_text", "<font color=".. font_dimmed ..">Day Text Format</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_5, "\nUsed to distinguish between singular and plural days format. Use this for singular.\n" )
local p_6 = obs.obs_properties_add_text( props, "days_text", "<font color=".. font_dimmed ..">Days Text Format</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_6, "\nUsed to distinguish between singular and plural days format. Use this for plural.\n" )
local p_7 = obs.obs_properties_add_list( props, "month", "<font color=".. font_dimmed ..">Month</font>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Select", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_7, v, i ) end
local p_8 = obs.obs_properties_add_int( props, "year", "<font color=".. font_dimmed ..">Year</font>", 2022, 212021221, 1 )
local p_9 = obs.obs_properties_add_int( props, "day", "<font color=".. font_dimmed ..">Day</font>", 1, 31, 1 )
local p_10 = obs.obs_properties_add_int( props, "hours", "<font color=".. font_dimmed ..">Hours</font>", 0, 23, 1 )
obs.obs_property_int_set_suffix( p_10, " Hours" )
local p_11 = obs.obs_properties_add_int( props, "minutes", "<font color=".. font_dimmed ..">Minutes</font>", 0, 59, 1 )
obs.obs_property_int_set_suffix( p_11, " Minutes" );
local p_12 = obs.obs_properties_add_int( props, "seconds", "<font color=".. font_dimmed ..">Seconds</font>", 0, 59, 1 )
obs.obs_property_int_set_suffix( p_12, " Seconds" );
local p_13 = obs.obs_properties_add_list( props, "timer_trim", "Timer Format", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Display full format", "Remove leading zeros", "No leading zeros, no split seconds", "No split seconds", "Custom Time Format"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_13, v, i ) end
local p_37 = obs.obs_properties_add_text( props, "custom_time_format", "<font color=".. font_dimmed ..">Time Format</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_37, "\n Timestamp is represented by $D = day, $H = hour, $M = minute, $S = second, $F = split second.\n\n To trim leading zeros, include $T = truncate leading zeros. This will ONLY affect a format matching '$D:$H:$M:$S,$F' (00:00:00:00,00)\n" )
local p_14 = obs.obs_properties_add_list( props, "split_source", "<i>Split Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_14, "Select", "select" )
list = {}
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name( source )
if not in_table( {timer_source, active_source, media["caution_note_source"], media["warning_note_source"]}, name ) then
--[[
add it to list so that it can be reordered
]]
list[name] = name
else
--continue
end
end
end
obs.bfree(source)
for key, value in pairsByKeys(list) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_14, value, value )
end
end
local p_15 = obs.obs_properties_add_list( props, "split_type", "Split Type", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Interval", "Mark", "Mark Interval", "Interval Mark"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_15, v, i ) end
obs.obs_property_set_long_description( p_15, "\nInterval = Time between current and previous split.\n\nMark = Time of split\n" )
local p_16 = obs.obs_properties_add_list( props, "audio_caution", "<font color=".. font_dimmed ..">Caution Audio</font>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_16, "None", "none" )
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "ffmpeg_source" then
local name = obs.obs_source_get_name( source )
obs.obs_property_list_add_string( p_16, name, name )
end
end
obs.bfree(source)
end
local p_17 = obs.obs_properties_add_list( props, "audio_warning", "<font color=".. font_dimmed ..">Warning Audio</font>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_17, "None", "none" )
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "ffmpeg_source" then
local name = obs.obs_source_get_name( source )
obs.obs_property_list_add_string( p_17, name, name )
end
end
obs.bfree(source)
end
obs.obs_properties_add_color( props, "normal_color", "Normal Color" )
obs.obs_properties_add_color( props, "caution_color", "Caution Color" )
obs.obs_properties_add_color( props, "warning_color", "Warning Color" )
local p_18 = obs.obs_properties_add_text( props, "caution_text", "<font color=".. font_dimmed ..">Caution Time</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_18, "\nUse format 00:00:00 ( hoursa:minutes:seconds )\n" )
local p_i = obs.obs_properties_add_text( props, "warning_text", "<font color=".. font_dimmed ..">Warning Time</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_i, "\nUse format 00:00:00 ( hoursa:minutes:seconds )\n" )
local p_19 = obs.obs_properties_add_list( props, "trigger_text", "<i>Trigger Text</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Disabled", "Enabled"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_19, v, i ) end
obs.obs_property_set_long_description( p_19, "\nDisplay a note when the timer trigger warning and caution states.\n" )
local p_20 = obs.obs_properties_add_list( props, "caution_note_source", "<i>Caution Note Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_20, "Select", "select" )
list = {}
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name( source )
if not in_table( {timer_source, split_source, active_source, media["warning_note_source"]}, name ) then
--[[
add it to list so that it can be reordered
]]
list[name] = name
else
--continue
end
end
end
obs.bfree(source)
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_20, value, value )
end
end
local p_21 = obs.obs_properties_add_list( props, "warning_note_source", "<i>Warning Note Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_21, "Select", "select" )
list = {}
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name( source )
if not in_table( {timer_source, split_source, active_source, media["caution_note_source"]}, name ) then
--[[
add it to list so that it can be reordered
]]
list[name] = name
else
--continue
end
end
end
obs.bfree( source )
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_21, value, value )
end
end
local p_22 = obs.obs_properties_add_text( props, "caution_note", "<font color=".. font_dimmed ..">Caution Note</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_22, "\nDisplay a note when the caution trigger.\n" )
local p_23 = obs.obs_properties_add_text( props, "warning_note", "<font color=".. font_dimmed ..">Warning Note</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_23, "\nDisplay a note when the warning trigger.\n" )
--*props, *name, *description, min, max, step
obs.obs_properties_add_int_slider( props, "caution_duration", "Caution Duration", 1, 100, 1 )
obs.obs_properties_add_int_slider( props, "warning_duration", "Warning Duration", 1, 100, 1 )
local p_24 = obs.obs_properties_add_list( props, "start_recording", "Auto Recording", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Yes", "No"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_24, v, i ) end
-- Combo list filled with the options from _type
local p_25 = obs.obs_properties_add_list( props, "recording_type", "Recording", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT )
t_type = {"Timer Expires", "Caution Time", "Warning Time", "Timer Visible", "Timer Start"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_int( p_25, v, i ) end
local p_26 = obs.obs_properties_add_list( props, "next_scene", "<i>Next Scene</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
t_type = {"Select", "TIMER END TEXT", "Source List", "Scene List"}
for i,v in ipairs( t_type ) do obs.obs_property_list_add_string( p_26, v, v ) end
local scene_source = obs.obs_frontend_get_current_scene()
local name = obs.obs_source_get_name( scene_source )
local scenes = obs.obs_frontend_get_scene_names()
if scenes ~= nil then
for i, scene in ipairs( scenes ) do
if name ~= scene then
obs.obs_property_list_add_string( p_26, scene, scene )
end
end
obs.bfree( scene )
end
obs.obs_source_release( scene_source )
local p_27 = obs.obs_properties_add_text( props, "text_prefix", "<font color=#fefceb>Timer Prefix</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_27, "\nDefine text placed before the Timer\n" )
local p_28 = obs.obs_properties_add_text( props, "text_suffix", "<font color=#fefceb>Timer Suffix</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_28, "\nDefine text placed after the Timer\n" )
local p_29 = obs.obs_properties_add_text( props, "stop_text", "<font color=#fef1eb>Timer End Text</font>", obs.OBS_TEXT_DEFAULT )
obs.obs_property_set_long_description( p_29, "\nDefine text displayed when timer ended\n" )
local p_30 = obs.obs_properties_add_list( props, "active_source", "<i>Active Source</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_set_long_description( p_30, "\nSelect a text source, that will be used to show the name for the current active Source or Scene\n" )
obs.obs_property_list_add_string( p_30, "Select", "select" )
list = {}
if sources ~= nil then
for _, source in ipairs( sources ) do
source_id = obs.obs_source_get_unversioned_id( source )
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name( source )
if name ~= timer_source then
--[[
add it to list so that it can be reordered
]]
list[name] = name
else
--continue
end
end
end
obs.bfree(source)
for key, value in pairsByKeys( list ) do
--[[
add item to property list
]]
obs.obs_property_list_add_string( p_30, value, value )
end
end
local p_31 = obs.obs_properties_add_editable_list(props, "cycle_list", "Cycle List",obs.OBS_EDITABLE_LIST_TYPE_STRINGS,nil,nil)
obs.obs_properties_add_button( props, "reset_button", "Reset Stopwatch", reset_button_clicked )
obs.obs_properties_add_button( props, "pause_button", "Start/Pause Stopwatch", pause_button_clicked )
obs.obs_properties_add_button( props, "split_button", "Split Time", split_button_clicked )
obs.obs_properties_add_bool( props, "start_on_visible", "Start Timer on Source Visible" )
obs.obs_properties_add_bool( props, "disable_script", "Disable Script" )
local p_32 = obs.obs_properties_add_bool( props, "backup_mode", "Backup Mode" )
local p_33 = obs.obs_properties_add_path( props, "backup_folder", "Backup Folder", obs.OBS_PATH_DIRECTORY, nil, nil)
local p_34 = obs.obs_properties_add_list( props, "import_list", "<i>Load Settings</i>", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING )
obs.obs_property_list_add_string( p_34, 'Select ', 'select' )
obs.obs_property_set_long_description( p_34, "\nSelect the Settings file to import.\n" )
local filenames = get_filenames( path )
if table.getn( filenames ) > 0 then
for i,v in pairs( filenames ) do
obs.obs_property_list_add_string( p_34, v, v )
end
end
local p_35 = obs.obs_properties_add_button( props, "export_button", "Export Settings", export_button_clicked )
local p_36 = obs.obs_properties_add_button( props, "import_button", "Import Settings", import_button_clicked )
obs.source_list_release( sources )
--Sets callback upon modification of the list Basically an Event Listener
obs.obs_property_set_modified_callback( p_1, property_onchange )
obs.obs_property_set_modified_callback( p_2, property_onchange )
obs.obs_property_set_modified_callback( p_4, property_onchange )
obs.obs_property_set_modified_callback( p_7, property_onchange )
obs.obs_property_set_modified_callback( p_8, property_onchange )
obs.obs_property_set_modified_callback( p_13, property_onchange )
obs.obs_property_set_modified_callback( p_19, property_onchange )
obs.obs_property_set_modified_callback( p_24, property_onchange )
obs.obs_property_set_modified_callback( p_26, property_onchange )
obs.obs_property_set_modified_callback( p_30, property_onchange )
obs.obs_property_set_modified_callback( p_32, property_onchange )
obs.obs_property_set_modified_callback( p_33, property_onchange )
obs.obs_property_set_modified_callback( p_34, property_onchange )
obs.obs_property_set_modified_callback( p_36, import_properties )
-- Calls the callback once to set-up current visibility
obs.obs_properties_apply_settings( props, script_settings )
return props
end
--[[
----------------------------------------------------------
A function named script_update will be called when settings are changed
----------------------------------------------------------
]]
-- Called upon settings initialization and modification
function script_update( settings )
assign_default_frequency()
activate( false )
trigger_text = obs.obs_data_get_int( settings, "trigger_text" )
media["caution_note_source"] = obs.obs_data_get_string( settings, "caution_note_source" )
media["warning_note_source"] = obs.obs_data_get_string( settings, "warning_note_source" )
media["caution_note"] = string.gsub(obs.obs_data_get_string( settings, "caution_note" ), "\\([n])", {n="\n"})
media["warning_note"] = string.gsub(obs.obs_data_get_string( settings, "warning_note" ), "\\([n])", {n="\n"})
timer_type = obs.obs_data_get_int( settings, "timer_type" )
timer_source = obs.obs_data_get_string( settings, "timer_source" )
countdown_type = obs.obs_data_get_int( settings, "countdown_type" )
if timer_type == 2 then
cur_seconds =
( obs.obs_data_get_int( settings, "hours" )*60*60 ) +
( obs.obs_data_get_int( settings, "minutes" )*60 ) +
obs.obs_data_get_int( settings, "seconds" )
else
cur_seconds = 0
end
custom_time_format = obs.obs_data_get_string( settings, "custom_time_format" )
longtimetext_s = string.gsub(obs.obs_data_get_string( settings, "day_text" ), "\\([n])", {n="\n"})
longtimetext_p = string.gsub(obs.obs_data_get_string( settings, "days_text" ), "\\([n])", {n="\n"})
timer_year = obs.obs_data_get_int( settings, "year" )
timer_month = obs.obs_data_get_int( settings, "month" ) - 1
timer_day = obs.obs_data_get_int( settings, "day" )
timer_hours = obs.obs_data_get_int( settings, "hours" )
timer_minutes = obs.obs_data_get_int( settings, "minutes" )
timer_seconds = obs.obs_data_get_int( settings, "seconds" )
if timer_type == 2 and countdown_type == 1 then
cur_seconds = delta_time( timer_year, timer_month, timer_day, timer_hours, timer_minutes, timer_seconds)
end
timer_trim = obs.obs_data_get_int( settings, "timer_trim" )
def_seconds = cur_seconds
split_source = obs.obs_data_get_string( settings, "split_source" )
active_source = obs.obs_data_get_string( settings, "active_source" )
media['source_name_audio_warning'] = obs.obs_data_get_string( settings, "audio_warning" )
media['source_name_audio_caution'] = obs.obs_data_get_string( settings, "audio_caution" )
media['normal_color'] = obs.obs_data_get_int( settings, "normal_color" )
media['caution_color'] = obs.obs_data_get_int( settings, "caution_color" )
media['warning_color'] = obs.obs_data_get_int( settings, "warning_color" )
media['warning_text'] = obs.obs_data_get_string( settings, "warning_text" )
media['caution_text'] = obs.obs_data_get_string( settings, "caution_text" )
media['caution_duration'] = obs.obs_data_get_int( settings, "caution_duration" )
media['warning_duration'] = obs.obs_data_get_int( settings, "warning_duration" )
split_type = obs.obs_data_get_string( settings, "split_type" )
start_recording = obs.obs_data_get_int( settings, "start_recording" )
recording_type = obs.obs_data_get_int( settings, "recording_type" )
next_scene = obs.obs_data_get_string( settings, "next_scene" )
text_prefix = string.gsub(obs.obs_data_get_string( settings, "text_prefix" ), "\\([n])", {n="\n"})
text_suffix = string.gsub(obs.obs_data_get_string( settings, "text_suffix" ), "\\([n])", {n="\n"})
stop_text = obs.obs_data_get_string( settings, "stop_text" )
start_on_visible = obs.obs_data_get_bool( settings,"start_on_visible" )
backup_folder = obs.obs_data_get_string( settings, "backup_folder" )
disable_script = obs.obs_data_get_bool( settings,"disable_script" )
import_list = obs.obs_data_get_string( settings, "import_list" )
reset( true )
-- Keep track of current settings
script_settings = settings
end
--[[
----------------------------------------------------------
A function named script_defaults will be called to set the default settings
----------------------------------------------------------
]]
function script_defaults( settings )
assign_default_frequency()
obs.obs_data_set_default_int( settings, "trigger_text", 1 )
obs.obs_data_set_default_string( settings, "custom_time_format", "$T$D:$H:$M:$S,$F" )
obs.obs_data_set_default_string( settings, "caution_note", "" )
obs.obs_data_set_default_string( settings, "warning_note", "" )
obs.obs_data_set_default_string( settings, "caution_note_source", "Select" )
obs.obs_data_set_default_string( settings, "warning_note_source", "Select" )
obs.obs_data_set_default_int( settings, "timer_type", 1 )
obs.obs_data_set_default_int( settings, "config", 1 )
obs.obs_data_set_default_string( settings, "timer_source", "Select" )
obs.obs_data_set_default_int( settings, "countdown_type", 2 )
obs.obs_data_set_default_int( settings, "year", os.date("%Y", os.time()) )
obs.obs_data_set_default_int( settings, "hours", 0 )
obs.obs_data_set_default_int( settings, "minutes", 0 )
obs.obs_data_set_default_int( settings, "seconds", 0 )
obs.obs_data_set_default_int( settings, "timer_trim", 1 )
obs.obs_data_set_default_string( settings, "day_text", "# Day \n" )
obs.obs_data_set_default_string( settings, "days_text", "# Days \n" )
obs.obs_data_set_default_string( settings, "split_source", "Select" )
obs.obs_data_set_default_string( settings, "audio_warning", "None" )
obs.obs_data_set_default_string( settings, "audio_caution", "None" )
obs.obs_data_set_default_int( settings, "normal_color", media['normal_color'] )
obs.obs_data_set_default_int( settings, "caution_color", media['caution_color'] )
obs.obs_data_set_default_int( settings, "warning_color", media['warning_color'] )
obs.obs_data_set_default_string( settings, "warning_text", "" )
obs.obs_data_set_default_string( settings, "caution_text", "" )
obs.obs_data_set_default_int( settings, "caution_duration", 5 )
obs.obs_data_set_default_int( settings, "warning_duration", 5 )
obs.obs_data_set_default_int( settings, "split_type", 2 )
obs.obs_data_set_default_int( settings, "start_recording", 2 )
obs.obs_data_set_default_int( settings, "recording_type", 5 )
obs.obs_data_set_default_string( settings, "next_scene", "Select" )
obs.obs_data_set_default_string( settings, "text_prefix", "" )
obs.obs_data_set_default_string( settings, "text_suffix", "" )
obs.obs_data_set_default_string( settings, "stop_text", "" )
obs.obs_data_set_default_bool( settings, "start_on_visible", false )
obs.obs_data_set_default_bool( settings, "disable_script", false )
obs.obs_data_set_default_bool( settings, "backup_mode", false )
-- Keep track of current settings
script_settings = settings
end
--[[
----------------------------------------------------------
A function named script_save will be called when the script is saved
NOTE: This function is usually used for saving extra data ( such as in this
case, a hotkey's save data ). Settings set via the properties are saved
automatically.
----------------------------------------------------------
]]
function script_save( settings )
local hotkey_save_array_reset = obs.obs_hotkey_save( hotkey_id_reset )
local hotkey_save_array_pause = obs.obs_hotkey_save( hotkey_id_pause )
local hotkey_save_array_split = obs.obs_hotkey_save( hotkey_id_split )
obs.obs_data_set_array( settings, "reset_hotkey", hotkey_save_array_reset )
obs.obs_data_set_array( settings, "pause_hotkey", hotkey_save_array_pause )
obs.obs_data_set_array( settings, "split_hotkey", hotkey_save_array_split )
obs.obs_data_array_release( hotkey_save_array_pause )
obs.obs_data_array_release( hotkey_save_array_reset )
obs.obs_data_array_release( hotkey_save_array_split )
end
--[[
----------------------------------------------------------
a function named script_load will be called on startup
Connect hotkey and activation/deactivation signal callbacks
--
NOTE: These particular script callbacks do not necessarily have to
be disconnected, as callbacks will automatically destroy themselves
if the script is unloaded. So there's no real need to manually
disconnect callbacks that are intended to last until the script is
unloaded.
----------------------------------------------------------
]]
function script_load( settings )
assign_default_frequency()
local sh = obs.obs_get_signal_handler()
obs.signal_handler_connect( sh, "source_activate", source_activated )
obs.signal_handler_connect( sh, "source_deactivate", source_deactivated )
hotkey_id_reset = obs.obs_hotkey_register_frontend( "reset_stopwatch_" .. filename():lower():gsub('[%W%p%c%s]', ''), "Reset " .. filename(), reset )
hotkey_id_pause = obs.obs_hotkey_register_frontend( "pause_stopwatch_" .. filename():lower():gsub('[%W%p%c%s]', ''), "Start/Pause " .. filename(), on_pause )
hotkey_id_split = obs.obs_hotkey_register_frontend( "split_stopwatch_" .. filename():lower():gsub('[%W%p%c%s]', ''), "Split Time " .. filename(), on_split )
local hotkey_save_array_reset = obs.obs_data_get_array( settings, "reset_hotkey" )
local hotkey_save_array_pause = obs.obs_data_get_array( settings, "pause_hotkey" )
local hotkey_save_array_split = obs.obs_data_get_array( settings, "split_hotkey" )
obs.obs_hotkey_load( hotkey_id_reset, hotkey_save_array_reset )
obs.obs_hotkey_load( hotkey_id_pause, hotkey_save_array_pause )
obs.obs_hotkey_load( hotkey_id_split, hotkey_save_array_split )
obs.obs_data_array_release( hotkey_save_array_reset )
obs.obs_data_array_release( hotkey_save_array_pause )
obs.obs_data_array_release( hotkey_save_array_split )
end