obs = obslua -- User-defined settings settings = { text_source_name = "", prefix = "Next Stream: ", separator = " • ", even_week_time = "20:00", odd_week_time = "21:00", suffix = " o'clock", days = { {enabled = false, auto_time = true, custom_time = ""}, -- Monday {enabled = false, auto_time = true, custom_time = ""}, -- Tuesday {enabled = false, auto_time = true, custom_time = ""}, -- Wednesday {enabled = false, auto_time = true, custom_time = ""}, -- Thursday {enabled = false, auto_time = true, custom_time = ""}, -- Friday {enabled = false, auto_time = true, custom_time = ""}, -- Saturday {enabled = false, auto_time = true, custom_time = ""} -- Sunday }, day_format = "full" -- Options: "full" or "short" } -- Helper function to get the current week number function get_week_number(day_offset) day_offset = day_offset or 0 local current_time = os.time() + (day_offset * 24 * 60 * 60) local year_start = os.time{year=os.date("%Y", current_time), month=1, day=1} local day_of_year = os.date("%j", current_time) local week_num = math.ceil(day_of_year / 7) return week_num end -- Helper function to check if a given week number is even function is_even_week(week_num) return week_num % 2 == 0 end -- Helper function to format time as HH:MM function format_time(time_str) local hours, minutes = time_str:match("^(%d+):?(%d*)$") hours = tonumber(hours) or 0 minutes = tonumber(minutes) or 0 return string.format("%02d:%02d", hours, minutes) end -- Function to determine the next stream day and time function get_next_stream() local days_of_week = settings.day_format == "full" and {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} or {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"} local current_time = os.time() local current_day = (os.date("*t").wday + 5) % 7 + 1 -- Adjusting to make Monday=1, ..., Sunday=7 for i = 0, 6 do local index = (current_day + i - 1) % 7 + 1 local day_setting = settings.days[index] if day_setting.enabled then local day_offset = i local week_num = get_week_number(day_offset) local is_even = is_even_week(week_num) local time if day_setting.auto_time then time = is_even and settings.even_week_time or settings.odd_week_time else time = day_setting.custom_time end local stream_time = os.time{year=os.date("%Y", current_time), month=os.date("%m", current_time), day=os.date("%d", current_time) + day_offset, hour=tonumber(time:sub(1, 2)), min=tonumber(time:sub(4, 5))} if stream_time > current_time then local day_name if i == 0 then day_name = "Today" elseif i == 1 then day_name = "Tomorrow" else day_name = days_of_week[index] end return day_name .. settings.separator .. format_time(time) end end end return nil end -- Function to update the text source function update_text_source() local next_stream = get_next_stream() local text = next_stream and (settings.prefix .. next_stream .. " " .. settings.suffix) or "No stream scheduled" local source = obs.obs_get_source_by_name(settings.text_source_name) if source then local source_settings = obs.obs_source_get_settings(source) obs.obs_data_set_string(source_settings, "text", text) obs.obs_source_update(source, source_settings) obs.obs_data_release(source_settings) obs.obs_source_release(source) end end -- Function to populate the dropdown list with text sources function add_text_sources(property) local sources = obs.obs_enum_sources() if sources ~= nil then for _, source in ipairs(sources) do local 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) obs.obs_property_list_add_string(property, name, name) end end end obs.source_list_release(sources) end -- Script properties function script_properties() local props = obs.obs_properties_create() -- Display current time, date, and week number local current_time = os.date("%A %H:%M") local week_num = get_week_number() local is_even = is_even_week(week_num) and "even" or "odd" local header = string.format("%s, (Week %d)", current_time, week_num) obs.obs_properties_add_text(props, "header", header, obs.OBS_TEXT_INFO) local text_source_list = obs.obs_properties_add_list(props, "text_source_name", "Text Source", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING) add_text_sources(text_source_list) -- Group for prefix, separator, and suffix local format_group = obs.obs_properties_create() obs.obs_properties_add_text(format_group, "prefix", "Prefix", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(format_group, "prefix"), "Text displayed before the next stream time.") obs.obs_properties_add_text(format_group, "separator", "Separator", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(format_group, "separator"), "Character that separates the day and time of the next stream.") obs.obs_properties_add_text(format_group, "suffix", "Suffix", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(format_group, "suffix"), "Text displayed after the time of the next stream.") obs.obs_properties_add_group(props, "format_settings", "Format Settings", obs.OBS_GROUP_NORMAL, format_group) -- Group for stream times local time_group = obs.obs_properties_create() obs.obs_properties_add_text(time_group, "even_week_time", "Stream Start (Even Weeks)", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(time_group, "even_week_time"), "Automatic stream start time for even weeks.") obs.obs_properties_add_text(time_group, "odd_week_time", "Stream Start (Odd Weeks)", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(time_group, "odd_week_time"), "Automatic stream start time for odd weeks.") obs.obs_properties_add_group(props, "time_settings", "Stream Start Settings", obs.OBS_GROUP_NORMAL, time_group) -- Day format settings local day_format = obs.obs_properties_add_list(props, "day_format", "Day Format", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING) obs.obs_property_list_add_string(day_format, "Full", "full") obs.obs_property_list_add_string(day_format, "Short", "short") obs.obs_property_set_long_description(day_format, "Choose between full or short day format.") -- Group for each day settings local days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} for i, day in ipairs(days) do local day_group = obs.obs_properties_create() obs.obs_properties_add_bool(day_group, day:lower() .. "_enabled", day .. " stream") obs.obs_property_set_long_description(obs.obs_properties_get(day_group, day:lower() .. "_enabled"), "Enable to stream on this day.") local time_choice = obs.obs_properties_add_list(day_group, day:lower() .. "_time_choice", "Stream Start", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING) obs.obs_property_list_add_string(time_choice, "Automatic (by week)", "auto") obs.obs_property_list_add_string(time_choice, "Manual", "custom") obs.obs_property_set_long_description(time_choice, "Choose whether the stream start time is automatic (depending on the week) or manual.") obs.obs_properties_add_text(day_group, day:lower() .. "_custom_time", "Manual Stream Start", obs.OBS_TEXT_DEFAULT) obs.obs_property_set_long_description(obs.obs_properties_get(day_group, day:lower() .. "_custom_time"), "Manually set stream start time for this day.") obs.obs_properties_add_group(props, day:lower(), day, obs.OBS_GROUP_NORMAL, day_group) end return props end -- Update settings when changed function script_update(new_settings) settings.text_source_name = obs.obs_data_get_string(new_settings, "text_source_name") settings.prefix = obs.obs_data_get_string(new_settings, "prefix") settings.separator = obs.obs_data_get_string(new_settings, "separator") settings.even_week_time = format_time(obs.obs_data_get_string(new_settings, "even_week_time")) settings.odd_week_time = format_time(obs.obs_data_get_string(new_settings, "odd_week_time")) settings.suffix = obs.obs_data_get_string(new_settings, "suffix") settings.day_format = obs.obs_data_get_string(new_settings, "day_format") local days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} for i, day in ipairs(days) do local day_lower = day:lower() settings.days[i].enabled = obs.obs_data_get_bool(new_settings, day_lower .. "_enabled") settings.days[i].auto_time = obs.obs_data_get_string(new_settings, day_lower .. "_time_choice") == "auto" settings.days[i].custom_time = format_time(obs.obs_data_get_string(new_settings, day_lower .. "_custom_time")) end update_text_source() end -- Initialize the script function script_description() return "'K_STYER's Dynamic Next Stream Version 1.3' updates a text source with the next stream day and time. Automatic or manual settings for each day are possible. First create a text source in OBS and select it from the dropdown list under 'Text Source'." end function script_load(new_settings) script_update(new_settings) obs.timer_add(update_text_source, 10000) -- Update every 10 seconds end function script_unload() obs.timer_remove(update_text_source) end