/****************************************************************************** Copyright (C) 2026 by FiniteSingularity This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ #include "PluginModuleLoader.hpp" #include "PluginManager.hpp" #include #include #include #include #include #include #include #include // BSD Third-Party Plugin Locations // // * User Path: // * Binary: //.so // * Data: //data // // * System Root Path: /usr // * Binary: //obs-modules/plugins/.so // * Data: /share/obs/obs-modules/plugins/ // // * User Root Path: /home//.config // * Binary: /obs-studio/plugins//.so // * Data: /obs-studio/plugins//data // // * Legacy User Path: + // * Binary: /.so // * Data: / // // * Legacy System Root Path: /usr // * Binary: //obs-plugins/.so // * Data: /share/obs/obs-plugins/ // // * Legacy User Root Path: /home//.config // * Binary: /obs-studio/plugins//bin/64bit/.so // * Data: /obs-studio/plugins//data // // * Legacy Fallback Path: // * Binary: /../../obs-plugins/64bit/.so // * Data: /share/obs/obs-plugins/ // using State = OBS::PluginManager::State; using ModuleType = obs_runtime_module_type; namespace Constants = OBS::Constants; constexpr std::string_view kModulePathSuffix{"/%module%/"}; constexpr std::string_view kModuleDataPathSuffix{"/%module%/data/"}; constexpr std::string_view kConfigBinaryPath{"/obs-studio/plugins/%module%/"}; constexpr std::string_view kConfigDataPath{"/obs-studio/plugins/%module%/data/"}; constexpr std::string_view kLegacyConfigBinaryPath{"/obs-studio/plugins/%module%/bin/64bit"}; constexpr std::string_view kLegacyConfigDataPath{"/obs-studio/plugins/%module%/data"}; constexpr bool hasSystemPluginPath = !Constants::kPlatformPluginModulePath.empty() && !Constants::kPlatformPluginDataPath.empty(); namespace { State pluginLoadHelper(const ModuleLoadInfo &info, ModuleList &failedModules) { int failedModuleCount = loadPluginsByInfo(info, failedModules); State result = (failedModuleCount > 0) ? State::PartialFailure : State::Success; return result; } } // namespace namespace OBS { State PluginManager::loadPlugins(bool usePortableMode) { State userPluginState = State::Failure; std::string userPluginPath = getEnvironmentVariable(kPathVariable); if (!userPluginPath.empty()) { std::string binaryPath{userPluginPath}; std::string dataPath{userPluginPath}; binaryPath.append(kModulePathSuffix); dataPath.append(kModuleDataPathSuffix); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_PLUGIN, .name = nullptr}; userPluginState = pluginLoadHelper(info, failedModules_); } else { userPluginState = State::Success; } State systemPluginState = State::Failure; if constexpr (hasSystemPluginPath) { std::string binaryPath{Constants::kPlatformPluginModulePath}; std::string dataPath{Constants::kPlatformPluginDataPath}; dataPath.append(kModulePathSuffix); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_PLUGIN, .name = nullptr}; systemPluginState = pluginLoadHelper(info, failedModules_); } else { systemPluginState = State::Success; } State configPluginState = State::Failure; if (!usePortableMode) { std::string userConfigPath{}; userConfigPath.resize(PATH_MAX); int bufferSize = os_get_config_path(userConfigPath.data(), userConfigPath.size(), nullptr); if (bufferSize > 0) { userConfigPath.resize(bufferSize); std::string binaryPath{userConfigPath}; std::string dataPath{userConfigPath}; binaryPath.append(kConfigBinaryPath); dataPath.append(kConfigDataPath); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_PLUGIN, .name = nullptr}; configPluginState = pluginLoadHelper(info, failedModules_); } } else { configPluginState = State::Success; } return (userPluginState && systemPluginState && configPluginState) ? State::Success : State::PartialFailure; } State PluginManager::loadLegacyPlugins(bool usePortableMode) { State userPluginState = State::Failure; std::string userPluginPath = getEnvironmentVariable(kLegacyBinaryPathVariable); std::string userDataPath = getEnvironmentVariable(kLegacyDataPathVariable); if (!userPluginPath.empty() && !userDataPath.empty()) { std::string binaryPath{userPluginPath}; std::string dataPath{userDataPath}; dataPath.append(kModulePathSuffix); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_LEGACY_PLUGIN, .name = nullptr}; userPluginState = pluginLoadHelper(info, failedModules_); } else { userPluginState = State::Success; } State systemPluginState = State::Failure; { std::string binaryPath{Constants::kPlatformInstallPath}; std::string dataPath{Constants::kPlatformInstallPath}; binaryPath.append(Constants::kPlatformLibraryPath); binaryPath.append("obs-plugins/"); dataPath.append(Constants::kPlatformDataPath); dataPath.append("obs/obs-plugins/%module%"); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_LEGACY_PLUGIN, .name = nullptr}; systemPluginState = pluginLoadHelper(info, failedModules_); } State configPluginState = State::Failure; if (!usePortableMode) { std::string userConfigPath{}; userConfigPath.resize(PATH_MAX); int bufferSize = os_get_config_path(userConfigPath.data(), userConfigPath.size(), nullptr); if (bufferSize > 0) { userConfigPath.resize(bufferSize); std::string binaryPath{userConfigPath}; std::string dataPath{userConfigPath}; binaryPath.append(kLegacyConfigBinaryPath); dataPath.append(kLegacyConfigDataPath); ModuleLoadInfo info = {.path_info = {.binary = binaryPath.c_str(), .data = dataPath.c_str()}, .type = OBS_MODULE_TYPE_LEGACY_PLUGIN, .name = nullptr}; configPluginState = pluginLoadHelper(info, failedModules_); } else { configPluginState = State::Success; } } return (userPluginState && systemPluginState && configPluginState) ? State::Success : State::PartialFailure; } } // namespace OBS