obs = obslua -- User-defined settings settings = { text_source_name = "", prefix = "Next Stream: ", separator = " • ", even_week_time = "08:00 PM", odd_week_time = "09:00 PM", suffix = "ET", 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 } } -- 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 AM/PM function format_time(time_str) local hours, minutes, ampm = time_str:match("^(%d+):(%d%d) (%a%a)$") hours = tonumber(hours) or 0 minutes = tonumber(minutes) or 0 return string.format("%02d:%02d %s", hours, minutes, ampm) end -- Function to determine the next stream day and time function get_next_stream() local days_of_week = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"} 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)) + (time:sub(-2) == "PM" and 12 or 0), min=tonumber(time:sub(4, 5))} if stream_time > current_time then return days_of_week[index] .. 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 planned" 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 -- Script properties function script_properties() local props = obs.obs_properties_create() -- Display current time, date, and week number local current_time = os.date("%A %I:%M %p") 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) obs.obs_properties_add_text(props, "text_source_name", "Text Source", obs.OBS_TEXT_DEFAULT) obs.obs_properties_add_text(props, "prefix", "Prefix", obs.OBS_TEXT_DEFAULT) obs.obs_properties_add_text(props, "suffix", "Suffix", obs.OBS_TEXT_DEFAULT) obs.obs_properties_add_text(props, "separator", "Separator", obs.OBS_TEXT_DEFAULT) obs.obs_properties_add_text(props, "even_week_time", "Stream Time (Even Weeks)", obs.OBS_TEXT_DEFAULT) obs.obs_properties_add_text(props, "odd_week_time", "Stream Time (Odd Weeks)", obs.OBS_TEXT_DEFAULT) 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 .. " streaming") local time_choice = obs.obs_properties_add_list(day_group, day:lower() .. "_time_choice", "Stream Time", 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_properties_add_text(day_group, day:lower() .. "_custom_time", "Manual Stream Time (e.g., 08:00 PM)", obs.OBS_TEXT_DEFAULT) 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") 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_STYERs Dynamic Next Stream' updates a text source with your next stream day and time. You can choose to automatically set stream times (useful for rotating schedules) or manually define stream times for each day. The next stream day and time will update automatically. First, create a text source in OBS and enter its exact name in the 'Text Source' setting." end function script_load(new_settings) script_update(new_settings) obs.timer_add(update_text_source, 10000) -- Update every 40 seconds end function script_unload() obs.timer_remove(update_text_source) end