Created
April 15, 2019 17:25
-
-
Save chrisrouse/fa070cb3dff6a813aa6903aad407b661 to your computer and use it in GitHub Desktop.
PVP transitions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var instance_skel = require('../../instance_skel'); | |
var debug; | |
var log; | |
function instance(system, id, config) { | |
var self = this; | |
// super-constructor | |
instance_skel.apply(this, arguments); | |
self.actions(); | |
return self; | |
}; | |
/** | |
* Config updated by the user. | |
*/ | |
instance.prototype.updateConfig = function(config) { | |
var self = this; | |
self.config = config; | |
self.setPvpIps(); | |
}; | |
/** | |
* Initializes the module. | |
*/ | |
instance.prototype.init = function() { | |
var self = this; | |
self.status(self.STATE_OK); | |
self.setPvpIps(); | |
debug = self.debug; | |
log = self.log; | |
self.init_presets(); | |
}; | |
/** | |
* Creates an array of PVP instances to control. | |
*/ | |
instance.prototype.setPvpIps = function() { | |
var self = this; | |
// Add the primary IP/port of PVP | |
self.arrTargets = [ | |
{ host:self.config.host, port:self.config.port } | |
]; | |
// If a backup instance was defined, add it too. | |
if (self.config.host_backup && self.config.port_backup) { | |
self.arrTargets.push( | |
{ host:self.config.host_backup, port:self.config.port_backup } | |
); | |
} | |
}; | |
/** | |
* Return config fields for web config. | |
*/ | |
instance.prototype.config_fields = function() { | |
var self = this; | |
return [ | |
{ | |
type: 'text', | |
id: 'info', | |
width: 12, | |
label: 'Information', | |
value: 'This module will control Renewed Vision PVP 3.1 or above.' | |
}, | |
{ | |
type: 'textinput', | |
id: 'host', | |
label: 'PVP IP', | |
width: 8, | |
regex: self.REGEX_IP | |
}, | |
{ | |
type: 'textinput', | |
id: 'port', | |
label: 'PVP Port', | |
width: 4, | |
regex: self.REGEX_PORT | |
}, | |
{ | |
type: 'text', | |
id: 'info', | |
width: 12, | |
label: 'Backup Instance', | |
value: "If you're running a backup instance of PVP, enter its connection details here. Leave empty to ignore." | |
}, | |
{ | |
type: 'textinput', | |
id: 'host_backup', | |
label: 'PVP IP (Backup instance)', | |
width: 8, | |
// Regex borrowed from instance_skel's REGEX_IP, but made optional | |
regex: '/^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))?$/' | |
}, | |
{ | |
type: 'textinput', | |
id: 'port_backup', | |
label: 'PVP Port (Backup instance)', | |
width: 4, | |
// Regex borrowed from instance_skel's REGEX_PORT, but made optional | |
regex: '/^(([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-4]))?$/' | |
} | |
]; | |
}; | |
/** | |
* Cleanup when the module gets deleted. | |
*/ | |
instance.prototype.destroy = function() { | |
var self = this; | |
debug("destroy"); | |
}; | |
/** | |
* Define button presets | |
*/ | |
instance.prototype.init_presets = function () { | |
var self = this; | |
var presets = [ | |
/** | |
* Presets for Layers | |
*/ | |
{ | |
category: 'Layers', | |
label: 'This button will clear the selected Layer.', | |
bank: { | |
style: 'text', | |
text: 'Clear\\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(255, 0, 0), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'clearLayer', | |
options: { | |
idx: 0, | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will mute the selected Layer.', | |
bank: { | |
style: 'text', | |
text: 'Mute\\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 153, 204), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'muteLayer', | |
options: { | |
idx: 0, | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will unmute the selected Layer.', | |
bank: { | |
style: 'text', | |
text: 'Unmute\\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 204, 0), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'unmuteLayer', | |
options: { | |
idx: 0 | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will mute and unmute the selected Layer.', | |
bank: { | |
style: 'text', | |
text: 'Mute/\\nUnmute\\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(204, 0, 204), | |
latch: true | |
}, | |
actions: [ | |
{ | |
action: 'muteLayer', | |
options: { | |
idx: 0 | |
} | |
} | |
], | |
release_actions: [ | |
{ | |
action: 'unmuteLayer', | |
options: { | |
idx: 0, | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will select and target a layer.', | |
bank: { | |
style: 'text', | |
text: 'Select \\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 0, 0), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'selectLayer', | |
options: { | |
idx: 0, | |
target: 'true', | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will hide and unhide the selected Layer.', | |
bank: { | |
style: 'text', | |
text: 'Hide/Show\\nLayer #', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 0, 0), | |
latch: true | |
}, | |
actions: [ | |
{ | |
action: 'hideLayer', | |
options: { | |
idx: 0 | |
} | |
} | |
], | |
release_actions: [ | |
{ | |
action: 'unhideLayer', | |
options: { | |
idx: 0, | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will select a Playlist.', | |
bank: { | |
style: 'text', | |
text: 'Select\\nPlaylist', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 0, 0), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'selectPL', | |
options: { | |
pl: 0, | |
} | |
} | |
] | |
}, | |
{ | |
category: 'Layers', | |
label: 'This button will trigger a Cue.', | |
bank: { | |
style: 'text', | |
text: 'Trigger\\nCue', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 0, 0), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'triggerCue', | |
options: { | |
cue: 0, | |
} | |
} | |
] | |
}, | |
/** | |
* Presets for Workspace | |
*/ | |
{ | |
category: 'Workspace', | |
label: 'This button will clear the Workspace.', | |
bank: { | |
style: 'text', | |
text: 'Clear\\nWork\\nspace', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(228, 0, 255), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'clearWs' | |
} | |
] | |
}, | |
{ | |
category: 'Workspace', | |
label: 'This button will mute the Workspace.', | |
bank: { | |
style: 'text', | |
text: 'Mute\\nWork\\nspace', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 102, 255), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'muteWs' | |
} | |
] | |
}, | |
{ | |
category: 'Workspace', | |
label: 'This button will unmute the Workspace.', | |
bank: { | |
style: 'text', | |
text: 'Unmute\\nWork\\nspace', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(0, 153, 51), | |
latch: false | |
}, | |
actions: [ | |
{ | |
action: 'unmuteWs' | |
} | |
] | |
}, | |
{ | |
category: 'Workspace', | |
label: 'This button will mute and unmute the Workspace.', | |
bank: { | |
style: 'text', | |
text: 'Mute\\nUnmute\\nWorknspace', | |
size: 'auto', | |
color: self.rgb(255, 255, 255), | |
bgcolor: self.rgb(102, 0, 102), | |
latch: true | |
}, | |
actions: [ | |
{ | |
action: 'muteWs' | |
} | |
], | |
release_actions: [ | |
{ | |
action: 'unmuteWs', | |
} | |
] | |
}, | |
]; | |
self.setPresetDefinitions(presets); | |
} | |
/** | |
* Populates the supported actions. | |
*/ | |
instance.prototype.actions = function(system) { | |
var self = this; | |
self.setActions({ | |
'clearLayer': { | |
label: 'Clear Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'muteLayer': { | |
label: 'Mute Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'unmuteLayer': { | |
label: 'Unmute Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'selectLayer': { | |
label: 'Select Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'dropdown', | |
label: 'Target Layer?', | |
id: 'target', | |
default: 'true', | |
choices: [ { id:'true', label:'Yes' }, { id:'false', label:'No' } ] | |
} | |
] | |
}, | |
'hideLayer': { | |
label: 'Hide Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'unhideLayer': { | |
label: 'Unhide Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'selectPL': { | |
label: 'Select Playlist', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Playlist ID', | |
id: 'pl', | |
default: '0' | |
} | |
] | |
}, | |
'triggerCue': { | |
label: 'Trigger Cue', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Cue ID', | |
id: 'cue', | |
default: '0' | |
} | |
] | |
}, | |
'triggerPL': { | |
label: 'Trigger Playlist', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Playlist ID', | |
id: 'pl', | |
default: '0' | |
} | |
] | |
}, | |
'triggerCuePL': { | |
label: 'Trigger Cue in Playlist', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Playlist ID', | |
id: 'pl', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Cue ID', | |
id: 'cue', | |
default: '0' | |
} | |
] | |
}, | |
'triggerCuePLLay': { | |
label: 'Trigger Cue in Playlist on Layer', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Playlist ID', | |
id: 'pl', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Cue ID', | |
id: 'cue', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
} | |
] | |
}, | |
'selectTargetSet': { | |
label: 'Layer Target Set', | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Target Set', | |
id: 'ts', | |
default: '' | |
}, | |
] | |
}, | |
'layerPreset': { | |
label: "Layer Preset", | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Preset Name', | |
id: 'lpn', | |
default: 'Preset 1' | |
} | |
] | |
}, | |
'layerEffectPreset': { | |
label: "Layer Effect Preset", | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Effect Preset Name', | |
id: 'epn', | |
default: '' | |
} | |
] | |
}, | |
'opacity': { | |
label: "Layer Opacity", | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Opacity (%)', | |
id: 'opacity', | |
default: '100', | |
regex: self.REGEX_SIGNED_NUMBER | |
} | |
] | |
}, | |
'blendMode': { | |
label: "Layer Blend Mode", | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Layer ID', | |
id: 'idx', | |
default: '0' | |
}, | |
{ | |
type: 'dropdown', | |
label: 'Blend Mode', | |
id: 'blendMode', | |
default: 'Normal', | |
choices: [ | |
{ id:'Normal', label:'Normal' }, | |
{ id:'Dissolve', label:'Dissolve' }, | |
{ id:'Darken', label:'Darken' }, | |
{ id:'Multiply', label:'Multiply' }, | |
{ id:'Color Burn', label:'Color Burn' }, | |
{ id:'Linear Burn', label:'Linear Burn' }, | |
{ id:'Darker Color', label:'Darker Color' }, | |
{ id:'Lighten', label:'Lighten' }, | |
{ id:'Screen', label:'Screen' }, | |
{ id:'Color Dodge', label:'Color Dodge' }, | |
{ id:'Linear Dodge', label:'Linear Dodge' }, | |
{ id:'Lighter Color', label:'Lighter Color' }, | |
{ id:'Overlay', label:'Overlay' }, | |
{ id:'Soft Light', label:'Soft Light' }, | |
{ id:'Hard Light', label:'Hard Light' }, | |
{ id:'Vivid Light', label:'Vivid Light' }, | |
{ id:'Linear Light', label:'Linear Light' }, | |
{ id:'Pin Light', label:'Pin Light' }, | |
{ id:'Hard Mix', label:'Hard Mix' }, | |
{ id:'Difference', label:'Difference' }, | |
{ id:'Exclusion', label:'Exclusion' }, | |
{ id:'Subtract', label:'Subtract' }, | |
{ id:'Divide', label:'Divide' }, | |
{ id:'Hue', label:'Hue' }, | |
{ id:'Saturation', label:'Saturation' }, | |
{ id:'Color', label:'Color' }, | |
{ id:'Luminosity', label:'Luminosity' }, | |
] | |
} | |
] | |
}, | |
'clearWs': { label: 'Clear Workspace'}, | |
'hideWs': { label: 'Hide Workspace'}, | |
'unhideWs': { label: 'Unhide Workspace'}, | |
'muteWs': { label: 'Mute Workspace'}, | |
'unmuteWs': { label: 'Unmute Workspace'}, | |
'workspaceEffectPreset': { | |
label: "Workspace Effect Preset", | |
options: [ | |
{ | |
type: 'textinput', | |
label: 'Effect Preset Name', | |
id: 'epn', | |
default: '' | |
} | |
] | |
}, | |
'workspaceTransition': { | |
label: 'Workspace Transition', | |
options: [ | |
{ | |
type: 'dropdown', | |
label: 'Transition', | |
id: 'transition', | |
default: 'Dissolve', | |
choices: [ | |
{ id:'Amoeba', label:'Amoeba (Scale, Duration)' }, | |
{ id:'Color Burn', label:'Color Burn (Color 1, Duration)' }, | |
{ id:'Color Push', label:'Color Push (Duration)' }, | |
{ id:'Color Warp', label:'Color Warp (Zoom, Size, Color Separation, Duration' }, | |
{ id:'Cross Hatch', label:'Cross Hatch (Duration)' }, | |
{ id:'Cube', label:'Cube (Duration)' }, | |
{ id:'Cut', label:'Cut (No options)' }, | |
{ id:'Dispersion Blur', label:'Dispersion Blur (Radius, Angle, Duration)' }, | |
{ id:'Dissolve', label:'Dissolve (Duration)' }, | |
{ id:'Door', label:'Door (Duration)' }, | |
{ id:'Fade', label:'Fade (Duration)' }, | |
{ id:'Fade Black', label:'Fade Black (Duration)' }, | |
{ id:'Fade Bright', label:'Fade Bright (Duration)' }, | |
{ id:'Fade Dark', label:'Fade Dark (Duration)' }, | |
{ id:'Fade Gray', label:'Fade Gray (Duration)' }, | |
{ id:'Fade White', label:'Fade White (Duration)' }, | |
{ id:'Film Burn', label:'Film Burn (Duration)' }, | |
{ id:'Flip', label:'Flip (Duration)' }, | |
{ id:'Fly In', label:'Fly In' }, | |
{ id:'Iris', label:'Iris' }, | |
{ id:'Kaleidoscope Wipe', label:'Kaleidoscope Wipe' }, | |
{ id:'Mosaic', label:'Mosaic' }, | |
{ id:'Move In', label:'Move In' }, | |
{ id:'Noisy Zoom', label:'Noisy Zoom' }, | |
{ id:'Push', label:'Push' }, | |
{ id:'Random Pixels', label:'Random Pixels' }, | |
{ id:'Random Squares', label:'Random Squares' }, | |
{ id:'Random Squares Flicker', label:'Random Squares Flicker' }, | |
{ id:'Reveal', label:'Reveal' }, | |
{ id:'Ripple', label:'Ripple' }, | |
{ id:'Square Wipe', label:'Square Wipe' }, | |
{ id:'Swap', label:'Swap' }, | |
{ id:'Warp Fade', label:'Warp Fade' }, | |
{ id:'Warp Dissolve', label:'Warp Dissolve' }, | |
{ id:'Warp Wipe', label:'Warp Wipe' }, | |
{ id:'Warp Zoom In', label:'Warp Zoom In' }, | |
] | |
}, | |
{ | |
type: 'textinput', | |
label: 'Duration (0.0 to 5.0)', | |
id: 'duration', | |
default: '0.5', | |
regex: self.REGEX_FLOAT_OR_INT | |
}, | |
{ | |
type: 'textinput', | |
label: 'Scale(10.0 to 40.0)', | |
id: 'scale', | |
default: '10', | |
regex: self.REGEX_FLOAT_OR_INT | |
}, | |
{ | |
type: 'textinput', | |
label: 'Color 1 (Hex)', | |
id: 'color1', | |
default: '#F0F0F0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Zoom (10.0 to 40.0)', | |
id: 'zoom', | |
default: '20.0' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Size (0.01 to 1.1)', | |
id: 'size', | |
default: '0.05' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Color Separation (0.1 to 4.1)', | |
id: 'colorSeparation', | |
default: '0.85' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Radius (0.0 to 2.0)', | |
id: 'radius', | |
default: '0.5' | |
}, | |
{ | |
type: 'textinput', | |
label: 'Angle (0.0 to 4.0)', | |
id: 'angle', | |
default: '2.3' | |
}, | |
{ | |
type: 'dropdown', | |
label: 'Fly In Direction', | |
id: 'flyInDirection', | |
default: '1', | |
choices: [ | |
{ id:'1', label:'Top Left' }, | |
{ id:'2', label:'Top' }, | |
{ id:'4', label:'Top Right' }, | |
{ id:'8', label:'Left' }, | |
{ id:'16', label:'Center' }, | |
{ id:'32', label:'Right' }, | |
{ id:'64', label:'Bottom Left' }, | |
{ id:'128', label:'Bottom' }, | |
{ id:'256', label:'Bottom Right' } | |
] | |
} | |
] | |
} | |
}); | |
}; | |
/** | |
* Retrieves information from PVP (GET) and returns a Promise. | |
* | |
* @param cmd The command to execute | |
* @param host The IP of the target PVP instance | |
* @param port The port of the target PVP instance | |
* @return A Promise that's resolved after the GET. | |
*/ | |
instance.prototype.getRest = function(cmd, host, port) { | |
var self = this; | |
return self.doRest('GET', cmd, host, port, {}); | |
}; | |
/** | |
* Commands PVP to do something (POST) and returns a Promise. | |
* | |
* @param cmd The command to execute | |
* @param host The IP of the target PVP instance | |
* @param port The port of the target PVP instance | |
* @param body The body of the POST; an object. | |
* @return A Promise that's resolved after the POST. | |
*/ | |
instance.prototype.postRest = function(cmd, host, port, body) { | |
var self = this; | |
return self.doRest('POST', cmd, host, port, body); | |
}; | |
/** | |
* Performs the REST command against PVP, either GET or POST. | |
* | |
* @param method Either GET or POST | |
* @param cmd The command to execute | |
* @param host The IP of the target PVP instance | |
* @param port The port of the target PVP instance | |
* @param body If POST, an object containing the POST's body | |
*/ | |
instance.prototype.doRest = function(method, cmd, host, port, body) { | |
var self = this; | |
var url = self.makeUrl(cmd, host, port); | |
return new Promise(function(resolve, reject) { | |
function handleResponse(err, result) { | |
if (err === null && typeof result === 'object' && result.response.statusCode === 200) { | |
// A successful response from PVP. | |
var objJson = {}; | |
if (result.data.length > 0) { | |
try { | |
objJson = JSON.parse(result.data.toString()); | |
} catch(error) { } | |
} | |
resolve([ host, port, objJson ]); | |
} else { | |
// Failure. Reject the promise. | |
var message = 'Unknown error'; | |
if (result !== undefined) { | |
if (result.response !== undefined) { | |
message = result.response.statusCode + ': ' + result.response.statusMessage; | |
} else if (result.error !== undefined) { | |
// Get the error message from the object if present. | |
message = result.error.code +': ' + result.error.message; | |
} | |
} | |
reject([ host, port, message ]); | |
} | |
} | |
switch(method) { | |
case 'POST': | |
self.system.emit('rest', url, body, function(err, result) { | |
handleResponse(err, result); | |
}); | |
break; | |
case 'GET': | |
self.system.emit('rest_get', url, function(err, result) { | |
handleResponse(err, result); | |
}); | |
break; | |
default: | |
throw new Error('Invalid method'); | |
} | |
}); | |
}; | |
/** | |
* Runs the specified action. | |
* | |
* @param action | |
*/ | |
instance.prototype.action = function(action) { | |
var self = this; | |
var opt = action.options; | |
switch (action.action) { | |
case 'clearLayer': | |
self.doCommand('/clear/layer/' + opt.idx); | |
return; | |
case 'hideLayer': | |
self.doCommand('/hide/layer/' + opt.idx); | |
return; | |
case 'muteLayer': | |
self.doCommand('/mute/layer/' + opt.idx); | |
return; | |
case 'unmuteLayer': | |
self.doCommand('/unmute/layer/' + opt.idx); | |
return; | |
case 'unhideLayer': | |
self.doCommand('/unhide/layer/' + opt.idx); | |
return; | |
case 'selectLayer': | |
// opt.target may not have been set originally. Assume true if not set | |
var target = opt.target || 'true'; | |
self.doCommand('/select/layer/' + opt.idx + '?target=' + target); | |
return; | |
case 'selectPL': | |
self.doCommand('/select/playlist/' + opt.pl); | |
return; | |
case 'triggerCue': | |
self.doCommand('/trigger/cue/' + opt.cue); | |
return; | |
case 'triggerPL': | |
self.doCommand('/trigger/playlist/' + opt.pl); | |
return; | |
case 'triggerCuePL': | |
self.doCommand('/trigger/playlist/' + opt.pl + '/cue/' + opt.cue); | |
return; | |
case 'triggerCuePLLay': | |
self.doCommand('/trigger/layer/' + opt.idx + '/playlist/' + opt.pl + '/cue/' + opt.cue); | |
return; | |
case 'clearWs': | |
self.doCommand('/clear/workspace'); | |
return; | |
case 'muteWs': | |
self.doCommand('/mute/workspace'); | |
return; | |
case 'unmuteWs': | |
self.doCommand('/unmute/workspace'); | |
return; | |
case 'hideWs': | |
self.doCommand('/hide/workspace'); | |
return; | |
case 'unhideWs': | |
self.doCommand('/unhide/workspace'); | |
return; | |
case 'selectTargetSet': | |
self.doCommand('/targetSet/layer/' + opt.idx, { value: opt.ts }); | |
return; | |
case 'layerPreset': | |
self.doCommand('/layerPreset/layer/' + opt.idx, { value: opt.lpn }); | |
return; | |
case 'layerEffectPreset': | |
self.doCommand('/effectsPreset/layer/' + opt.idx, { value: opt.epn }); | |
if (opt.epn === '') { | |
// This will clear all the effects from the layer | |
self.doCommand('/effects/layer/' + opt.idx, { }); | |
} | |
return; | |
case 'workspaceEffectPreset': | |
self.doCommand('/effectsPreset/workspace', { value: opt.epn }); | |
if (opt.epn === '') { | |
// This will clear all the effects from the workspace | |
self.doCommand('/effects/workspace/' + opt.idx, { }); | |
} | |
return; | |
case 'opacity': | |
// Opacity needs to be posted as a double. | |
if (opt.opacity[0] === '+' || opt.opacity[0] === '-') { | |
// Relative opacity. First retrieve the layer's current opacity. | |
// Do this command against the primary PVP and the backup PVP (if configured). | |
for (var i=0; i<self.arrTargets.length; i++) { | |
var target = self.arrTargets[i]; | |
self.getRest('/opacity/layer/'+opt.idx, target.host, target.port).then(function(arrResult) { | |
var host = arrResult[0]; | |
var port = arrResult[1]; | |
// Convert the current opacity from a float to a percent, and add on the | |
// relative opacity. | |
var opacity = parseFloat(arrResult[2].opacity.value) * 100; | |
self.postRest('/opacity/layer/'+opt.idx, host, port, | |
{ value: self.formatOpacity(opacity + parseInt(opt.opacity)) } | |
); | |
}).catch(function(arrResult) { | |
self.log('error', host + ':' + port + ' ' + arrResult[2]); | |
}); | |
} | |
} else { | |
// Absolute opacity. | |
self.doCommand('/opacity/layer/'+opt.idx, { value: self.formatOpacity(opt.opacity) }); | |
} | |
return; | |
case 'blendMode': | |
self.doCommand('/blendMode/layer/' + opt.idx, { value: opt.blendMode }); | |
return; | |
case 'workspaceTransition': | |
self.doCommand('/transition/workspace', { | |
"transition" : { | |
"variables" : [ | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.scale), | |
"name" : "Scale" | |
} | |
}, | |
{ | |
"type" : "Color", | |
"base" : { | |
"name" : "Burn Color", | |
"color" : opt.color1 | |
} | |
}, | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.zoom), | |
"name" : "Zoom" | |
} | |
}, | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.size), | |
"name" : "Size" | |
} | |
}, | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.colorSeparation), | |
"name" : "Color Separation" | |
} | |
}, | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.radius), | |
"name" : "Radius" | |
} | |
}, | |
{ | |
"type" : "Float", | |
"base" : { | |
"value" : parseFloat(opt.angle), | |
"name" : "Angle" | |
} | |
}, | |
{ | |
"type" : "Direction", | |
"base" : { | |
"name" : "Direction", | |
"direction": opt.flyInDirection | |
} | |
} | |
], | |
"duration" : parseFloat(opt.duration), | |
"enabled": true, | |
"name" : opt.transition | |
} | |
}); | |
return; | |
} | |
}; | |
/** | |
* Runs the [POST] command against PVP. | |
* | |
* @param cmd The command the run. Must start with '/' | |
* @param body The body of the POST content | |
*/ | |
instance.prototype.doCommand = function(cmd, body) { | |
var self = this; | |
// Do this command against the primary PVP and the backup PVP (if configured). | |
for (var i=0; i<self.arrTargets.length; i++) { | |
var target = self.arrTargets[i]; | |
self.postRest(cmd, target.host, target.port, body).then(function(objJson) { | |
// Success | |
}).catch(function(message) { | |
self.log('error', target.host + ':' + target.port + ' ' + message); | |
}); | |
} | |
}; | |
/** | |
* Changes the opacity from a whole number (0 to 100) to a double (0.0 to 1.0). | |
* | |
* @param opacity A whole number percentage from 0 to 100 | |
* @return The opacity as a double | |
*/ | |
instance.prototype.formatOpacity = function(opacity) { | |
var self = this; | |
// Force the percentage bounds and convert to a double. | |
var opacity = Math.min(100, Math.max(0, parseInt(opacity))); | |
return Math.round(opacity) / 100.0; | |
}; | |
/** | |
* Makes the complete URL. | |
* | |
* @param cmd Must start with a / | |
* @param host The IP of the PVP target | |
* @param port The port of the PVP target | |
*/ | |
instance.prototype.makeUrl = function(cmd, host, port) { | |
var self = this; | |
if (cmd[0] !== '/') { | |
throw new Error('cmd must start with a /'); | |
} | |
return 'http://' + host + ':' + port + '/api/0' + cmd; | |
}; | |
instance_skel.extendedBy(instance); | |
exports = module.exports = instance; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment