mirror of
https://github.com/onyx-and-iris/obsws-ruby.git
synced 2026-04-18 05:23:32 +00:00
Compare commits
15 Commits
main
...
799ae52b02
| Author | SHA1 | Date | |
|---|---|---|---|
| 799ae52b02 | |||
| bc93654297 | |||
| aafcd185d0 | |||
| 43ecfb37f5 | |||
| 2e70c63ae7 | |||
| c67ce47026 | |||
|
|
0bac7eaf3a | ||
|
|
5b0ce79e46 | ||
|
|
a0f5d8e57b | ||
|
|
f1a1c970e0 | ||
|
|
449684c405 | ||
|
|
da5ef76c81 | ||
|
|
8752132012 | ||
|
|
fb162ca195 | ||
|
|
b33fe94cee |
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"tabWidth": 2
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
obsws (0.0.3)
|
||||
obsws (0.1.3)
|
||||
observer (~> 0.1.1)
|
||||
waitutil (~> 0.2.1)
|
||||
websocket-driver (~> 0.7.5)
|
||||
|
||||
13
README.md
13
README.md
@@ -115,6 +115,19 @@ If a request fails an `OBSWSError` will be raised with a status code.
|
||||
|
||||
For a full list of status codes refer to [Codes](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatus)
|
||||
|
||||
### Logging
|
||||
|
||||
To see the raw messages set log level to debug
|
||||
|
||||
example:
|
||||
|
||||
```ruby
|
||||
require "obsws"
|
||||
|
||||
OBSWS::LOGGER.debug!
|
||||
...
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
To run all tests:
|
||||
|
||||
14
Rakefile
14
Rakefile
@@ -1,5 +1,7 @@
|
||||
require "minitest/test_task"
|
||||
|
||||
HERE = File.expand_path File.dirname(__FILE__)
|
||||
|
||||
Minitest::TestTask.create(:test) do |t|
|
||||
t.libs << "test"
|
||||
t.warning = false
|
||||
@@ -7,3 +9,15 @@ Minitest::TestTask.create(:test) do |t|
|
||||
end
|
||||
|
||||
task default: :test
|
||||
task :events do
|
||||
filepath = File.join(HERE, "examples", "events", "main.rb")
|
||||
ruby filepath
|
||||
end
|
||||
task :levels do
|
||||
filepath = File.join(HERE, "examples", "levels", "main.rb")
|
||||
ruby filepath
|
||||
end
|
||||
task :scene_rotate do
|
||||
filepath = File.join(HERE, "examples", "scene_rotate", "main.rb")
|
||||
ruby filepath
|
||||
end
|
||||
|
||||
@@ -4,6 +4,6 @@ source "https://rubygems.org"
|
||||
|
||||
# gem "rails"
|
||||
|
||||
gem "perfect_toml", "~> 0.9.0"
|
||||
|
||||
gem "obsws", path: "../.."
|
||||
|
||||
gem "perfect_toml", "~> 0.9.0"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: ../..
|
||||
specs:
|
||||
obsws (0.0.2)
|
||||
obsws (0.1.0)
|
||||
observer (~> 0.1.1)
|
||||
waitutil (~> 0.2.1)
|
||||
websocket-driver (~> 0.7.5)
|
||||
@@ -24,4 +24,4 @@ DEPENDENCIES
|
||||
perfect_toml (~> 0.9.0)
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.24
|
||||
2.3.22
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require "obsws"
|
||||
require "perfect_toml"
|
||||
|
||||
OBSWS::LOGGER.debug!
|
||||
OBSWS::LOGGER.info!
|
||||
|
||||
class Observer
|
||||
attr_reader :running
|
||||
|
||||
53
examples/levels/main.rb
Normal file
53
examples/levels/main.rb
Normal file
@@ -0,0 +1,53 @@
|
||||
require "obsws"
|
||||
require "perfect_toml"
|
||||
|
||||
OBSWS::LOGGER.info!
|
||||
DEVICE = "Desktop Audio"
|
||||
|
||||
module LevelTypes
|
||||
VU = 0
|
||||
POSTFADER = 1
|
||||
PREFADER = 2
|
||||
end
|
||||
|
||||
class Observer
|
||||
attr_reader :running
|
||||
|
||||
def initialize(**kwargs)
|
||||
kwargs[:subs] = OBSWS::Events::SUBS::LOW_VOLUME | OBSWS::Events::SUBS::INPUTVOLUMEMETERS
|
||||
@e_client = OBSWS::Events::Client.new(**kwargs)
|
||||
@e_client.add_observer(self)
|
||||
end
|
||||
|
||||
def on_input_mute_state_changed(data)
|
||||
"""An input's mute state has changed."""
|
||||
if data.input_name == DEVICE
|
||||
puts "#{DEVICE} mute toggled"
|
||||
end
|
||||
end
|
||||
|
||||
def on_input_volume_meters(data)
|
||||
def fget(x) = x > 0 ? (20 * Math.log(x, 10)).round(1) : -200.0
|
||||
|
||||
data.inputs.each do |d|
|
||||
name = d[:inputName]
|
||||
if name == DEVICE && !d[:inputLevelsMul].empty?
|
||||
left, right = d[:inputLevelsMul]
|
||||
puts "#{name} [L: #{fget(left[LevelTypes::POSTFADER])}, R: #{fget(right[LevelTypes::POSTFADER])}]"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def conn_from_toml
|
||||
PerfectTOML.load_file("obs.toml", symbolize_names: true)[:connection]
|
||||
end
|
||||
|
||||
def main
|
||||
o = Observer.new(**conn_from_toml)
|
||||
|
||||
puts "press <Enter> to quit"
|
||||
loop { exit if gets.chomp.empty? }
|
||||
end
|
||||
|
||||
main if $0 == __FILE__
|
||||
9
examples/scene_rotate/Gemfile
Normal file
9
examples/scene_rotate/Gemfile
Normal file
@@ -0,0 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
# gem "rails"
|
||||
|
||||
gem "obsws", path: "../.."
|
||||
|
||||
gem "perfect_toml", "~> 0.9.0"
|
||||
27
examples/scene_rotate/Gemfile.lock
Normal file
27
examples/scene_rotate/Gemfile.lock
Normal file
@@ -0,0 +1,27 @@
|
||||
PATH
|
||||
remote: ../..
|
||||
specs:
|
||||
obsws (0.1.0)
|
||||
observer (~> 0.1.1)
|
||||
waitutil (~> 0.2.1)
|
||||
websocket-driver (~> 0.7.5)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
observer (0.1.1)
|
||||
perfect_toml (0.9.0)
|
||||
waitutil (0.2.1)
|
||||
websocket-driver (0.7.5)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
|
||||
PLATFORMS
|
||||
x64-mingw-ucrt
|
||||
|
||||
DEPENDENCIES
|
||||
obsws!
|
||||
perfect_toml (~> 0.9.0)
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.22
|
||||
22
examples/scene_rotate/main.rb
Normal file
22
examples/scene_rotate/main.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
require "obsws"
|
||||
require "perfect_toml"
|
||||
|
||||
OBSWS::LOGGER.info!
|
||||
|
||||
def conn_from_toml
|
||||
PerfectTOML.load_file("obs.toml", symbolize_names: true)[:connection]
|
||||
end
|
||||
|
||||
def main
|
||||
r_client = OBSWS::Requests::Client.new(**conn_from_toml)
|
||||
r_client.run do
|
||||
resp = r_client.get_scene_list
|
||||
resp.scenes.reverse.each do |s|
|
||||
puts "Switching to scene #{s[:sceneName]}"
|
||||
r_client.set_current_program_scene(s[:sceneName])
|
||||
sleep(0.5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main if $0 == __FILE__
|
||||
@@ -45,12 +45,12 @@ module OBSWS
|
||||
@closed = true
|
||||
end
|
||||
@driver.on :message do |msg|
|
||||
LOGGER.debug("received [#{msg}] passing to handler")
|
||||
LOGGER.debug("received: #{msg.data}")
|
||||
msg_handler(JSON.parse(msg.data, symbolize_names: true))
|
||||
end
|
||||
start_driver
|
||||
WaitUtil.wait_for_condition(
|
||||
"waiting successful identification",
|
||||
"successful identification",
|
||||
delay_sec: 0.01,
|
||||
timeout_sec: 3
|
||||
) { @identified }
|
||||
@@ -74,7 +74,7 @@ module OBSWS
|
||||
)
|
||||
end
|
||||
|
||||
def authenticate(auth = nil)
|
||||
def identify(auth)
|
||||
payload = {
|
||||
op: Mixin::OPCodes::IDENTIFY,
|
||||
d: {
|
||||
@@ -82,21 +82,21 @@ module OBSWS
|
||||
eventSubscriptions: @subs
|
||||
}
|
||||
}
|
||||
payload[:d][:authentication] = auth_token(**auth) if auth
|
||||
if auth
|
||||
if @password.empty?
|
||||
raise OBSWSError("auth enabled but no password provided")
|
||||
end
|
||||
LOGGER.info("initiating authentication")
|
||||
payload[:d][:authentication] = auth_token(**auth)
|
||||
end
|
||||
@driver.text(JSON.generate(payload))
|
||||
end
|
||||
|
||||
def msg_handler(data)
|
||||
case data[:op]
|
||||
when Mixin::OPCodes::HELLO
|
||||
if data[:d].key? :authentication
|
||||
LOGGER.debug("initiating authentication")
|
||||
else
|
||||
LOGGER.debug("authentication disabled... skipping.")
|
||||
end
|
||||
authenticate(data[:d][:authentication])
|
||||
identify(data[:d][:authentication])
|
||||
when Mixin::OPCodes::IDENTIFIED
|
||||
LOGGER.debug("client succesfully identified with server")
|
||||
@identified = true
|
||||
when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE
|
||||
changed
|
||||
@@ -113,8 +113,8 @@ module OBSWS
|
||||
}
|
||||
}
|
||||
payload[:d][:requestData] = data if data
|
||||
LOGGER.debug("sending request: #{payload}")
|
||||
queued = @driver.text(JSON.generate(payload))
|
||||
LOGGER.debug("request with id #{id} queued? #{queued}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,38 +7,30 @@ module OBSWS
|
||||
module Events
|
||||
module SUBS
|
||||
NONE = 0
|
||||
GENERAL = (1 << 0)
|
||||
CONFIG = (1 << 1)
|
||||
SCENES = (1 << 2)
|
||||
INPUTS = (1 << 3)
|
||||
TRANSITIONS = (1 << 4)
|
||||
FILTERS = (1 << 5)
|
||||
OUTPUTS = (1 << 6)
|
||||
SCENEITEMS = (1 << 7)
|
||||
MEDIAINPUTS = (1 << 8)
|
||||
VENDORS = (1 << 9)
|
||||
UI = (1 << 10)
|
||||
GENERAL = 1 << 0
|
||||
CONFIG = 1 << 1
|
||||
SCENES = 1 << 2
|
||||
INPUTS = 1 << 3
|
||||
TRANSITIONS = 1 << 4
|
||||
FILTERS = 1 << 5
|
||||
OUTPUTS = 1 << 6
|
||||
SCENEITEMS = 1 << 7
|
||||
MEDIAINPUTS = 1 << 8
|
||||
VENDORS = 1 << 9
|
||||
UI = 1 << 10
|
||||
|
||||
def low_volume
|
||||
GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
|
||||
LOW_VOLUME = GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
|
||||
SCENEITEMS | MEDIAINPUTS | VENDORS | UI
|
||||
end
|
||||
|
||||
INPUTVOLUMEMETERS = (1 << 16)
|
||||
INPUTACTIVESTATECHANGED = (1 << 17)
|
||||
INPUTSHOWSTATECHANGED = (1 << 18)
|
||||
SCENEITEMTRANSFORMCHANGED = (1 << 19)
|
||||
INPUTVOLUMEMETERS = 1 << 16
|
||||
INPUTACTIVESTATECHANGED = 1 << 17
|
||||
INPUTSHOWSTATECHANGED = 1 << 18
|
||||
SCENEITEMTRANSFORMCHANGED = 1 << 19
|
||||
|
||||
def high_volume
|
||||
INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
|
||||
HIGH_VOLUME = INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
|
||||
SCENEITEMTRANSFORMCHANGED
|
||||
end
|
||||
|
||||
def all
|
||||
low_volume | high_volume
|
||||
end
|
||||
|
||||
module_function :low_volume, :high_volume, :all
|
||||
ALL = LOW_VOLUME | HIGH_VOLUME
|
||||
end
|
||||
|
||||
module Callbacks
|
||||
@@ -75,11 +67,16 @@ module OBSWS
|
||||
include Mixin::OPCodes
|
||||
|
||||
def initialize(**kwargs)
|
||||
kwargs[:subs] = SUBS.low_volume
|
||||
kwargs[:subs] ||= SUBS::LOW_VOLUME
|
||||
@base_client = Base.new(**kwargs)
|
||||
LOGGER.info("#{self} succesfully identified with server")
|
||||
@base_client.add_observer(self)
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{self.class.name.split("::").last(2).join("::")}"
|
||||
end
|
||||
|
||||
def update(op_code, data)
|
||||
if op_code == Mixin::OPCodes::EVENT
|
||||
event = data[:eventType]
|
||||
|
||||
@@ -14,16 +14,21 @@ module OBSWS
|
||||
|
||||
def initialize(**kwargs)
|
||||
@base_client = Base.new(**kwargs)
|
||||
LOGGER.info("#{self} succesfully identified with server")
|
||||
@base_client.add_observer(self)
|
||||
@response = { requestId: 0 }
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{self.class.name.split("::").last(2).join("::")}"
|
||||
end
|
||||
|
||||
def run
|
||||
yield
|
||||
ensure
|
||||
close
|
||||
WaitUtil.wait_for_condition(
|
||||
"driver has closed",
|
||||
"driver to close",
|
||||
delay_sec: 0.01,
|
||||
timeout_sec: 1
|
||||
) { @base_client.closed }
|
||||
@@ -37,7 +42,7 @@ module OBSWS
|
||||
id = rand(1..1000)
|
||||
@base_client.req(id, req, data)
|
||||
WaitUtil.wait_for_condition(
|
||||
"reponse id matches request id",
|
||||
"reponse id to match request id",
|
||||
delay_sec: 0.001,
|
||||
timeout_sec: 3
|
||||
) { @response[:requestId] == id }
|
||||
@@ -72,7 +77,10 @@ module OBSWS
|
||||
end
|
||||
|
||||
def call_vendor_request(name, type_, data = nil)
|
||||
call(requestType, requestData)
|
||||
payload = { vendorName: name, requestType: type_ }
|
||||
payload[:requestData] = data if data
|
||||
resp = call("CallVendorRequest", payload)
|
||||
Mixin::Response.new(resp, resp.keys)
|
||||
end
|
||||
|
||||
def get_hotkey_list
|
||||
@@ -256,7 +264,7 @@ module OBSWS
|
||||
end
|
||||
|
||||
def get_group_list
|
||||
resp = call("GetSceneList")
|
||||
resp = call("GetGroupList")
|
||||
Mixin::Response.new(resp, resp.keys)
|
||||
end
|
||||
|
||||
@@ -324,6 +332,7 @@ module OBSWS
|
||||
|
||||
def get_special_inputs
|
||||
resp = call("GetSpecialInputs")
|
||||
Mixin::Response.new(resp, resp.keys)
|
||||
end
|
||||
|
||||
def create_input(
|
||||
@@ -341,6 +350,7 @@ module OBSWS
|
||||
sceneItemEnabled: scene_item_enabled
|
||||
}
|
||||
resp = call("CreateInput", payload)
|
||||
Mixin::Response.new(resp, resp.keys)
|
||||
end
|
||||
|
||||
def remove_input(name)
|
||||
@@ -823,6 +833,7 @@ module OBSWS
|
||||
|
||||
def stop_record
|
||||
resp = call("StopRecord")
|
||||
Mixin::Response.new(resp, resp.keys)
|
||||
end
|
||||
|
||||
def toggle_record_pause
|
||||
|
||||
@@ -7,7 +7,7 @@ module OBSWS
|
||||
end
|
||||
|
||||
def minor
|
||||
0
|
||||
1
|
||||
end
|
||||
|
||||
def patch
|
||||
|
||||
Reference in New Issue
Block a user