mirror of
https://github.com/stagehacks/Cue-View.git
synced 2026-08-05 22:03:41 +00:00
Merge pull request #275 from stagehacks/plugin-lightfactory
add support for LightFactory
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,136 @@
|
||||
exports.config = {
|
||||
defaultName: 'LightFactory',
|
||||
connectionType: 'TCPsocket',
|
||||
remotePort: 3100,
|
||||
mayChangePorts: true,
|
||||
heartbeatInterval: 5000,
|
||||
heartbeatTimeout: 10000,
|
||||
searchOptions: {
|
||||
type: 'TCPport',
|
||||
searchBuffer: Buffer.from('\n', 'ascii'),
|
||||
testPort: 3100,
|
||||
validateResponse(msg, info) {
|
||||
return msg.toString().includes('LightFactory');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
exports.ready = function ready(_device) {
|
||||
const device = _device;
|
||||
device.data.cueLists = {};
|
||||
device.send('get cue list\n');
|
||||
};
|
||||
|
||||
function cleanMessage(message) {
|
||||
return message.split('\n').filter((line) => line.trim() !== '');
|
||||
}
|
||||
|
||||
// TODO(jwetzell): try to grab notes?
|
||||
exports.data = function data(_device, _message) {
|
||||
const message = _message.toString();
|
||||
const device = _device;
|
||||
|
||||
if (message.includes('Current Cue List')) {
|
||||
// NOTE(jwetzell): loading cue list info
|
||||
const cueListMessage = cleanMessage(message);
|
||||
if (cueListMessage.includes('<LIST START>') && cueListMessage.includes('<LIST FINISHED>')) {
|
||||
const cueListstartIndex = cueListMessage.indexOf('<LIST START>');
|
||||
const cueListFinishedIndex = cueListMessage.indexOf('<LIST FINISHED>');
|
||||
|
||||
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];
|
||||
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);
|
||||
|
||||
// NOTE(jwetzell): this is so gross
|
||||
if (cueListCuesMessage.includes('<LIST START>') && cueListCuesMessage.includes('<LIST FINISHED>')) {
|
||||
const cuesStartIndex = cueListCuesMessage.indexOf('<LIST START>');
|
||||
const cuesFinishedIndex = cueListCuesMessage.indexOf('<LIST FINISHED>');
|
||||
|
||||
const validCueNumbers = [];
|
||||
for (let i = cuesStartIndex + 1; i < cuesFinishedIndex; i++) {
|
||||
const cueData = cueListCuesMessage[i];
|
||||
const cueSplit = cueData.indexOf(' ');
|
||||
const cueNumber = cueSplit > 0 ? cueData.substring(0, cueSplit).trim() : cueData.trim();
|
||||
const cueName = cueSplit > 0 ? cueData.substring(cueSplit + 1).trim() : '';
|
||||
cueList.cues[cueNumber] = {
|
||||
name: cueName,
|
||||
number: cueNumber,
|
||||
active: false,
|
||||
};
|
||||
validCueNumbers.push(cueNumber);
|
||||
}
|
||||
|
||||
const invalidCueNumbers = Object.keys(cueList.cues).filter((cueNumber) => !validCueNumbers.includes(cueNumber));
|
||||
|
||||
invalidCueNumbers.forEach((cueNumber) => {
|
||||
delete cueList.cues[cueNumber];
|
||||
});
|
||||
|
||||
const activeCueLine = cueListCuesMessage[cuesFinishedIndex + 1];
|
||||
if (activeCueLine) {
|
||||
const activeCueLineParts = activeCueLine.split('Current Live Cue');
|
||||
const activeCue = activeCueLineParts[activeCueLineParts.length - 1].trim();
|
||||
if (activeCue && cueList.cues[activeCue] !== undefined) {
|
||||
cueList.cues[activeCue].active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE(jwetzell): load next cue list's cues if there is one
|
||||
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`);
|
||||
}
|
||||
} else if (message.includes('Running cue') || message.includes('Goto cue')) {
|
||||
const cueUpdateMessage = message
|
||||
.trim()
|
||||
.slice(0, -1)
|
||||
.split(':')
|
||||
.map((item) => item.trim());
|
||||
if (cueUpdateMessage.length === 3) {
|
||||
const cueListName = cueUpdateMessage[1];
|
||||
const updatedCue = cueUpdateMessage[2];
|
||||
|
||||
const split = updatedCue.indexOf(' ');
|
||||
|
||||
const updatedCueNumber = split > 0 ? updatedCue.substring(0, split).trim() : updatedCue.trim();
|
||||
if (device.data.cueLists[cueListName] !== undefined) {
|
||||
Object.entries(device.data.cueLists[cueListName].cues).forEach(([cueName, cueData]) => {
|
||||
cueData.active = cueData.number === updatedCueNumber;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
device.draw();
|
||||
};
|
||||
|
||||
// TODO(jwetzell): keep alive? refresh cue list info?
|
||||
exports.heartbeat = function heartbeat(device) {
|
||||
device.send('get cue list\n');
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
section {
|
||||
background-color: #363636;
|
||||
border: gray 1px solid;
|
||||
padding: 2px;
|
||||
padding-top: 0px;
|
||||
overflow: hidden;
|
||||
font-size: 8px;
|
||||
margin-bottom: 10px;
|
||||
width: 300px;
|
||||
}
|
||||
table {
|
||||
border: #414142 1px solid;
|
||||
background-color: #272727;
|
||||
width: 100%;
|
||||
}
|
||||
table,
|
||||
th,
|
||||
td {
|
||||
border-collapse: collapse;
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
th {
|
||||
padding: 2px 10px;
|
||||
border: #282828 1px solid;
|
||||
background: linear-gradient(#404040, #363636);
|
||||
text-align: left;
|
||||
}
|
||||
td {
|
||||
text-align: left;
|
||||
padding: 7px 7px;
|
||||
font-family: sans-serif;
|
||||
position: relative;
|
||||
}
|
||||
tr {
|
||||
border-bottom: #363636 1px solid;
|
||||
}
|
||||
tr:nth-child(odd) {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background-color: #202020;
|
||||
}
|
||||
|
||||
.active_indicator {
|
||||
color: #00ff00;
|
||||
font-size: 13px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: -4px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<header>
|
||||
<h1><%= listName %></h1>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<!-- Server Loop -->
|
||||
<% Object.entries(data.cueLists).forEach(([cueListName,cueListData]) => { %>
|
||||
|
||||
<section>
|
||||
<h2>Cue List: <%= cueListData.name %> <%= cueListData.active ? '(Active)': '' %></h2>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th width="10px" style="padding: 0px;"></th>
|
||||
<th width="50px">Cue No</th>
|
||||
<th>Description</th>
|
||||
|
||||
</tr>
|
||||
<!-- Tracker Loop -->
|
||||
<% Object.entries(cueListData.cues).forEach(([cueName,cueData]) => { %>
|
||||
|
||||
<tr>
|
||||
<td style="padding: 0px;"><span class="active_indicator"><%= cueData.active ? '◢': '' %></span></td>
|
||||
<td><%= cueData.number %></td>
|
||||
<td><%= cueData.name %> </td>
|
||||
</tr>
|
||||
|
||||
<% }); %>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<%
|
||||
});
|
||||
%>
|
||||
</div>
|
||||
Reference in New Issue
Block a user