diff --git a/plugins/lightfactory/info.html b/plugins/lightfactory/info.html new file mode 100644 index 0000000..e69de29 diff --git a/plugins/lightfactory/main.js b/plugins/lightfactory/main.js new file mode 100644 index 0000000..edbd269 --- /dev/null +++ b/plugins/lightfactory/main.js @@ -0,0 +1,99 @@ +exports.config = { + defaultName: 'LightFactory', + connectionType: 'TCPsocket', + remotePort: 3100, + mayChangePorts: true, + searchOptions: { + type: 'TCPport', + searchBuffer: Buffer.from('authenticate 1\n', 'ascii'), + testPort: 3100, + validateResponse(msg, info) { + return msg.toString().substring(0, 5) === 'Ready'; + }, + }, +}; + +exports.ready = function ready(device) { + device.data.cueLists = {}; + device.send('get cue list\n'); +}; + +function cleanMessage(message) { + return message.split('\n').filter((line) => line.trim() !== ''); +} + +// TODO(jwetzell): process updates? are they live or do we need to poll? +exports.data = function data(_device, _message) { + const message = _message.toString(); + const device = _device; + console.log(message); + + if (message.includes('Current Cue List')) { + // NOTE(jwetzell): loading cue list info + const cueListMessage = cleanMessage(message); + if (cueListMessage.includes('') && cueListMessage.includes('')) { + console.log('message is a cue list message'); + const cueListstartIndex = cueListMessage.indexOf(''); + const cueListFinishedIndex = cueListMessage.indexOf(''); + + for (let i = cueListstartIndex + 1; i < cueListFinishedIndex; i++) { + const cueListName = cueListMessage[i]; + if (device.data.cueLists[cueListName] === undefined) { + device.data.cueLists[cueListName] = { + name: cueListName, + cues: {}, + active: false, + }; + } else { + // NOTE(jwetzell): reset active as it will be computed in a few lines + device.data.cueLists[cueListName].active = false; + } + } + const activeCueListLine = cueListMessage[cueListFinishedIndex + 1]; + if (activeCueListLine) { + const activeCueListLineParts = activeCueListLine.split('Current Cue List'); + const activeCueList = activeCueListLineParts[activeCueListLineParts.length - 1].trim(); + if (activeCueList && device.data.cueLists[activeCueList] !== undefined) { + device.data.cueLists[activeCueList].active = true; + } + } + device.data.cueListToLoad = Object.keys(device.data.cueLists)[0]; + console.log(device.data.cueListToLoad); + device.send(`get cues ${device.data.cueListToLoad}\n`); + } + } else if (message.includes('Current Live Cue')) { + // NOTE(jwetzell): loading cues for a cue list + const cueList = device.data.cueLists[device.data.cueListToLoad]; + const cueListCuesMessage = cleanMessage(message); + + console.log(cueListCuesMessage); + if (cueListCuesMessage.includes('') && cueListCuesMessage.includes('')) { + console.log('message is a cue list message'); + const cuesStartIndex = cueListCuesMessage.indexOf(''); + const cuesFinishedIndex = cueListCuesMessage.indexOf(''); + for (let i = cuesStartIndex + 1; i < cuesFinishedIndex; i++) { + const cueName = cueListCuesMessage[i]; + if (cueList.cues[cueName] === undefined) { + cueList.cues[cueName] = { + name: cueName, + active: false, + }; + } else { + // NOTE(jwetzell): reset active as it will be computed in a few lines + cueList[cueName].active = false; + } + } + } + const cueListNames = Object.keys(device.data.cueLists); + + const cueListIndex = cueListNames.indexOf(device.data.cueListToLoad); + device.data.cueListToLoad = cueListNames.at(cueListIndex + 1); + if (device.data.cueListToLoad !== undefined) { + device.send(`get cues ${device.data.cueListToLoad}\n`); + } + } + device.draw(); +}; + +// TODO(jwetzell): keep alive? refresh cue list info? +exports.heartbeat = function heartbeat(device) {}; diff --git a/plugins/lightfactory/styles.css b/plugins/lightfactory/styles.css new file mode 100644 index 0000000..0fd89a2 --- /dev/null +++ b/plugins/lightfactory/styles.css @@ -0,0 +1,28 @@ +section { + background-color: #2d2d2d; + border: gray 1px solid; + padding: 10px; + padding-top: 0px; + border-radius: 10px; + overflow: hidden; +} +table { + width: 100%; + border: #414142 1px solid; + background-color: #272727; +} +table, +th, +td { + border-collapse: collapse; + color: #ccc; + font-size: 13px; +} +th { + padding: 2px 10px; +} +td { + text-align: center; + padding: 2px 7px; + font-family: 'Courier New', Courier, monospace; +} diff --git a/plugins/lightfactory/template.ejs b/plugins/lightfactory/template.ejs new file mode 100644 index 0000000..aa6feab --- /dev/null +++ b/plugins/lightfactory/template.ejs @@ -0,0 +1,31 @@ +
+

<%= listName %>

+
+ +
+ + <% Object.entries(data.cueLists).forEach(([cueListName,cueListData]) => { %> + +
+

Cue List: <%= cueListData.name %> <%= cueListData.active ? '(Active)': '' %>

+ + + + + + + + <% Object.entries(cueListData.cues).forEach(([cueName,cueData]) => { %> + + + + + + <% }); %> +
Name
<%= cueName %>
+
+ + <% + }); + %> +
\ No newline at end of file