diff --git a/plugins/livestream-studio/icon.png b/plugins/livestream-studio/icon.png new file mode 100644 index 0000000..aa91358 Binary files /dev/null and b/plugins/livestream-studio/icon.png differ diff --git a/plugins/livestream-studio/img/button_green.png b/plugins/livestream-studio/img/button_green.png new file mode 100644 index 0000000..2bf0f70 Binary files /dev/null and b/plugins/livestream-studio/img/button_green.png differ diff --git a/plugins/livestream-studio/img/button_off.png b/plugins/livestream-studio/img/button_off.png new file mode 100644 index 0000000..078ebab Binary files /dev/null and b/plugins/livestream-studio/img/button_off.png differ diff --git a/plugins/livestream-studio/img/button_red.png b/plugins/livestream-studio/img/button_red.png new file mode 100644 index 0000000..e215389 Binary files /dev/null and b/plugins/livestream-studio/img/button_red.png differ diff --git a/plugins/livestream-studio/img/button_white.png b/plugins/livestream-studio/img/button_white.png new file mode 100644 index 0000000..71ac9b5 Binary files /dev/null and b/plugins/livestream-studio/img/button_white.png differ diff --git a/plugins/livestream-studio/img/button_yellow.png b/plugins/livestream-studio/img/button_yellow.png new file mode 100644 index 0000000..4c34feb Binary files /dev/null and b/plugins/livestream-studio/img/button_yellow.png differ diff --git a/plugins/livestream-studio/img/tbar_bg.png b/plugins/livestream-studio/img/tbar_bg.png new file mode 100644 index 0000000..a38efdf Binary files /dev/null and b/plugins/livestream-studio/img/tbar_bg.png differ diff --git a/plugins/livestream-studio/img/tbar_handle.png b/plugins/livestream-studio/img/tbar_handle.png new file mode 100644 index 0000000..b377159 Binary files /dev/null and b/plugins/livestream-studio/img/tbar_handle.png differ diff --git a/plugins/livestream-studio/info.html b/plugins/livestream-studio/info.html new file mode 100644 index 0000000..683805d --- /dev/null +++ b/plugins/livestream-studio/info.html @@ -0,0 +1,5 @@ +

Livestream Studio Configuration

