local obs = obslua local folder_path = "" local media_source_name = "" local files = {} local last_played_file = nil local next_interval = 0 local tick_accumulator = 0 local min_interval = 10 local max_interval = 30 local file_extensions = {"mp3", "wav", "ogg"} local path_sep = package.config:sub(1, 1) function script_description() return table.concat({ "Plays random tracks from the selected folder in the Media Source with a pause between them (random within range)", "Features:", "- Select folder and media source", "- Set min/max interval between tracks", "- Filter by file extension", "- Automatic scheduling and playback", "- Detailed logging for troubleshooting" }, "\n") end function script_properties() local props = obs.obs_properties_create() obs.obs_properties_add_path(props, "folder_path", "Folder with Tracks", obs.OBS_PATH_DIRECTORY, "", "") local media_list = obs.obs_properties_add_list(props, "media_source_name", "Media Source", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING) local all_sources = obs.obs_enum_sources() if all_sources then for _, source in ipairs(all_sources) do if obs.obs_source_get_id(source) == "ffmpeg_source" then local name = obs.obs_source_get_name(source) obs.obs_property_list_add_string(media_list, name, name) end end obs.source_list_release(all_sources) end obs.obs_properties_add_int(props, "min_interval", "Min. Interval (sec)", 1, 3600, 1) obs.obs_properties_add_int(props, "max_interval", "Max. Interval (sec)", 1, 3600, 1) return props end function script_update(settings) folder_path = obs.obs_data_get_string(settings, "folder_path") media_source_name = obs.obs_data_get_string(settings, "media_source_name") min_interval = obs.obs_data_get_int(settings, "min_interval") max_interval = obs.obs_data_get_int(settings, "max_interval") if min_interval > max_interval then min_interval, max_interval = max_interval, min_interval end load_files() if media_source_name and media_source_name ~= "" then local source = obs.obs_get_source_by_name(media_source_name) if source then local handler = obs.obs_source_get_signal_handler(source) obs.signal_handler_disconnect(handler, "media_ended", on_media_ended) obs.signal_handler_connect(handler, "media_ended", on_media_ended) obs.obs_source_release(source) else obs.script_log(obs.LOG_WARNING, string.format("Source not found: %s", media_source_name)) end end end function script_load(settings) math.randomseed(os.time()) play_random_file() set_new_interval() end function load_files() files = {} if not folder_path or folder_path == "" then obs.script_log(obs.LOG_WARNING, "No folder selected") return end local p = io.popen(string.format('dir "%s" /b', folder_path)) if not p then obs.script_log(obs.LOG_ERROR, string.format("Failed to open folder: %s", tostring(folder_path))) return end for file in p:lines() do for _, ext in ipairs(file_extensions) do if file:lower():match("%." .. ext:lower() .. "$") then table.insert(files, folder_path .. path_sep .. file) break end end end p:close() end function set_new_interval() local min = math.max(min_interval, 1) local max = math.max(max_interval, min) if min == max then next_interval = min else next_interval = math.random(min, max) end obs.script_log(obs.LOG_INFO, string.format("Next interval: %s", next_interval)) end function script_tick(seconds) if next_interval > 0 then next_interval = next_interval - seconds if next_interval <= 0 then play_random_file() end end end function play_random_file() if #files == 0 then obs.script_log(obs.LOG_WARNING, "No files to play") return end local idx = math.random(1, #files) local file = files[idx] if #files > 1 and file == last_played_file then idx = idx % #files + 1 file = files[idx] end last_played_file = file local source = obs.obs_get_source_by_name(media_source_name) if not source then obs.script_log(obs.LOG_ERROR, string.format("Source not found when trying to play: %s", media_source_name)) return end local settings = obs.obs_source_get_settings(source) if not settings then obs.script_log(obs.LOG_ERROR, string.format("Failed to get source settings for %s", media_source_name)) obs.obs_source_release(source) return end obs.obs_data_set_string(settings, "local_file", file) local ok = pcall(function() obs.obs_source_update(source, settings) obs.obs_source_media_restart(source) end) obs.obs_data_release(settings) obs.obs_source_release(source) if not ok then obs.script_log(obs.LOG_ERROR, string.format("Failed to play file: %s", file)) end end function on_media_ended(_) set_new_interval() end function on_event(event) if event == obs.OBS_FRONTEND_EVENT_EXIT then local source = obs.obs_get_source_by_name(media_source_name) if source then local handler = obs.obs_source_get_signal_handler(source) obs.signal_handler_disconnect(handler, "media_ended", on_media_ended) obs.obs_source_release(source) end end end