|
36 | 36 | #include "drm-format.hpp" |
37 | 37 | #endif |
38 | 38 |
|
| 39 | +struct scene_item_enum_data { |
| 40 | + std::vector<nlohmann::json> *items; |
| 41 | +}; |
| 42 | + |
| 43 | +static bool enum_scene_items(obs_scene_t *scene, obs_sceneitem_t *item, void *param) |
| 44 | +{ |
| 45 | + scene_item_enum_data *data = static_cast<scene_item_enum_data *>(param); |
| 46 | + |
| 47 | + obs_source_t *source = obs_sceneitem_get_source(item); |
| 48 | + if (!source) |
| 49 | + return true; |
| 50 | + |
| 51 | + const char *source_name = obs_source_get_name(source); |
| 52 | + if (!source_name) |
| 53 | + return true; |
| 54 | + |
| 55 | + nlohmann::json item_json = {{"id", obs_sceneitem_get_id(item)}, |
| 56 | + {"name", source_name}, |
| 57 | + {"visible", obs_sceneitem_visible(item)}, |
| 58 | + {"locked", obs_sceneitem_locked(item)}, |
| 59 | + {"type", obs_source_get_type(source)}}; |
| 60 | + |
| 61 | + data->items->push_back(item_json); |
| 62 | + return true; |
| 63 | +} |
| 64 | + |
39 | 65 | inline bool BrowserClient::valid() const |
40 | 66 | { |
41 | 67 | return !!bs && !bs->destroying; |
@@ -244,6 +270,107 @@ bool BrowserClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefR |
244 | 270 | json = {{"name", name}, |
245 | 271 | {"width", obs_source_get_width(current_scene)}, |
246 | 272 | {"height", obs_source_get_height(current_scene)}}; |
| 273 | + } else if (name == "getSceneItemList") { |
| 274 | + OBSSourceAutoRelease current_scene = obs_frontend_get_current_scene(); |
| 275 | + |
| 276 | + if (!current_scene) |
| 277 | + return false; |
| 278 | + |
| 279 | + // Convert source to scene object for enumeration |
| 280 | + obs_scene_t *scene = obs_scene_from_source(current_scene); |
| 281 | + if (!scene) |
| 282 | + return false; |
| 283 | + |
| 284 | + std::vector<nlohmann::json> scene_items; |
| 285 | + scene_item_enum_data data = {&scene_items}; |
| 286 | + |
| 287 | + // Enumerate all items in the scene and collect their data |
| 288 | + obs_scene_enum_items(scene, enum_scene_items, &data); |
| 289 | + |
| 290 | + json = scene_items; |
| 291 | + } else if (name == "getBrowserInputSettings") { |
| 292 | + const std::string input_name = input_args->GetString(1).ToString(); |
| 293 | + |
| 294 | + // Retrieve the source by name from OBS |
| 295 | + // Lookup by ID not needed. When a user duplicates a source with reference the settings are the same. |
| 296 | + OBSSourceAutoRelease source = obs_get_source_by_name(input_name.c_str()); |
| 297 | + if (!source) { |
| 298 | + return false; |
| 299 | + } |
| 300 | + |
| 301 | + // Validate that the source is actually a browser source |
| 302 | + const char *source_id = obs_source_get_id(source); |
| 303 | + if (!source_id || strcmp(source_id, "browser_source") != 0) { |
| 304 | + return false; |
| 305 | + } |
| 306 | + |
| 307 | + // Get the source settings data |
| 308 | + obs_data_t *settings = obs_source_get_settings(source); |
| 309 | + if (!settings) { |
| 310 | + return false; |
| 311 | + } |
| 312 | + |
| 313 | + // Extract browser source specific settings from the data |
| 314 | + const char *url = obs_data_get_string(settings, "url"); |
| 315 | + int width = (int)obs_data_get_int(settings, "width"); |
| 316 | + int height = (int)obs_data_get_int(settings, "height"); |
| 317 | + bool shutdown = obs_data_get_bool(settings, "shutdown"); |
| 318 | + int webpage_control_level = (int)obs_data_get_int(settings, "webpage_control_level"); |
| 319 | + |
| 320 | + json = {{"inputKind", "browser_source"}, |
| 321 | + {"inputSettings", |
| 322 | + {{"height", height}, |
| 323 | + {"shutdown", shutdown}, |
| 324 | + {"url", url ? url : ""}, |
| 325 | + {"webpage_control_level", webpage_control_level}, |
| 326 | + {"width", width}}}}; |
| 327 | + |
| 328 | + // Release allocated memory |
| 329 | + obs_data_release(settings); |
| 330 | + } else if (name == "getSceneItemTransform") { |
| 331 | + const std::string scene_name = input_args->GetString(1).ToString(); |
| 332 | + int64_t scene_item_id = input_args->GetInt(2); |
| 333 | + |
| 334 | + OBSSourceAutoRelease source = obs_get_source_by_name(scene_name.c_str()); |
| 335 | + if (!source) { |
| 336 | + return false; |
| 337 | + } |
| 338 | + |
| 339 | + // Verify that the source is actually a scene |
| 340 | + if (!obs_source_is_scene(source)) { |
| 341 | + return false; |
| 342 | + } |
| 343 | + |
| 344 | + // Convert source to scene object for item lookup |
| 345 | + obs_scene_t *scene = obs_scene_from_source(source); |
| 346 | + if (!scene) { |
| 347 | + return false; |
| 348 | + } |
| 349 | + |
| 350 | + // Find the specific scene item by its unique ID |
| 351 | + obs_sceneitem_t *item = obs_scene_find_sceneitem_by_id(scene, scene_item_id); |
| 352 | + if (!item) { |
| 353 | + return false; |
| 354 | + } |
| 355 | + |
| 356 | + // Retrieve transform and crop information from the scene item |
| 357 | + struct obs_transform_info transform; |
| 358 | + struct obs_sceneitem_crop crop; |
| 359 | + obs_sceneitem_get_info2(item, &transform); |
| 360 | + obs_sceneitem_get_crop(item, &crop); |
| 361 | + |
| 362 | + json = {{"position", {{"x", transform.pos.x}, {"y", transform.pos.y}}}, |
| 363 | + {"rotation", transform.rot}, |
| 364 | + {"scale", {{"x", transform.scale.x}, {"y", transform.scale.y}}}, |
| 365 | + {"alignment", transform.alignment}, |
| 366 | + {"boundsType", transform.bounds_type}, |
| 367 | + {"boundsAlignment", transform.bounds_alignment}, |
| 368 | + {"bounds", {{"x", transform.bounds.x}, {"y", transform.bounds.y}}}, |
| 369 | + {"crop", |
| 370 | + {{"left", crop.left}, |
| 371 | + {"top", crop.top}, |
| 372 | + {"right", crop.right}, |
| 373 | + {"bottom", crop.bottom}}}}; |
247 | 374 | } else if (name == "getTransitions") { |
248 | 375 | struct obs_frontend_source_list list = {}; |
249 | 376 | obs_frontend_get_transitions(&list); |
|
0 commit comments