diff --git a/plugins/eos/cue.ejs b/plugins/eos/cue.ejs
index e8fa4ca..e302e20 100644
--- a/plugins/eos/cue.ejs
+++ b/plugins/eos/cue.ejs
@@ -11,7 +11,9 @@
<% } %>
- <% if(isActive){ %>
+ <% if(isRunning){ %>
+
+ <% }else if(isComplete || isActive){ %>
<% }else{ %>
@@ -53,7 +55,8 @@
<%= part.prettyDuration(part.beamTimeDuration, true) %>
|
- <%= part.prettyDuration(part.duration) %> |
+ <% var durValue = (isRunning && remainingDuration !== null && remainingDuration !== undefined) ? remainingDuration : part.duration %>
+ <%= part.prettyDuration(durValue) %> |
<% }else{ %>
|
@@ -63,13 +66,23 @@
|
<% } %>
- <%= part.mark %> |
- <%= part.block %> |
- <%= part.assert %> |
-
- <%= (part.follow>=0)? "F"+part.prettyDuration(part.follow) : "" %>
- <%= (part.hang>=0)? "H"+part.prettyDuration(part.hang) : "" %>
- |
+ <%= part.mark %> |
+ <%= part.block %> |
+ <%= part.assert %> |
+ <% var followDisplay = (part.follow>=0)? "F"+part.prettyDuration(part.follow) : "" %>
+ <% var hangDisplay = (part.hang>=0)? "H"+part.prettyDuration(part.hang) : "" %>
+ <% var followHangDisplay = followDisplay + hangDisplay %>
+ <% var isFollowHangOnlyRunning = (followHangRemainingDuration !== null && followHangRemainingDuration !== undefined && followHangRemainingDuration > 0 && !isRunning) %>
+ <% if(followHangRemainingDuration !== null && followHangRemainingDuration !== undefined && followHangRemainingDuration > 0){ %>
+ <% if(part.follow >= 0){ %>
+ <% followHangDisplay = "F"+part.prettyDuration(followHangRemainingDuration) %>
+ <% }else if(part.hang >= 0 && !isRunning){ %>
+ <% followHangDisplay = "H"+part.prettyDuration(followHangRemainingDuration) %>
+ <% } %>
+ <% } %>
+
+ <%= followHangDisplay %>
+ |
<%= (partNumber==0 ? "": " ") %>
<%= part.label %>
diff --git a/plugins/eos/main.js b/plugins/eos/main.js
index f16b406..c444514 100644
--- a/plugins/eos/main.js
+++ b/plugins/eos/main.js
@@ -27,6 +27,9 @@ exports.config = {
action(_device) {
const device = _device;
device.data.cueListFilter = device.fields.cueListFilter;
+ if (device.data.EOS) {
+ subscribeToCueList(device);
+ }
device.draw();
},
},
@@ -40,10 +43,14 @@ exports.ready = function ready(_device) {
cue: _.template(fs.readFileSync(path.join(__dirname, `cue.ejs`))),
};
device.data.cueListFilter = device.fields.cueListFilter;
+ device.data.EOS.progressCueList = resolveConfiguredCueList(device);
device.send('/eos/get/cuelist/count');
device.send('/eos/get/version');
device.send('/eos/subscribe', [{ type: 'i', value: 1 }]);
+
+ // subscribe to the selected cue list specifically
+ subscribeToCueList(device);
};
exports.data = function data(_device, osc) {
@@ -80,6 +87,7 @@ exports.data = function data(_device, osc) {
device.update('cueData', {
cue: device.data.EOS.cueLists[addressParts[4]][addressParts[5]],
+ cueListNumber: addressParts[4],
cueNumber: addressParts[5],
uid: osc.args[1],
});
@@ -92,9 +100,88 @@ exports.data = function data(_device, osc) {
if (osc.args.length === 3) {
device.data.EOS.cueLists[addressParts[4]][addressParts[5]][0].extLinks = osc.args[2];
}
+ } else if (match(addressParts, ['eos', 'out', 'cuelist', '8001', '1'])) {
+ const cueListNumber = resolveConfiguredCueList(device);
+ const cueNumber = cueNumberValue(osc.args[1]);
+ const totalMs = nonNegativeInt(osc.args[6]);
+ const cueRemainingMs = nonNegativeInt(osc.args[7]);
+ const previousCueNumber = cueNumberValue(device.data.EOS.activeCueByList[cueListNumber]);
+
+ if (cueNumber !== undefined) {
+ device.data.EOS.activeCueByList[cueListNumber] = cueNumber;
+ device.data.EOS.activeCue = cueNumber;
+ }
+
+ if (cueNumber !== undefined || cueRemainingMs !== null || totalMs !== null) {
+ const progress = device.data.EOS.progressByList[cueListNumber] || {};
+ if (cueNumber !== undefined) {
+ progress.cueNumber = cueNumber;
+ }
+ if (cueRemainingMs !== null) {
+ progress.cueRemainingMs = cueRemainingMs;
+ }
+ if (totalMs !== null) {
+ progress.totalMs = totalMs;
+ }
+ device.data.EOS.progressByList[cueListNumber] = progress;
+ }
+
+ if (previousCueNumber !== undefined && previousCueNumber !== cueNumber) {
+ device.update('cueState', {
+ cueListNumber,
+ cueNumber: previousCueNumber,
+ });
+ }
+
+ if (cueNumber !== undefined) {
+ device.update('cueState', {
+ cueListNumber,
+ cueNumber,
+ });
+ }
+ } else if (match(addressParts, ['eos', 'out', 'cuelist', '8001'])) {
+ const cueListNumber = resolveConfiguredCueList(device);
+ const followHangRemainingMs = nonNegativeInt(osc.args[2]);
+ if (followHangRemainingMs !== null) {
+ const progress = device.data.EOS.progressByList[cueListNumber] || {};
+ const activeCueForList = cueNumberValue(device.data.EOS.activeCueByList[cueListNumber]);
+ if (progress.cueNumber === undefined && activeCueForList !== undefined) {
+ progress.cueNumber = activeCueForList;
+ }
+ progress.followHangRemainingMs = followHangRemainingMs;
+ device.data.EOS.progressByList[cueListNumber] = progress;
+ if (progress.cueNumber !== undefined) {
+ device.update('cueState', {
+ cueListNumber,
+ cueNumber: progress.cueNumber,
+ });
+ }
+ }
} else if (match(addressParts, ['eos', 'out', 'event', 'cue', '*', '*', 'fire'])) {
- device.data.EOS.activeCue = addressParts[5];
- device.draw();
+ const cueListNumber = cueNumberValue(addressParts[4]);
+ const cueNumber = cueNumberValue(addressParts[5]);
+ const previousCueNumber = cueNumberValue(device.data.EOS.activeCueByList[cueListNumber]);
+
+ device.data.EOS.activeCue = cueNumber;
+ device.data.EOS.activeCueByList[cueListNumber] = cueNumber;
+ device.data.EOS.progressByList[cueListNumber] = {
+ cueNumber,
+ cueRemainingMs: null,
+ followHangRemainingMs: null,
+ totalMs: null,
+ };
+
+ if (previousCueNumber !== undefined && previousCueNumber !== cueNumber) {
+ device.update('cueState', {
+ cueListNumber,
+ cueNumber: previousCueNumber,
+ });
+ }
+ device.update('cueState', {
+ cueListNumber,
+ cueNumber,
+ });
+
const cues = device.data.EOS.cueLists[addressParts[4]][addressParts[5]];
if (cues) {
device.update('activeCue', {
@@ -115,18 +202,48 @@ exports.data = function data(_device, osc) {
exports.update = function update(device, doc, updateType, data) {
if (updateType === 'cueData') {
const $elem = doc.getElementById(data.uid);
+ const cueState = cueRenderState(device, data.cueListNumber, data.cueNumber);
if ($elem) {
$elem.outerHTML = device.templates.cue({
q: data.cue,
cueNumber: data.cueNumber,
- isActive: false,
+ isActive: cueState.isComplete,
+ isComplete: cueState.isComplete,
+ isRunning: cueState.isRunning,
+ remainingDuration: cueState.remainingDuration,
+ followHangRemainingDuration: cueState.followHangRemainingDuration,
+ });
+ } else {
+ device.draw();
+ }
+ } else if (updateType === 'cueState') {
+ const cueListNumber = cueNumberValue(data.cueListNumber);
+ const cueNumber = cueNumberValue(data.cueNumber);
+ const cues = device.data.EOS.cueLists?.[cueListNumber]?.[cueNumber];
+ if (!cues || !cues[0]) {
+ device.draw();
+ return;
+ }
+ const $elem = doc.getElementById(cues[0].uid);
+ if ($elem) {
+ const cueState = cueRenderState(device, cueListNumber, cueNumber);
+ $elem.outerHTML = device.templates.cue({
+ q: cues,
+ cueNumber,
+ isActive: cueState.isComplete,
+ isComplete: cueState.isComplete,
+ isRunning: cueState.isRunning,
+ remainingDuration: cueState.remainingDuration,
+ followHangRemainingDuration: cueState.followHangRemainingDuration,
});
} else {
device.draw();
}
} else if (updateType === 'activeCue') {
const $elem = doc.getElementById(data.uid);
- $elem.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ if ($elem) {
+ $elem.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
}
};
@@ -134,6 +251,62 @@ exports.heartbeat = function heartbeat(device) {
device.send('/eos/ping');
};
+function resolveConfiguredCueList(device) {
+ const cueListFilter = cueNumberValue(device.data.cueListFilter);
+ return cueListFilter || '1';
+}
+
+function subscribeToCueList(device) {
+ const cueListNumber = resolveConfiguredCueList(device);
+ const eosState = device.data.EOS;
+ eosState.progressCueList = cueListNumber;
+ device.send(`/eos/cuelist/8001/config/${cueListNumber}/0/0`);
+}
+
+function cueRenderState(device, cueListNumber, cueNumber) {
+ const list = cueNumberValue(cueListNumber);
+ const cue = cueNumberValue(cueNumber);
+ const progress = device.data.EOS.progressByList[list];
+ const activeCue = cueNumberValue(device.data.EOS.activeCueByList[list]);
+ const cueRemainingMs = progress?.cueRemainingMs;
+ const followHangRemainingMs = progress?.followHangRemainingMs;
+ const isComplete = cue === activeCue;
+ const isRunning =
+ isComplete &&
+ progress !== undefined &&
+ cue === cueNumberValue(progress.cueNumber) &&
+ cueRemainingMs !== null &&
+ cueRemainingMs > 0;
+ const hasFollowHangCountdown = isComplete && followHangRemainingMs !== null && followHangRemainingMs > 0;
+
+ return {
+ isRunning,
+ isComplete,
+ remainingDuration: isRunning ? cueRemainingMs : null,
+ followHangRemainingDuration: hasFollowHangCountdown ? followHangRemainingMs : null,
+ };
+}
+
+function cueNumberValue(value) {
+ if (value === undefined || value === null) {
+ return undefined;
+ }
+ return `${value}`.trim();
+}
+
+function nonNegativeInt(value) {
+ if (value === undefined || value === null) {
+ return null;
+ }
+
+ const numericValue = Number(value);
+ if (!Number.isFinite(numericValue)) {
+ return null;
+ }
+
+ return Math.max(0, Math.round(numericValue));
+}
+
function match(testArray, patternArray) {
let out = true;
if (testArray.length !== patternArray.length) {
@@ -152,5 +325,8 @@ class EOS {
this.showName = '';
this.cueLists = {};
this.activeCue = undefined;
+ this.activeCueByList = {};
+ this.progressByList = {};
+ this.progressCueList = '1';
}
}
diff --git a/plugins/eos/styles.css b/plugins/eos/styles.css
index 2d3db83..2f5682d 100644
--- a/plugins/eos/styles.css
+++ b/plugins/eos/styles.css
@@ -63,6 +63,25 @@ tr.active-cue .time {
border-color: #c78b07;
}
+tr.running-cue {
+ color: #ae0009;
+}
+tr.running-cue td.num div {
+ margin: 0px;
+ padding: 1px 6px;
+ background-color: #ae0009;
+ border-radius: 4px;
+ color: white;
+}
+tr.running-cue .time {
+ border-color: #ae0009;
+}
+
+td.running-follow-hang {
+ color: #ae0009;
+ font-weight: 700;
+}
+
.list_name {
color: lightgray;
margin-left: 5px;
diff --git a/plugins/eos/template.ejs b/plugins/eos/template.ejs
index ab6873e..8c279cc 100644
--- a/plugins/eos/template.ejs
+++ b/plugins/eos/template.ejs
@@ -25,15 +25,30 @@
<% var cues = Object.keys(data.EOS.cueLists[i]).sort(function(a, b){return Number(a)-Number(b)}) %>
+ <% var activeCueByList = data.EOS.activeCueByList || {} %>
+ <% var progressByList = data.EOS.progressByList || {} %>
+ <% var activeCueNumber = (activeCueByList[i] !== undefined) ? (activeCueByList[i] + "") : undefined %>
+ <% var progressState = progressByList[i] || {} %>
+ <% var progressCueNumber = (progressState.cueNumber !== undefined && progressState.cueNumber !== null) ? (progressState.cueNumber + "") : undefined %>
+ <% var hasCueRemaining = (progressState.cueRemainingMs !== undefined && progressState.cueRemainingMs !== null) %>
+ <% var hasFollowHangRemaining = (progressState.followHangRemainingMs !== undefined && progressState.followHangRemainingMs !== null) %>
<% for(var j=0; j
<% var q = data.EOS.cueLists[i][cues[j]] %>
-
+ <% var isComplete = (activeCueNumber !== undefined && cues[j] == activeCueNumber) %>
+ <% var isRunning = isComplete && hasCueRemaining && progressCueNumber === cues[j] && progressState.cueRemainingMs > 0 %>
+ <% var remainingDuration = isRunning ? progressState.cueRemainingMs : null %>
+ <% var followHangRemainingDuration = (isComplete && !isRunning && hasFollowHangRemaining && progressState.followHangRemainingMs > 0) ? progressState.followHangRemainingMs : null %>
+
<%= templates.cue({
q: q,
cues: cues,
cueNumber: cues[j],
- isActive: (cues[j]==data.EOS.activeCue+"")
+ isActive: isComplete,
+ isComplete: isComplete,
+ isRunning: isRunning,
+ remainingDuration: remainingDuration,
+ followHangRemainingDuration: followHangRemainingDuration
}) %>
<% } %>
|