From 538dfa8616ad9b4dc267a6488e2b91413828ab49 Mon Sep 17 00:00:00 2001 From: Aidan Bradley Date: Tue, 4 Nov 2025 00:25:36 -0500 Subject: [PATCH 1/2] feat: Add per-scene-item transition support - Add GetSceneItemShowTransition request to get scene item show transitions - Add SetSceneItemShowTransition request to set scene item show transitions - Add GetSceneItemHideTransition request to get scene item hide transitions - Add SetSceneItemHideTransition request to set scene item hide transitions These requests expose per-scene-item transition properties through the WebSocket API, allowing clients to configure and manage show/hide transitions for individual scene items. Transitions support: - Setting custom transitions for show/hide actions - Configuring duration (in milliseconds) for each transition - Removing transitions by passing null - Works with both scenes and scene groups Addresses issue #906 --- src/requesthandler/RequestHandler.cpp | 6 + src/requesthandler/RequestHandler.h | 6 + .../RequestHandler_SceneItems.cpp | 212 ++++++++++++++++++ 3 files changed, 224 insertions(+) diff --git a/src/requesthandler/RequestHandler.cpp b/src/requesthandler/RequestHandler.cpp index c077215e..3e02fc50 100644 --- a/src/requesthandler/RequestHandler.cpp +++ b/src/requesthandler/RequestHandler.cpp @@ -147,6 +147,12 @@ const std::unordered_map RequestHandler::_han {"GetSceneItemPrivateSettings", &RequestHandler::GetSceneItemPrivateSettings}, {"SetSceneItemPrivateSettings", &RequestHandler::SetSceneItemPrivateSettings}, + // Scene Item Transitions + {"GetSceneItemShowTransition", &RequestHandler::GetSceneItemShowTransition}, + {"SetSceneItemShowTransition", &RequestHandler::SetSceneItemShowTransition}, + {"GetSceneItemHideTransition", &RequestHandler::GetSceneItemHideTransition}, + {"SetSceneItemHideTransition", &RequestHandler::SetSceneItemHideTransition}, + // Outputs {"GetVirtualCamStatus", &RequestHandler::GetVirtualCamStatus}, {"ToggleVirtualCam", &RequestHandler::ToggleVirtualCam}, diff --git a/src/requesthandler/RequestHandler.h b/src/requesthandler/RequestHandler.h index 082a6a1b..cd5eda3c 100644 --- a/src/requesthandler/RequestHandler.h +++ b/src/requesthandler/RequestHandler.h @@ -166,6 +166,12 @@ class RequestHandler { RequestResult GetSceneItemPrivateSettings(const Request &); RequestResult SetSceneItemPrivateSettings(const Request &); + // Scene Item Transitions + RequestResult GetSceneItemShowTransition(const Request &); + RequestResult SetSceneItemShowTransition(const Request &); + RequestResult GetSceneItemHideTransition(const Request &); + RequestResult SetSceneItemHideTransition(const Request &); + // Outputs RequestResult GetVirtualCamStatus(const Request &); RequestResult ToggleVirtualCam(const Request &); diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 146fb654..2f517a66 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -839,3 +839,215 @@ RequestResult RequestHandler::SetSceneItemPrivateSettings(const Request &request return RequestResult::Success(); } + +/** + * Gets the show transition for a scene item. + * + * Scenes and Groups + * + * @requestField ?sceneName | String | Name of the scene the item is in + * @requestField ?sceneUuid | String | UUID of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField transitionName | String | Name of the transition or null if none set + * @responseField transitionUuid | String | UUID of the transition or null if none set + * @responseField transitionKind | String | Kind of the transition or null if none set + * @responseField transitionDuration | Number | Duration of the transition in milliseconds or null if none set + * + * @requestType GetSceneItemShowTransition + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::GetSceneItemShowTransition(const Request &request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = + request.ValidateSceneItem(statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!sceneItem) + return RequestResult::Error(statusCode, comment); + + json responseData; + + OBSSourceAutoRelease transition = obs_sceneitem_get_transition(sceneItem, true); + if (transition) { + responseData["transitionName"] = obs_source_get_name(transition); + responseData["transitionUuid"] = obs_source_get_uuid(transition); + responseData["transitionKind"] = obs_source_get_id(transition); + responseData["transitionDuration"] = obs_sceneitem_get_transition_duration(sceneItem, true); + } else { + responseData["transitionName"] = nullptr; + responseData["transitionUuid"] = nullptr; + responseData["transitionKind"] = nullptr; + responseData["transitionDuration"] = nullptr; + } + + return RequestResult::Success(responseData); +} + +/** + * Sets the show transition for a scene item. + * + * Scenes and Groups + * + * @requestField ?sceneName | String | Name of the scene the item is in + * @requestField ?sceneUuid | String | UUID of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField ?transitionName | String | Name of the transition to set. Pass null to remove transition | null + * @requestField ?transitionDuration | Number | Duration of the transition in milliseconds | >= 0 + * + * @requestType SetSceneItemShowTransition + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::SetSceneItemShowTransition(const Request &request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = + request.ValidateSceneItem(statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!sceneItem) + return RequestResult::Error(statusCode, comment); + + // Get transition name if provided + std::optional transitionName; + if (request.RequestData.contains("transitionName") && !request.RequestData["transitionName"].is_null()) { + if (!request.ValidateString("transitionName", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + transitionName = request.RequestData["transitionName"]; + } + + // Set transition if provided + if (transitionName) { + OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(transitionName.value()); + if (!transition) + return RequestResult::Error(RequestStatus::ResourceNotFound, + "No transition was found with the name '" + transitionName.value() + "'."); + obs_sceneitem_set_transition(sceneItem, true, transition); + } else if (request.RequestData.contains("transitionName") && request.RequestData["transitionName"].is_null()) { + // Remove transition if explicitly set to null + obs_sceneitem_set_transition(sceneItem, true, nullptr); + } + + // Set duration if provided + if (request.RequestData.contains("transitionDuration")) { + if (!request.ValidateNumber("transitionDuration", statusCode, comment, 0)) + return RequestResult::Error(statusCode, comment); + uint32_t duration = request.RequestData["transitionDuration"]; + obs_sceneitem_set_transition_duration(sceneItem, true, duration); + } + + return RequestResult::Success(); +} + +/** + * Gets the hide transition for a scene item. + * + * Scenes and Groups + * + * @requestField ?sceneName | String | Name of the scene the item is in + * @requestField ?sceneUuid | String | UUID of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * + * @responseField transitionName | String | Name of the transition or null if none set + * @responseField transitionUuid | String | UUID of the transition or null if none set + * @responseField transitionKind | String | Kind of the transition or null if none set + * @responseField transitionDuration | Number | Duration of the transition in milliseconds or null if none set + * + * @requestType GetSceneItemHideTransition + * @complexity 2 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::GetSceneItemHideTransition(const Request &request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = + request.ValidateSceneItem(statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!sceneItem) + return RequestResult::Error(statusCode, comment); + + json responseData; + + OBSSourceAutoRelease transition = obs_sceneitem_get_transition(sceneItem, false); + if (transition) { + responseData["transitionName"] = obs_source_get_name(transition); + responseData["transitionUuid"] = obs_source_get_uuid(transition); + responseData["transitionKind"] = obs_source_get_id(transition); + responseData["transitionDuration"] = obs_sceneitem_get_transition_duration(sceneItem, false); + } else { + responseData["transitionName"] = nullptr; + responseData["transitionUuid"] = nullptr; + responseData["transitionKind"] = nullptr; + responseData["transitionDuration"] = nullptr; + } + + return RequestResult::Success(responseData); +} + +/** + * Sets the hide transition for a scene item. + * + * Scenes and Groups + * + * @requestField ?sceneName | String | Name of the scene the item is in + * @requestField ?sceneUuid | String | UUID of the scene the item is in + * @requestField sceneItemId | Number | Numeric ID of the scene item | >= 0 + * @requestField ?transitionName | String | Name of the transition to set. Pass null to remove transition | null + * @requestField ?transitionDuration | Number | Duration of the transition in milliseconds | >= 0 + * + * @requestType SetSceneItemHideTransition + * @complexity 3 + * @rpcVersion -1 + * @initialVersion 5.7.0 + * @api requests + * @category scene items + */ +RequestResult RequestHandler::SetSceneItemHideTransition(const Request &request) +{ + RequestStatus::RequestStatus statusCode; + std::string comment; + OBSSceneItemAutoRelease sceneItem = + request.ValidateSceneItem(statusCode, comment, OBS_WEBSOCKET_SCENE_FILTER_SCENE_OR_GROUP); + if (!sceneItem) + return RequestResult::Error(statusCode, comment); + + // Get transition name if provided + std::optional transitionName; + if (request.RequestData.contains("transitionName") && !request.RequestData["transitionName"].is_null()) { + if (!request.ValidateString("transitionName", statusCode, comment)) + return RequestResult::Error(statusCode, comment); + transitionName = request.RequestData["transitionName"]; + } + + // Set transition if provided + if (transitionName) { + OBSSourceAutoRelease transition = Utils::Obs::SearchHelper::GetSceneTransitionByName(transitionName.value()); + if (!transition) + return RequestResult::Error(RequestStatus::ResourceNotFound, + "No transition was found with the name '" + transitionName.value() + "'."); + obs_sceneitem_set_transition(sceneItem, false, transition); + } else if (request.RequestData.contains("transitionName") && request.RequestData["transitionName"].is_null()) { + // Remove transition if explicitly set to null + obs_sceneitem_set_transition(sceneItem, false, nullptr); + } + + // Set duration if provided + if (request.RequestData.contains("transitionDuration")) { + if (!request.ValidateNumber("transitionDuration", statusCode, comment, 0)) + return RequestResult::Error(statusCode, comment); + uint32_t duration = request.RequestData["transitionDuration"]; + obs_sceneitem_set_transition_duration(sceneItem, false, duration); + } + + return RequestResult::Success(); +} From 29c7a4e4543f191b42d632db85a8095b6db551e4 Mon Sep 17 00:00:00 2001 From: Brutus Gaius Date: Wed, 5 Nov 2025 18:41:08 -0500 Subject: [PATCH 2/2] Update RequestHandler_SceneItems.cpp In order to fully close the issue of #906 of obs-websockets, #include is necessary (v32 of OBS as of this commit). --- src/requesthandler/RequestHandler_SceneItems.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requesthandler/RequestHandler_SceneItems.cpp b/src/requesthandler/RequestHandler_SceneItems.cpp index 2f517a66..0fd907f4 100644 --- a/src/requesthandler/RequestHandler_SceneItems.cpp +++ b/src/requesthandler/RequestHandler_SceneItems.cpp @@ -16,7 +16,7 @@ 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 #include "RequestHandler.h" /**