feat: Expose filename-override operations as obs-websocket vendor requests#143
Closed
hanatyan128 wants to merge 17 commits into
Closed
feat: Expose filename-override operations as obs-websocket vendor requests#143hanatyan128 wants to merge 17 commits into
hanatyan128 wants to merge 17 commits into
Conversation
Open
hanatyan128
force-pushed
the
feat-obs-websocket-vendor-request
branch
6 times, most recently
from
April 26, 2026 04:04
d22598e to
6f5a051
Compare
hanatyan128
force-pushed
the
feat-obs-websocket-vendor-request
branch
3 times, most recently
from
May 8, 2026 03:37
ed982fa to
3ea123e
Compare
Add Lua variants of recording-filename-from-text and replay-buffer-filename-from-text sample scripts. Both include: - Robust filename sanitization (control chars, trailing dots/spaces, Windows reserved names) - UTF-8 BOM stripping and UTF-16 detection - 4 KB read size limit for safety - Filter id verification before proc calls - Proper cleanup on filter selection change and script reload Enhance API.md and API_ja.md with: - Threading and call context requirements - Filter source acquisition guide - osi_branch_output_get_filter_list notes (post_load timing, private source exclusion) - Sample scripts section covering both Python and Lua variants Update README TIPS sections to mention both Python and Lua variants. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Align recording/replay-buffer filename-from-text sample scripts so the Lua and Python variants share the same robustness fixes: version note corrected to v1.0.9+, override_cleared flag to suppress redundant proc calls, enhanced sanitize_filename (control chars, trailing dots/spaces, Windows reserved names), BOM handling with 4KB read limit, old-filter override clearing on selection change, filter ID validation with proc return-value logging, and defensive timer_remove in script_load. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- onGetFilterList: dispatch to UI thread via QMetaObject::invokeMethod, with same-thread direct-call fallback to avoid BlockingQueuedConnection self-deadlock; null-out statusDock on module unload - Sample scripts: reset last_text (and throttle state) on clear_override, warn on empty file path, extend Windows reserved-name check to cover base names with extensions (e.g. CON.txt) - API docs: revise threading notes and add call-context guidance for osi_branch_output_get_filter_list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…etime Round 1-3 review findings across sample scripts and related native code: - Lua sanitize_filename now normalizes NBSP/U+3000/ZWSP/U+2028/U+2029/BOM - Document Windows ANSI code page limitation of Lua io.open - statusDock promoted to std::atomic and unpublished before dock teardown - Clarify callback safety and hotkey context in API docs - Document lock ordering and proc_handler lifetime in native code Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the per-byte-sequence gsub chain in sanitize_filename() with a utf8.codes() walk driven by a strip/space lookup. Also folds the en/em space family (U+2000–200A) for parity with the Python variant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Lua: replace Lua 5.3 utf8 library with LuaJIT-compatible manual
UTF-8 decoder/encoder (utf8_codepoints, cp_to_utf8), removing
dead code and misleading pcall warning
- C++: change JSON fallback from empty string to '{}' for safer
downstream parsing
- Python: wrap calldata_create/calldata_free in try/finally to
prevent leaks on exception
- Python: add MAX_SANITIZED_LENGTH=128 to sanitize_filename to
avoid exceeding Windows MAX_PATH
Lua/Python scripts: - Truncate sanitized filenames to 200 bytes with UTF-8 boundary respect - Call clear_override() when text source is deselected in script_update() - Validate empty base_format to prevent ambiguous empty overrides (Lua) - Add group source limitation note to script_description() C++: - Use statusDock.store() instead of implicit operator= for consistency - Fix comment: 'acquire/release semantics' -> 'sequential consistency' - Clarify Q_DECLARE_METATYPE comment as qRegisterMetaType safety net
Trim review-round artifacts where long justification comments were added to defend design choices. Replace prose with concise FIXMEs where the root-cause fix is deferred. Drop internal-implementation details from API.md / API_ja.md that callers do not need. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Defer last_text update to proc call success to prevent failed calls from being silently swallowed on subsequent ticks - Fix 4-branch new_format logic in Python to match Lua (trailing space, unintended clear when base_format is empty) - Add UTF-8 validation for non-UTF-8 file content (CP932 etc.) - Add cp_to_utf8 surrogate-half guard - Detect and warn on file truncation at MAX_READ_SIZE - Unify sanitize_filename step order with Python variant - Move MAX_FILENAME_BYTES to module-level constants - Log warning on JSON parse failure - Remove redundant state resets after clear_override()
Expose the existing proc handlers (get_filter_list, override_recording_filename_format, override_replay_buffer_filename_format) as obs-websocket vendor requests under vendor name "osi_branch_output". Vendor request callbacks delegate to the proc handlers so logic stays in one place. Add obs-websocket as a git submodule under lib/ for the API header.
- Validate filter_uuid length, format size (strnlen), and filter type - Return success/error protocol consistently across vendor requests - Add FIXME for ws worker thread and in-flight unregister race - Guard missing obs-websocket submodule with CMake FATAL_ERROR - Document submodule tag-pin policy in .gitmodules - Exclude lib/ from run-cmake-format local scan
- Relocate the vendor request section from README to API.md / API_ja.md - README now points to the API reference for details - Trim internal implementation notes; keep only user-facing limitations
- Move FILTER_ID and PROC_OVERRIDE_* proc names to plugin-main.hpp as shared constants - Normalize UUID input to lowercase before obs_get_source_by_uuid() lookup - Move vendor.store() to after all request registrations complete - Replace locale-dependent std::isxdigit/isalpha with explicit ASCII range checks - Reorder obs_module_unload() to null statusDock before unregistering vendor requests - Remove lib/ from CPACK_SOURCE_IGNORE_FILES to preserve obs-websocket-api.h in source tarballs - Add SYSTEM keyword to obs-websocket include directory in CMakeLists.txt - Add early exit in build.ps1 on submodule update failure - Fix cmake-format glob pattern for lib/ submodule exclusion - Add submodule init instructions to README / README_ja - Correct error strings in API documentation
Submodule presence is checked only when the option is ON, with FATAL_ERROR on absence. Includes accumulated input validation, lifetime annotation, and Security documentation refinements.
hanatyan128
force-pushed
the
feat-obs-websocket-vendor-request
branch
from
May 8, 2026 03:38
3ea123e to
85e1ec6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
osi_branch_outputobs-websocket vendor with three requests that mirror the existing proc handler APIs:get_filter_list,override_recording_filename_format,override_replay_buffer_filename_format.lib/obs-websocketas a tag-pinned git submodule (5.7.3) for the vendor API headers only; no runtime linkage.API.md/API_ja.mdwith the same audience as the existing proc handler reference;README.md/README_ja.mdnow point there.Vendor requests
get_filter_list{ success, error?, filters: array }override_recording_filename_format{ filter_uuid, format }{ success, error? }override_replay_buffer_filename_format{ filter_uuid, format }{ success, error? }filterselements exposesource_name,source_uuid,filter_name,filter_uuid, matching the existingosi_branch_output_get_filter_listproc handler.formatclears the override (same semantics as the proc handlers).Input validation
filter_uuidmust be a 36-character hyphenated UUID. Non-matching shapes return"filter_uuid must be a UUID string".formatis capped at 1024 bytes (strnlenearly-exit). Oversized inputs return"format too long".osi_branch_output). Non-matching sources and missing UUIDs both return"Filter not found"to avoid leaking existence information.obs_source_get_id()null-guard added for defensive safety on the ws worker thread path.Security model
formatstring is forwarded to libobs's filename expander unchanged and can therefore include subdirectory paths or overwrite existing recordings.API.md/API_ja.mdcapture this explicitly in the Security section.Build / CI
CMakeLists.txt:FATAL_ERRORguard if the submodule is missing;CMAKE_CURRENT_SOURCE_DIRused for super-build robustness..gitmodules: tag-pinned operation documented via comment (nobranch =entry so--remotecannot drift).build-aux/.run-format.zsh: excludelib/*so local cmake-format runs do not pick up submodule files..gitignore: allowlist!/libto un-ignore the submodule directory..github/workflows/check-format.yaml: unchanged (submodule checkout not required; format scope issrc/and project CMake files).Threading / lifecycle caveats
outputMutexvia the underlying proc handlers. A recording transition (split/restart) can pin the caller for up to ~1 s. Documented inline as aFIXMEfor future rework (in-flight counter + timeout).obs_websocket_vendor_unregister_request()does not wait for in-flight callbacks; documented as aFIXMEparallel to the existingstatusDockshutdown race.Test plan
get_filter_listvia an obs-websocket client; confirmfilterslists every Branch Output filter with correctsource_*/filter_*fields.override_recording_filename_formatwith a valid filter UUID and observe the next recording uses the new format; pass""to clear.override_replay_buffer_filename_formatwith a valid filter UUID and confirm the next replay save uses the new format; pass""to clear.format, non-filter source UUID); confirm each returns the expectedsuccess=false+errormessage.cmake --freshwithout the submodule and confirm theFATAL_ERRORmessage instructsgit submodule update --init --recursive../build-aux/run-cmake-format --checklocally with the submodule present; confirm no submodule files are scanned.🤖 Generated with Claude Code