mirror of
https://github.com/onyx-and-iris/obsws-ruby.git
synced 2026-04-18 13:33:31 +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
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
obsws (0.0.3)
|
obsws (0.1.3)
|
||||||
observer (~> 0.1.1)
|
observer (~> 0.1.1)
|
||||||
waitutil (~> 0.2.1)
|
waitutil (~> 0.2.1)
|
||||||
websocket-driver (~> 0.7.5)
|
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)
|
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
|
### Tests
|
||||||
|
|
||||||
To run all tests:
|
To run all tests:
|
||||||
|
|||||||
14
Rakefile
14
Rakefile
@@ -1,5 +1,7 @@
|
|||||||
require "minitest/test_task"
|
require "minitest/test_task"
|
||||||
|
|
||||||
|
HERE = File.expand_path File.dirname(__FILE__)
|
||||||
|
|
||||||
Minitest::TestTask.create(:test) do |t|
|
Minitest::TestTask.create(:test) do |t|
|
||||||
t.libs << "test"
|
t.libs << "test"
|
||||||
t.warning = false
|
t.warning = false
|
||||||
@@ -7,3 +9,15 @@ Minitest::TestTask.create(:test) do |t|
|
|||||||
end
|
end
|
||||||
|
|
||||||
task default: :test
|
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 "rails"
|
||||||
|
|
||||||
gem "perfect_toml", "~> 0.9.0"
|
|
||||||
|
|
||||||
gem "obsws", path: "../.."
|
gem "obsws", path: "../.."
|
||||||
|
|
||||||
|
gem "perfect_toml", "~> 0.9.0"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: ../..
|
remote: ../..
|
||||||
specs:
|
specs:
|
||||||
obsws (0.0.2)
|
obsws (0.1.0)
|
||||||
observer (~> 0.1.1)
|
observer (~> 0.1.1)
|
||||||
waitutil (~> 0.2.1)
|
waitutil (~> 0.2.1)
|
||||||
websocket-driver (~> 0.7.5)
|
websocket-driver (~> 0.7.5)
|
||||||
@@ -24,4 +24,4 @@ DEPENDENCIES
|
|||||||
perfect_toml (~> 0.9.0)
|
perfect_toml (~> 0.9.0)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.3.24
|
2.3.22
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
require "obsws"
|
require "obsws"
|
||||||
require "perfect_toml"
|
require "perfect_toml"
|
||||||
|
|
||||||
OBSWS::LOGGER.debug!
|
OBSWS::LOGGER.info!
|
||||||
|
|
||||||
class Observer
|
class Observer
|
||||||
attr_reader :running
|
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
|
@closed = true
|
||||||
end
|
end
|
||||||
@driver.on :message do |msg|
|
@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))
|
msg_handler(JSON.parse(msg.data, symbolize_names: true))
|
||||||
end
|
end
|
||||||
start_driver
|
start_driver
|
||||||
WaitUtil.wait_for_condition(
|
WaitUtil.wait_for_condition(
|
||||||
"waiting successful identification",
|
"successful identification",
|
||||||
delay_sec: 0.01,
|
delay_sec: 0.01,
|
||||||
timeout_sec: 3
|
timeout_sec: 3
|
||||||
) { @identified }
|
) { @identified }
|
||||||
@@ -74,7 +74,7 @@ module OBSWS
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate(auth = nil)
|
def identify(auth)
|
||||||
payload = {
|
payload = {
|
||||||
op: Mixin::OPCodes::IDENTIFY,
|
op: Mixin::OPCodes::IDENTIFY,
|
||||||
d: {
|
d: {
|
||||||
@@ -82,21 +82,21 @@ module OBSWS
|
|||||||
eventSubscriptions: @subs
|
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))
|
@driver.text(JSON.generate(payload))
|
||||||
end
|
end
|
||||||
|
|
||||||
def msg_handler(data)
|
def msg_handler(data)
|
||||||
case data[:op]
|
case data[:op]
|
||||||
when Mixin::OPCodes::HELLO
|
when Mixin::OPCodes::HELLO
|
||||||
if data[:d].key? :authentication
|
identify(data[:d][:authentication])
|
||||||
LOGGER.debug("initiating authentication")
|
|
||||||
else
|
|
||||||
LOGGER.debug("authentication disabled... skipping.")
|
|
||||||
end
|
|
||||||
authenticate(data[:d][:authentication])
|
|
||||||
when Mixin::OPCodes::IDENTIFIED
|
when Mixin::OPCodes::IDENTIFIED
|
||||||
LOGGER.debug("client succesfully identified with server")
|
|
||||||
@identified = true
|
@identified = true
|
||||||
when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE
|
when Mixin::OPCodes::EVENT, Mixin::OPCodes::REQUESTRESPONSE
|
||||||
changed
|
changed
|
||||||
@@ -113,8 +113,8 @@ module OBSWS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
payload[:d][:requestData] = data if data
|
payload[:d][:requestData] = data if data
|
||||||
|
LOGGER.debug("sending request: #{payload}")
|
||||||
queued = @driver.text(JSON.generate(payload))
|
queued = @driver.text(JSON.generate(payload))
|
||||||
LOGGER.debug("request with id #{id} queued? #{queued}")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,38 +7,30 @@ module OBSWS
|
|||||||
module Events
|
module Events
|
||||||
module SUBS
|
module SUBS
|
||||||
NONE = 0
|
NONE = 0
|
||||||
GENERAL = (1 << 0)
|
GENERAL = 1 << 0
|
||||||
CONFIG = (1 << 1)
|
CONFIG = 1 << 1
|
||||||
SCENES = (1 << 2)
|
SCENES = 1 << 2
|
||||||
INPUTS = (1 << 3)
|
INPUTS = 1 << 3
|
||||||
TRANSITIONS = (1 << 4)
|
TRANSITIONS = 1 << 4
|
||||||
FILTERS = (1 << 5)
|
FILTERS = 1 << 5
|
||||||
OUTPUTS = (1 << 6)
|
OUTPUTS = 1 << 6
|
||||||
SCENEITEMS = (1 << 7)
|
SCENEITEMS = 1 << 7
|
||||||
MEDIAINPUTS = (1 << 8)
|
MEDIAINPUTS = 1 << 8
|
||||||
VENDORS = (1 << 9)
|
VENDORS = 1 << 9
|
||||||
UI = (1 << 10)
|
UI = 1 << 10
|
||||||
|
|
||||||
def low_volume
|
LOW_VOLUME = GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
|
||||||
GENERAL | CONFIG | SCENES | INPUTS | TRANSITIONS | FILTERS | OUTPUTS |
|
|
||||||
SCENEITEMS | MEDIAINPUTS | VENDORS | UI
|
SCENEITEMS | MEDIAINPUTS | VENDORS | UI
|
||||||
end
|
|
||||||
|
|
||||||
INPUTVOLUMEMETERS = (1 << 16)
|
INPUTVOLUMEMETERS = 1 << 16
|
||||||
INPUTACTIVESTATECHANGED = (1 << 17)
|
INPUTACTIVESTATECHANGED = 1 << 17
|
||||||
INPUTSHOWSTATECHANGED = (1 << 18)
|
INPUTSHOWSTATECHANGED = 1 << 18
|
||||||
SCENEITEMTRANSFORMCHANGED = (1 << 19)
|
SCENEITEMTRANSFORMCHANGED = 1 << 19
|
||||||
|
|
||||||
def high_volume
|
HIGH_VOLUME = INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
|
||||||
INPUTVOLUMEMETERS | INPUTACTIVESTATECHANGED | INPUTSHOWSTATECHANGED |
|
|
||||||
SCENEITEMTRANSFORMCHANGED
|
SCENEITEMTRANSFORMCHANGED
|
||||||
end
|
|
||||||
|
|
||||||
def all
|
ALL = LOW_VOLUME | HIGH_VOLUME
|
||||||
low_volume | high_volume
|
|
||||||
end
|
|
||||||
|
|
||||||
module_function :low_volume, :high_volume, :all
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Callbacks
|
module Callbacks
|
||||||
@@ -75,11 +67,16 @@ module OBSWS
|
|||||||
include Mixin::OPCodes
|
include Mixin::OPCodes
|
||||||
|
|
||||||
def initialize(**kwargs)
|
def initialize(**kwargs)
|
||||||
kwargs[:subs] = SUBS.low_volume
|
kwargs[:subs] ||= SUBS::LOW_VOLUME
|
||||||
@base_client = Base.new(**kwargs)
|
@base_client = Base.new(**kwargs)
|
||||||
|
LOGGER.info("#{self} succesfully identified with server")
|
||||||
@base_client.add_observer(self)
|
@base_client.add_observer(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{self.class.name.split("::").last(2).join("::")}"
|
||||||
|
end
|
||||||
|
|
||||||
def update(op_code, data)
|
def update(op_code, data)
|
||||||
if op_code == Mixin::OPCodes::EVENT
|
if op_code == Mixin::OPCodes::EVENT
|
||||||
event = data[:eventType]
|
event = data[:eventType]
|
||||||
|
|||||||
@@ -14,16 +14,21 @@ module OBSWS
|
|||||||
|
|
||||||
def initialize(**kwargs)
|
def initialize(**kwargs)
|
||||||
@base_client = Base.new(**kwargs)
|
@base_client = Base.new(**kwargs)
|
||||||
|
LOGGER.info("#{self} succesfully identified with server")
|
||||||
@base_client.add_observer(self)
|
@base_client.add_observer(self)
|
||||||
@response = { requestId: 0 }
|
@response = { requestId: 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
"#{self.class.name.split("::").last(2).join("::")}"
|
||||||
|
end
|
||||||
|
|
||||||
def run
|
def run
|
||||||
yield
|
yield
|
||||||
ensure
|
ensure
|
||||||
close
|
close
|
||||||
WaitUtil.wait_for_condition(
|
WaitUtil.wait_for_condition(
|
||||||
"driver has closed",
|
"driver to close",
|
||||||
delay_sec: 0.01,
|
delay_sec: 0.01,
|
||||||
timeout_sec: 1
|
timeout_sec: 1
|
||||||
) { @base_client.closed }
|
) { @base_client.closed }
|
||||||
@@ -37,7 +42,7 @@ module OBSWS
|
|||||||
id = rand(1..1000)
|
id = rand(1..1000)
|
||||||
@base_client.req(id, req, data)
|
@base_client.req(id, req, data)
|
||||||
WaitUtil.wait_for_condition(
|
WaitUtil.wait_for_condition(
|
||||||
"reponse id matches request id",
|
"reponse id to match request id",
|
||||||
delay_sec: 0.001,
|
delay_sec: 0.001,
|
||||||
timeout_sec: 3
|
timeout_sec: 3
|
||||||
) { @response[:requestId] == id }
|
) { @response[:requestId] == id }
|
||||||
@@ -72,7 +77,10 @@ module OBSWS
|
|||||||
end
|
end
|
||||||
|
|
||||||
def call_vendor_request(name, type_, data = nil)
|
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
|
end
|
||||||
|
|
||||||
def get_hotkey_list
|
def get_hotkey_list
|
||||||
@@ -256,7 +264,7 @@ module OBSWS
|
|||||||
end
|
end
|
||||||
|
|
||||||
def get_group_list
|
def get_group_list
|
||||||
resp = call("GetSceneList")
|
resp = call("GetGroupList")
|
||||||
Mixin::Response.new(resp, resp.keys)
|
Mixin::Response.new(resp, resp.keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -324,6 +332,7 @@ module OBSWS
|
|||||||
|
|
||||||
def get_special_inputs
|
def get_special_inputs
|
||||||
resp = call("GetSpecialInputs")
|
resp = call("GetSpecialInputs")
|
||||||
|
Mixin::Response.new(resp, resp.keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_input(
|
def create_input(
|
||||||
@@ -341,6 +350,7 @@ module OBSWS
|
|||||||
sceneItemEnabled: scene_item_enabled
|
sceneItemEnabled: scene_item_enabled
|
||||||
}
|
}
|
||||||
resp = call("CreateInput", payload)
|
resp = call("CreateInput", payload)
|
||||||
|
Mixin::Response.new(resp, resp.keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_input(name)
|
def remove_input(name)
|
||||||
@@ -823,6 +833,7 @@ module OBSWS
|
|||||||
|
|
||||||
def stop_record
|
def stop_record
|
||||||
resp = call("StopRecord")
|
resp = call("StopRecord")
|
||||||
|
Mixin::Response.new(resp, resp.keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
def toggle_record_pause
|
def toggle_record_pause
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ module OBSWS
|
|||||||
end
|
end
|
||||||
|
|
||||||
def minor
|
def minor
|
||||||
0
|
1
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
|
|||||||
Reference in New Issue
Block a user