+ diff --git a/plugins/livestream-studio/main.js b/plugins/livestream-studio/main.js new file mode 100644 index 0000000..fa6eb1a --- /dev/null +++ b/plugins/livestream-studio/main.js @@ -0,0 +1,147 @@ +exports.config = { + defaultName: 'Livestream Studio', + connectionType: 'TCPsocket', + remotePort: 9923, + mayChangePort: false, + searchOptions: { + type: 'TCPport', + searchBuffer: Buffer.from(''), + testPort: 9923, + validateResponse(msg, info) { + return msg.toString().startsWith('ILCC:'); + }, + }, +}; + +exports.ready = function ready(_device) { + console.log('livestream studio ready'); + const device = _device; + device.draw(); + + setInterval(() => { + device.update('inputs', device.data); + device.update('fadeToBlack', device.data); + }, 1000); +}; + +exports.update = function update(device, _document, updateType, data) { + const document = _document; + if (updateType === 'programInput' || updateType === 'previewInput' || updateType === 'inputs') { + device.data.inputs.forEach((input) => { + if (device.data.program === input.number) { + document.getElementById(`program-input-${input.number}`).classList.add('lss-red'); + document.getElementById(`input-${input.number}`).classList.add('lss-red'); + } else { + document.getElementById(`program-input-${input.number}`).classList.remove('lss-red'); + document.getElementById(`input-${input.number}`).classList.remove('lss-red'); + } + + if (device.data.preview === input.number) { + document.getElementById(`preview-input-${input.number}`).classList.add('lss-green'); + document.getElementById(`input-${input.number}`).classList.add('lss-green'); + } else { + document.getElementById(`preview-input-${input.number}`).classList.remove('lss-green'); + document.getElementById(`input-${input.number}`).classList.remove('lss-green'); + } + }); + } else if (updateType === 'fadeToBlack') { + const ftbId = 'ftb'; + + if (device.data.fadeToBlack) { + if (document.getElementById(ftbId).classList.contains('lss-red')) { + document.getElementById(ftbId).classList.remove('lss-red'); + } else { + document.getElementById(ftbId).classList.add('lss-red'); + } + } else { + document.getElementById(ftbId).classList.remove('lss-red'); + } + } else if (updateType === 'tbar') { + const tbarId = `tbar-div`; + const tbarHandleId = `tbar-handle-div`; + if (document.getElementById(tbarId)) { + document.getElementById(tbarId).style.height = `${device.data.tBar.percent}%`; + } + if (document.getElementById(tbarHandleId)) { + document.getElementById(tbarHandleId).style.bottom = `${device.data.tBar.percent}%`; + } + + if (device.data.tBar.status === 'Automatic') { + document.getElementById(`auto`).classList.add('lss-red'); + } else { + document.getElementById(`auto`).classList.remove('lss-red'); + } + } else if (updateType === 'cut') { + document.getElementById('cut').classList.add('lss-red'); + setTimeout(() => { + document.getElementById('cut').classList.remove('lss-red'); + }, 250); + } +}; + +exports.data = function data(_device, msg) { + const device = _device; + + const packets = msg.toString().split('\n'); + + packets.forEach((packet) => { + const packetParts = packet.split(':'); + const packetType = packetParts[0]; + if (packetType === 'ILC') { + if (device.data.inputs === undefined) { + device.data.inputs = []; + } + device.data.inputs[packetParts[1]] = { + number: Number.parseInt(packetParts[1], 10) + 1, + name: packetParts[2].replaceAll('"', ''), + audio: { + level: parseFloat(packetParts[3]) / 1000, + gain: parseFloat(packetParts[4]) / 1000, + mute: packetParts[5] === '1', + solo: packetParts[6] === '1', + programLock: packetParts[7] === '1', + }, + type: packetParts[8], + }; + device.draw(); + device.update('inputs', device.data); + } else if (packetType === 'ILCC') { + if (device.data.inputCount !== undefined) { + device.data.inputs = []; + } + device.data.inputCount = Number.parseInt(packetParts[1], 10); + } else if (packetType === 'PmIS') { + device.data.program = Number.parseInt(packetParts[1], 10) + 1; + device.update('programInput', device.data); + } else if (packetType === 'PwIS') { + device.data.preview = Number.parseInt(packetParts[1], 10) + 1; + device.update('previewInput', device.data); + } else if (packetType === 'Cut') { + [device.data.preview, device.data.program] = [device.data.program, device.data.preview]; + device.update('cut'); + device.update('program', device.data); + } else if (packetType === 'FOut') { + device.data.fadeToBlack = true; + device.update('fadeToBlack', device.data); + } else if (packetType === 'FIn') { + device.data.fadeToBlack = false; + device.update('fadeToBlack', device.data); + } else if (packetType === 'TrASp' || packetType === 'TrMSp') { + if (device.data.tBar === undefined) { + device.data.tBar = {}; + } + device.data.tBar.status = packetType === 'TrASp' ? 'Automatic' : 'Manual'; + device.data.tBar.percent = Number.parseInt(packetParts[1], 10) / 10; + if (device.data.tBar.percent === 0) { + device.data.tBar.status = 'Stop'; + } + device.update('tbar', device.data); + } else if (packetType === 'TrAStart' || packetType === 'TrAStop') { + device.data.tBar.status = packetType.slice(3); + if (packetType === 'TrAStop') { + device.data.tBar.percent = 0; + } + device.update('tbar', device.data); + } + }); +}; diff --git a/plugins/livestream-studio/styles.css b/plugins/livestream-studio/styles.css new file mode 100644 index 0000000..c242184 --- /dev/null +++ b/plugins/livestream-studio/styles.css @@ -0,0 +1,159 @@ +body { + background-color: #282828; +} +h1 { + font-family: 'Open Sans', sans-serif; +} +h3 { + color: #6d6d6d !important; + margin: 30px 0px 10px 9px; + font-size: 0.9em; + font-weight: 400; + font-family: 'Open Sans', sans-serif; +} + +.lss-input { + width: 52px; + height: 52px; + background-image: url('img/button_white.png'); +} + +.source-wrapper { + display: flex; + flex-wrap: wrap; + background-color: #1f1f1f; + border: #1a1a1a 2px solid; + border-radius: 8px; + max-width: 416px; + padding: 12px; +} + +.lss-red { + background-image: url('img/button_red.png'); + box-shadow: 0px 0px 10px 1px #ff0000; + z-index: 10000; +} + +.lss-green { + background-image: url('img/button_green.png'); + box-shadow: 0px 0px 10px 1px #06c300; + z-index: 10000; +} + +.lss-yellow { + background-image: url('img/button_yellow.png'); + box-shadow: 0px 0px 10px 1px #c7ca00; + z-index: 10000; +} + +.lss-disabled { + background-image: url('img/button_off.png'); + color: #3a3a3a; +} + +.lss-gray { + color: #575757; +} + +.source-label { + display: flex; + align-items: center; + justify-content: center; + height: 100%; + font-size: 11px; + font-weight: bold; +} + +.transition-container { + display: flex; + flex-wrap: wrap; + justify-content: space-between; +} + +.transition-settings { + display: flex; + flex-direction: column; + justify-content: space-between; + margin-right: 30px; +} + +.tbar-container { + display: flex; + flex-direction: column-reverse; + background-color: #1f1f1f; + border: 2px solid; + border-color: #1a1a1a; + border-radius: 6px; + width: 88px; + height: 429px; + position: relative; + margin-top: 58px; + margin-right: 60px; +} + +.tbar-bg { + position: absolute; + background-image: url('img/tbar_bg.png'); + width: 88px; + height: 429px; +} +.tbar-handle { + position: absolute; + background-image: url('img/tbar_handle.png'); + width: 126px; + height: 50px; + left: -3px; +} +.tbar-div { + width: 100%; + background-color: #7aff58; + overflow: hidden; +} + +.fade-to-black-container { + display: flex; + flex-direction: column; + align-items: flex-end; +} + +.fade-to-black .source-wrapper { + display: flex; + width: 100%; + padding: 5px; + justify-content: center; +} + +.fade-to-black h3 { + text-align: center; +} + +.clear { + background: transparent; + border-color: transparent; + background-color: transparent; +} + +.hide { + display: none; +} + +.no-wrap { + flex-wrap: nowrap; +} + +.show-small { + display: none; +} + +@media screen and (min-width: 0px) and (max-width: 480px) { + .hide-small { + display: none; + } + .show-small { + display: block; + } +} + +.float-left { + float: left; +} diff --git a/plugins/livestream-studio/template.ejs b/plugins/livestream-studio/template.ejs new file mode 100644 index 0000000..08a70bf --- /dev/null +++ b/plugins/livestream-studio/template.ejs @@ -0,0 +1,95 @@ +
+

<%= listName %>

+
+ +<% if (data.inputCount) { %> +
+

Preview/Program

+
+ <% data.inputs.forEach((input)=>{ %> +
+
<%= input.name %>
+
+ <% }) %> +
+
+
+
+

Program

+
+ <% data.inputs.forEach((input)=>{ %> +
+
<%= input.name %>
+
+ <% }) %> +
+
+
+

Preview

+
+ <% data.inputs.forEach((input)=>{ %> +
+
<%= input.name %>
+
+ <% }) %> +
+
+
+
+
+ + +
+

Transition Style

+
+
+
CUT
+
+
+
AUTO
+
+
+
+
+
+
+
+
+
+
+
+

Fade to Black

+
+
+
FTB
+
+
+
+
+
+<% } %>