local SCRIPT_NAME = "Organized Output Directory" local VERSION_STRING = "1.0.1" local GITHUB_PROJECT_URL = "https://github.com/MrMartin92/obs_organized_output_directory" local GITHUB_PROJECT_LICENCE_URL = "https://raw.githubusercontent.com/MrMartin92/obs_organized_output_directory/main/LICENSE" local GITHUB_PROJECT_BUG_TRACKER_URL = GITHUB_PROJECT_URL .. "/issues" local GITHUB_AUTHOR_URL = "https://github.com/MrMartin92" local TWITCH_AUTHOR_URL = "https://twitch.tv/MrMartin_" local KOFI_URL = "https://ko-fi.com/MrMartin_" local name_source_enum = { ["Window Title"] = 0, ["Process Name"] = 1 } local DEFAULT_SCREENSHOT_SUB_DIR = "screenshots" local DEFAULT_REPLAY_SUB_DIR = "replays" local DEFAULT_NAME_SOURCE = name_source_enum["Window Title"] local cfg_screenshot_sub_dir local cfg_replay_sub_dir local cfg_name_source local obs = obslua function script_description() return "
\z With \"" .. SCRIPT_NAME .. "\" you can create order in your output directory. \z The script automatically creates subdirectories for each game in the output directory. \z To do this, it searches for Window Capture or Game Capture sources in the current scene. \z The last active and hooked source is then used to determine the name of the subdirectory from the window title or the process name.
\z You found a bug or you have a feature request? Great! Open an issue on GitHub.
\z โฅ๏ธ If you wish, you can support me on Ko-fi. Thank you! ๐ค
\z
๐ Version: " .. VERSION_STRING .. "
\z
๐งโ๐ป Author: Tobias Lorenz [GitHub] [Twitch]
\z
๐ฌ Source: GitHub.com
\z
๐งพ Licence: MIT"
end
function script_properties()
local props = obs.obs_properties_create()
obs.obs_properties_add_text(props, "SCREENSHOT_SUB_DIR", "Screenshot directory name", obs.OBS_TEXT_DEFAULT)
obs.obs_properties_add_text(props, "REPLAY_SUB_DIR", "Replay directory name", obs.OBS_TEXT_DEFAULT)
local props_name_source = obs.obs_properties_add_list(props, "NAME_SOURCE", "Name source", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT)
for name, value in pairs(name_source_enum) do
obs.obs_property_list_add_int(props_name_source, name, value)
end
return props
end
function script_update(settings)
print("script_update()")
cfg_screenshot_sub_dir = obs.obs_data_get_string(settings, "SCREENSHOT_SUB_DIR")
cfg_replay_sub_dir = obs.obs_data_get_string(settings, "REPLAY_SUB_DIR")
cfg_name_source = obs.obs_data_get_int(settings, "NAME_SOURCE")
end
function script_defaults(settings)
print("script_defaults()")
obs.obs_data_set_default_string(settings, "SCREENSHOT_SUB_DIR", DEFAULT_SCREENSHOT_SUB_DIR)
obs.obs_data_set_default_string(settings, "REPLAY_SUB_DIR", DEFAULT_REPLAY_SUB_DIR)
obs.obs_data_set_default_int(settings, "NAME_SOURCE", DEFAULT_NAME_SOURCE)
end
local function get_filename(path)
return string.match(path, "[^/]*$")
end
local function get_base_path(path)
local filename_length = #get_filename(path)
return string.sub(path, 0, -1 - filename_length)
end
local function get_source_hook_infos(source)
local cd = obs.calldata_create()
local proc = obs.obs_source_get_proc_handler(source)
obs.proc_handler_call(proc, "get_hooked", cd)
local hooked = obs.calldata_bool(cd, "hooked")
local executable = obs.calldata_string(cd, "executable")
local title = obs.calldata_string(cd, "title")
obs.calldata_destroy(cd)
return executable, title, hooked
end
local function search_for_capture_source_and_get_data()
local process_name, window_name
local sources = obs.obs_enum_sources()
for _, source in ipairs(sources) do
if obs.obs_source_active(source) then
local tmp_process_name, tmp_window_title, tmp_hooked = get_source_hook_infos(source)
if tmp_hooked then
process_name = tmp_process_name
window_name = tmp_window_title
end
end
end
return process_name, window_name
end
local function get_game_name()
print("get_game_name()")
local executable, title = search_for_capture_source_and_get_data()
if executable ~= nil then
print("\tExecutable: " .. executable)
end
if title ~= nil then
print("\tWindow title: " .. title)
end
if cfg_name_source == name_source_enum["Process Name"] then
return executable
end
return title
end
local function move_file(src, dst)
print("move_file()")
print("\t Src: " .. src)
print("\t Dst: " .. dst)
obs.os_mkdirs(get_base_path(dst))
if not obs.os_file_exists(dst) then
obs.os_rename(src, dst)
else
print("File aready exist at the destination! So we don't move the file!")
end
end
local function sanitize_path_string(path)
path = string.gsub(path, "^ +", "") -- Remove leading whitespaces
path = string.gsub(path, " +$", "") -- Remove trailing whitespaces
path = string.gsub(path, "[<>:\\/\"|?*]", "") -- Remove illigal path characters for Windows
return path
end
local function screenshot_event()
print("screenshot_event()")
local file_path = obs.obs_frontend_get_last_screenshot()
local game_name = get_game_name()
if game_name == nil then
return
end
local new_file_path = get_base_path(file_path) .. sanitize_path_string(game_name) .. "/" .. sanitize_path_string(cfg_screenshot_sub_dir) .. "/".. get_filename(file_path)
move_file(file_path, new_file_path)
end
local function replay_event()
print("replay_event()")
local file_path = obs.obs_frontend_get_last_replay()
local game_name = get_game_name()
if game_name == nil then
return
end
local new_file_path = get_base_path(file_path) .. sanitize_path_string(game_name) .. "/" .. sanitize_path_string(cfg_replay_sub_dir) .. "/".. get_filename(file_path)
move_file(file_path, new_file_path)
end
local function event_dispatch(event)
if event == obs.OBS_FRONTEND_EVENT_SCREENSHOT_TAKEN then
screenshot_event()
elseif event == obs.OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED then
replay_event()
end
end
function script_load(settings)
print("script_load()")
obs.obs_frontend_add_event_callback(event_dispatch)
end