init resolume column by name
This commit is contained in:
parent
3a4c50f9aa
commit
9f18c78845
2 changed files with 453 additions and 0 deletions
447
Resolume Column By Name/RB Resolume Column By Name v1_0.lua
Normal file
447
Resolume Column By Name/RB Resolume Column By Name v1_0.lua
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
local base_url = 'http://localhost:8899'
|
||||
|
||||
-- Maximum amount of time an entire request may take
|
||||
local request_timeout = 3
|
||||
|
||||
-- Maximum time a single socket operation may block
|
||||
local socket_timeout = 0.01
|
||||
|
||||
-- How long to give MA3 back control between operations
|
||||
local yield_time = 0.01
|
||||
|
||||
local socket = require("socket")
|
||||
local json = require("json")
|
||||
|
||||
local columns = {}
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- UI helpers
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function show_message(title, message)
|
||||
MessageBox({
|
||||
title = title,
|
||||
message = message,
|
||||
commands = {
|
||||
{ value = 1, name = "Ok" },
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
local function show_error(message)
|
||||
ErrEcho("Resolume: " .. tostring(message))
|
||||
show_message("Resolume Error", tostring(message))
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Utility
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function yield()
|
||||
coroutine.yield(yield_time)
|
||||
end
|
||||
|
||||
|
||||
local function parse_url(url)
|
||||
local host, port, path
|
||||
|
||||
host, port, path = url:match(
|
||||
"^http://([^:/]+):(%d+)(/.*)$"
|
||||
)
|
||||
|
||||
if not host then
|
||||
host, path = url:match(
|
||||
"^http://([^/]+)(/.*)$"
|
||||
)
|
||||
|
||||
if host then
|
||||
port = 80
|
||||
end
|
||||
end
|
||||
|
||||
if not host then
|
||||
host = url:match("^http://([^/]+)$")
|
||||
|
||||
if host then
|
||||
port = 80
|
||||
path = "/"
|
||||
end
|
||||
end
|
||||
|
||||
if not host then
|
||||
return nil
|
||||
end
|
||||
|
||||
return host, tonumber(port), path
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- HTTP
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function http_request(url, method, body)
|
||||
|
||||
local host, port, path = parse_url(url)
|
||||
|
||||
if not host then
|
||||
show_error("Invalid URL: " .. tostring(url))
|
||||
return nil
|
||||
end
|
||||
|
||||
local start_time = os.clock()
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Create socket
|
||||
------------------------------------------------------------
|
||||
|
||||
local tcp, err = socket.tcp()
|
||||
|
||||
if not tcp then
|
||||
show_error("Could not create socket: " .. tostring(err))
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Each individual socket operation can block for at most
|
||||
-- socket_timeout seconds.
|
||||
tcp:settimeout(socket_timeout)
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Connect
|
||||
------------------------------------------------------------
|
||||
|
||||
local connected = false
|
||||
|
||||
while not connected do
|
||||
|
||||
local ok, connect_err = tcp:connect(host, port)
|
||||
|
||||
if ok then
|
||||
connected = true
|
||||
|
||||
elseif connect_err == "timeout" then
|
||||
-- Connection is still in progress.
|
||||
-- Give MA3 some time before trying again.
|
||||
yield()
|
||||
|
||||
else
|
||||
tcp:close()
|
||||
|
||||
show_error(
|
||||
"Connection failed: " ..
|
||||
tostring(connect_err)
|
||||
)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
if os.clock() - start_time >= request_timeout then
|
||||
tcp:close()
|
||||
|
||||
show_error("Connection timeout")
|
||||
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Construct HTTP request
|
||||
------------------------------------------------------------
|
||||
|
||||
local request =
|
||||
method .. " " .. path .. " HTTP/1.1\r\n" ..
|
||||
"Host: " .. host .. ":" .. tostring(port) .. "\r\n" ..
|
||||
"Connection: close\r\n"
|
||||
|
||||
if body then
|
||||
request =
|
||||
request ..
|
||||
"Content-Type: application/json\r\n" ..
|
||||
"Content-Length: " .. tostring(#body) .. "\r\n"
|
||||
end
|
||||
|
||||
request = request .. "\r\n"
|
||||
|
||||
if body then
|
||||
request = request .. body
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Send
|
||||
------------------------------------------------------------
|
||||
|
||||
local send_pos = 1
|
||||
|
||||
while send_pos <= #request do
|
||||
|
||||
local sent, send_err, last_pos =
|
||||
tcp:send(request, send_pos)
|
||||
|
||||
if sent then
|
||||
send_pos = sent + 1
|
||||
|
||||
elseif send_err == "timeout" then
|
||||
|
||||
if last_pos then
|
||||
send_pos = last_pos + 1
|
||||
end
|
||||
|
||||
yield()
|
||||
|
||||
else
|
||||
tcp:close()
|
||||
|
||||
show_error(
|
||||
"Send failed: " ..
|
||||
tostring(send_err)
|
||||
)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
if os.clock() - start_time >= request_timeout then
|
||||
tcp:close()
|
||||
|
||||
show_error("Send timeout")
|
||||
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Receive
|
||||
------------------------------------------------------------
|
||||
|
||||
local response = {}
|
||||
|
||||
while true do
|
||||
|
||||
local data, recv_err, partial =
|
||||
tcp:receive(4096)
|
||||
|
||||
if data then
|
||||
response[#response + 1] = data
|
||||
end
|
||||
|
||||
if partial then
|
||||
response[#response + 1] = partial
|
||||
end
|
||||
|
||||
if recv_err == "closed" then
|
||||
break
|
||||
|
||||
elseif recv_err == "timeout" then
|
||||
-- Nothing available yet.
|
||||
yield()
|
||||
|
||||
elseif recv_err then
|
||||
tcp:close()
|
||||
|
||||
show_error(
|
||||
"Receive failed: " ..
|
||||
tostring(recv_err)
|
||||
)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
if os.clock() - start_time >= request_timeout then
|
||||
tcp:close()
|
||||
|
||||
show_error("HTTP request timeout")
|
||||
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
tcp:close()
|
||||
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Parse HTTP response
|
||||
------------------------------------------------------------
|
||||
|
||||
local raw_response = table.concat(response)
|
||||
|
||||
local header_end =
|
||||
raw_response:find("\r\n\r\n", 1, true)
|
||||
|
||||
if not header_end then
|
||||
show_error("Invalid HTTP response")
|
||||
return nil
|
||||
end
|
||||
|
||||
local headers =
|
||||
raw_response:sub(1, header_end - 1)
|
||||
|
||||
local response_body =
|
||||
raw_response:sub(header_end + 4)
|
||||
|
||||
local status_code =
|
||||
tonumber(
|
||||
headers:match(
|
||||
"^HTTP/%d%.%d%s+(%d+)"
|
||||
)
|
||||
)
|
||||
|
||||
if not status_code then
|
||||
show_error("Could not determine HTTP status")
|
||||
return nil
|
||||
end
|
||||
|
||||
if status_code < 200 or status_code >= 300 then
|
||||
show_error(
|
||||
"HTTP error " ..
|
||||
tostring(status_code)
|
||||
)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
return response_body
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- JSON HTTP helpers
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function http_request_json(url, method, body)
|
||||
|
||||
local response_body =
|
||||
http_request(url, method, body)
|
||||
|
||||
if not response_body then
|
||||
return nil
|
||||
end
|
||||
|
||||
local ok, response =
|
||||
pcall(
|
||||
json.decode,
|
||||
response_body
|
||||
)
|
||||
|
||||
if not ok or type(response) ~= "table" then
|
||||
show_error(
|
||||
"JSON error decoding: " ..
|
||||
tostring(response_body)
|
||||
)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
|
||||
local function http_request_void(url, method)
|
||||
return http_request(url, method)
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Resolume
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function update_columns()
|
||||
|
||||
-- Echo("Resolume: fetching composition...")
|
||||
|
||||
local comp =
|
||||
http_request_json(
|
||||
base_url .. "/api/v1/composition",
|
||||
"GET"
|
||||
)
|
||||
|
||||
if not comp then
|
||||
return
|
||||
end
|
||||
|
||||
if not comp.columns then
|
||||
show_error(
|
||||
"Resolume response contains no columns"
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
columns = {}
|
||||
|
||||
for _, column in ipairs(comp.columns) do
|
||||
|
||||
if column.name and column.name.value then
|
||||
columns[column.name.value] = column.id
|
||||
end
|
||||
end
|
||||
|
||||
-- Echo(
|
||||
-- "Resolume columns: " ..
|
||||
-- json.encode(columns)
|
||||
-- )
|
||||
end
|
||||
|
||||
|
||||
local function connect_column(name)
|
||||
|
||||
local column_id = columns[name]
|
||||
|
||||
if not column_id then
|
||||
show_error(
|
||||
"Unknown column: " ..
|
||||
tostring(name)
|
||||
)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
http_request_void(
|
||||
base_url ..
|
||||
"/api/v1/composition/columns/by-id/" ..
|
||||
tostring(column_id) ..
|
||||
"/connect",
|
||||
|
||||
"POST"
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Plugin entry point
|
||||
----------------------------------------------------------------
|
||||
|
||||
local function main(_display, rawArgs)
|
||||
|
||||
|
||||
|
||||
if rawArgs == nil or rawArgs == "" then
|
||||
|
||||
while true do
|
||||
update_columns()
|
||||
|
||||
coroutine.yield(5)
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local columnName = rawArgs
|
||||
|
||||
if not columnName then
|
||||
show_error("No column specified")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
connect_column(columnName)
|
||||
end
|
||||
|
||||
update_columns()
|
||||
|
||||
return main
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GMA3 DataVersion="2.5.1.0">
|
||||
<UserPlugin Name="RB Resolume Column By Name v1_0" Version="1.0.0.0">
|
||||
<ComponentLua Name="[RB_Resolume_Column_By_Name_v1_0_lua]" FileName="RB_Resolume_Column_By_Name_v1_0.lua" />
|
||||
</UserPlugin>
|
||||
</GMA3>
|
||||
Loading…
Add table
Add a link
Reference in a new issue