local output_path = obslua.obs_frontend_get_current_record_output_path() local output_path_prop_key = "output_path" local remux_enabled_prop_key = "remux_enabled" local remux_format_prop_key = "remux_format" local input_format_prop_key = "input_format" local delete_original_prop_key = "delete_original" local ffmpeg_path_prop_key = "ffmpeg_path" local desktop_notify_prop_key = "desktop_notify" local restart_replay_prop_key = "restart_replay_buffer" local REPLAY_EVENT = 0 local RECORDING_EVENT = 1 local SCREENSHOT_EVENT = 2 local remux_enabled = false local remux_format = "mp4" local input_format = "mkv" local delete_original = false local ffmpeg_path = "ffmpeg" local desktop_notify = false local restart_replay_buffer = false function script_description() return [[
Moves recordings, replays, and screenshots to a folder named after the current scene and optionally remuxes them to a different format.
]] end function script_load() obslua.obs_frontend_add_event_callback(obs_frontend_callback) end function obs_frontend_callback(callback, _private_data) if callback == obslua.OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED then save(REPLAY_EVENT) elseif callback == obslua.OBS_FRONTEND_EVENT_RECORDING_STOPPED then save(RECORDING_EVENT) elseif callback == obslua.OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN then save(SCREENSHOT_EVENT) end end function script_properties() local prop = obslua.obs_properties_create() obslua.obs_properties_add_path(prop, output_path_prop_key, "Output path:", obslua.OBS_PATH_DIRECTORY, nil, nil) obslua.obs_properties_add_path(prop, ffmpeg_path_prop_key, "FFmpeg Path:", obslua.OBS_PATH_FILE, nil, nil) obslua.obs_properties_add_bool(prop, remux_enabled_prop_key, "Enable Remuxing") obslua.obs_properties_add_bool(prop, delete_original_prop_key, "Delete Original After Remux") obslua.obs_properties_add_bool(prop, desktop_notify_prop_key, "Enable Desktop Notifications") obslua.obs_properties_add_bool(prop, restart_replay_prop_key, "Restart Replay Buffer After Save") local input_format_list = obslua.obs_properties_add_list( prop, input_format_prop_key, "Input Format", obslua.OBS_COMBO_TYPE_EDITABLE, obslua.OBS_COMBO_FORMAT_STRING ) obslua.obs_property_list_add_string(input_format_list, "MKV", "mkv") obslua.obs_property_list_add_string(input_format_list, "MOV", "mov") obslua.obs_property_list_add_string(input_format_list, "FLV", "flv") obslua.obs_property_list_add_string(input_format_list, "TS", "ts") obslua.obs_property_list_add_string(input_format_list, "MP4", "mp4") local remux_format_list = obslua.obs_properties_add_list( prop, remux_format_prop_key, "Remux To", obslua.OBS_COMBO_TYPE_EDITABLE, obslua.OBS_COMBO_FORMAT_STRING ) obslua.obs_property_list_add_string(remux_format_list, "MP4", "mp4") obslua.obs_property_list_add_string(remux_format_list, "MKV", "mkv") obslua.obs_property_list_add_string(remux_format_list, "MOV", "mov") obslua.obs_property_list_add_string(remux_format_list, "FLV", "flv") obslua.obs_property_list_add_string(remux_format_list, "TS", "ts") return prop end function script_update(settings) output_path = obslua.obs_data_get_string(settings, output_path_prop_key) remux_enabled = obslua.obs_data_get_bool(settings, remux_enabled_prop_key) delete_original = obslua.obs_data_get_bool(settings, delete_original_prop_key) ffmpeg_path = obslua.obs_data_get_string(settings, ffmpeg_path_prop_key) input_format = obslua.obs_data_get_string(settings, input_format_prop_key) remux_format = obslua.obs_data_get_string(settings, remux_format_prop_key) desktop_notify = obslua.obs_data_get_bool(settings, desktop_notify_prop_key) restart_replay_buffer = obslua.obs_data_get_bool(settings, restart_replay_prop_key) if ffmpeg_path == "" then ffmpeg_path = "ffmpeg" end end function script_defaults(settings) obslua.obs_data_set_default_string(settings, output_path_prop_key, output_path) obslua.obs_data_set_default_bool(settings, remux_enabled_prop_key, false) obslua.obs_data_set_default_string(settings, input_format_prop_key, "mkv") obslua.obs_data_set_default_string(settings, remux_format_prop_key, "mp4") obslua.obs_data_set_default_bool(settings, delete_original_prop_key, false) obslua.obs_data_set_default_string(settings, ffmpeg_path_prop_key, "ffmpeg") obslua.obs_data_set_default_bool(settings, desktop_notify_prop_key, false) obslua.obs_data_set_default_bool(settings, restart_replay_prop_key, false) end function notify_desktop(message) if desktop_notify then os.execute(('notify-send "OBSReplay" "%s"'):format(message)) end end function save(event) local latest_file_path = (event == REPLAY_EVENT and obslua.obs_frontend_get_last_replay()) or (event == RECORDING_EVENT and obslua.obs_frontend_get_last_recording()) or (event == SCREENSHOT_EVENT and obslua.obs_frontend_get_last_screenshot()) if latest_file_path and latest_file_path ~= "" then local current_scene_name = get_current_scene_name() local scene_folder_path = output_path .. "/" .. current_scene_name os.execute(('mkdir -p "%s"'):format(scene_folder_path)) local file_name = latest_file_path:match("([^/\\]+)$") local moved_file_path = scene_folder_path .. "/" .. file_name local move_command = ('mv "%s" "%s"'):format(latest_file_path, moved_file_path) os.execute(move_command) notify_desktop("Moved file to scene folder.") local file_exists = io.open(moved_file_path, "r") if not file_exists then notify_desktop("Move failed: file not found.") return else file_exists:close() end local base_name, ext = file_name:match("(.+)%.([^.]+)$") if not base_name or not ext then notify_desktop("Remux failed: invalid file name.") return end ext = ext:lower() local normalized_input_format = input_format:lower() if remux_enabled and ext == normalized_input_format then local new_file_path = scene_folder_path .. "/" .. base_name .. "." .. remux_format:lower() local remux_command = ('%s -y -i "%s" -c:v copy -c:a copy "%s" 2>&1') :format(ffmpeg_path, moved_file_path, new_file_path) local handle = io.popen(remux_command, "r") local result = handle:read("*a") handle:close() local remuxed_file_exists = io.open(new_file_path, "r") if not remuxed_file_exists then notify_desktop("Remux failed: check FFmpeg.") return else remuxed_file_exists:close() notify_desktop("Remuxed to " .. remux_format:upper() .. " successfully.") end if delete_original then local delete_command = ('rm "%s"'):format(moved_file_path) os.execute(delete_command) notify_desktop("Original file deleted after remux.") end elseif remux_enabled and ext ~= normalized_input_format then notify_desktop("Remux skipped format mismatch") end if re1_replay_buffer and event == REPLAY_EVENT then obslua.obs_frontend_replay_buffer_start() end else notify_desktop("No file found to move.") end end function get_current_scene_name() local current_scene = obslua.obs_frontend_get_current_scene() local name = obslua.obs_source_get_name(current_scene) obslua.obs_source_release(current_scene) return name end