implement announce to all displays, add favicon, enhance caching and reduce requests, better iframe handling...

This commit is contained in:
Reaby committed 2019-07-14 21:41:19 +03:00
1 parent b65124cd32
commit cac14449dd
14 files changed
+298 -179

No files matched your search

-3
View File
@@ -58,17 +58,14 @@ module.exports = {
"displays": [
{
"id": 1,
"name": "Big Screen",
"bundle": "default"
},
{
"id": 2,
"name": "Secondary Screen",
"bundle": "set1"
},
{
"id": 3,
"name": "Kiosk",
"bundle": "default"
}
+2 -1
View File
@@ -23,7 +23,8 @@
"createNew": "Create New",
"createNewSlide": "Create New Slide",
"addWebPage": "Add Web page",
"announce": "Fast Announce"
"announce": "Fast Announce",
"announceAll": "Global Announce"
},
"navs": {
"bundle": "bundle",
+2 -1
View File
@@ -23,7 +23,8 @@
"createNew": "Luo Uusi",
"createNewSlide": "Luo uusi dia",
"addWebPage": "Lisää Web-sivu",
"announce": "Ilmoita"
"announce": "Ilmoita",
"announceAll": "Ilmoita Kaikille"
},
"navs": {
"bundle": "DiaPaketti",
+12 -7
View File
@@ -206,10 +206,16 @@ class admin {
// override
socket.on('admin.override', function (data) {
try {
let view = getView(parseInt(data.displayId));
view.overrideSlide(data.json, data.png, data.duration);
view.displayCurrentSlide();
if (data.displayId === null) {
if (data.duration == null || data.duration <= 5) {
data.duration = 45;
}
dispatcher.emit("all.override", data);
} else {
let view = getView(parseInt(data.displayId));
view.overrideSlide(data.json, data.png, data.duration);
view.displayCurrentSlide();
}
} catch (err) {
cli.error("error, admin.override", err);
}
@@ -223,9 +229,8 @@ class admin {
});
socket.on('admin.dashboard.sync', function (data) {
cli.error("admin.dashboard.sync is deprecated!");
// syncDashboard(socket, 0);
// updateDashboard(socket, data.displayId);
syncDashboard(socket, data.displayId);
updateDashboard(socket, data.displayId);
});
socket.on('admin.setDisplay', function (data) {
+8
View File
@@ -65,6 +65,12 @@ class display {
* @listens event:announce
*
*/
dispatcher.on("all.override", function (data) {
self.overrideSlide(data.json, data.png, data.duration);
self.displayCurrentSlide();
});
dispatcher.on("announce", function (obj) {
// if global announce, ie screens is null
if (obj.screens == null) {
@@ -109,6 +115,7 @@ class display {
init(meta) {
this.io.emit("callback.reload");
this.changeBundle(meta.bundle);
}
@@ -127,6 +134,7 @@ class display {
this.serverOptions.currentId = bundle.enabledSlides.indexOf(this.serverOptions.currentFile);
this.serverOptions.transition = bundle.getBundleData().transition;
this.serverOptions.loop = true;
this.io.emit("callbackLoad", this.getSlideData());
this.mainLoop();
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

+55 -40
View File
@@ -44,7 +44,7 @@ $(function () {
var layer = 0;
var flvPlayer;
var doNext = false;
/** bundleData
* @see data/default/bundle.json
*
@@ -85,6 +85,7 @@ function getLayer(offset) {
/** when connected **/
socket.on('connect', function () {
socket.emit("sync");
doNext = true;
});
socket.on('callback.blackout', function (data) {
@@ -117,7 +118,10 @@ socket.on('callbackLoad', function (data) {
checkBlackout();
setBackground(data.bundleData.background);
if (checkStream(serverOptions) === false) {
nextSlide(data);
if (doNext) {
doNext = false;
nextSlide(data);
}
}
});
@@ -198,7 +202,7 @@ function checkBlackout() {
function nextSlide(data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
checkImages(data.slides);
var needWait = checkImages(data.slides);
checkTimeDisplay();
if (serverOptions.isAnnounce) {
@@ -208,17 +212,17 @@ function nextSlide(data) {
clearIFrame(getWebLayer());
clearIFrame(getWebLayer(1));
}, 2500);
$("#slider").show();
$("#slider").addClass();
$("#helperLayer").addClass("announce");
try {
var randomId = uuidv4();
var image = new Image();
image.src = "/tmp/" + serverOptions.displayId + "/?randomId=" + randomId;
image.id = randomId;
image.class = "temp";
window.f.images.push(image);
window.f.showTempImage(randomId);
getDataUri("/tmp/" + serverOptions.displayId + "/?randomId=" + randomId, randomId, function (imageId, dataUrl, image) {
image.id = imageId;
image.class = "temp";
window.f.images.push(image);
window.f.imageData.push(dataUrl);
$("#slider").show();
$("#helperLayer").addClass("announce");
window.f.showTempImage(imageId);
});
} catch (err) {
console.log(err);
}
@@ -246,7 +250,10 @@ function nextSlide(data) {
}, 2500);
$("#slider").show();
window.f.showImageById(serverOptions.currentFile, transition);
setTimeout(function () {
window.f.showImageById(serverOptions.currentFile, transition);
}, needWait ? 1000 : 50);
break;
}
}
@@ -293,9 +300,7 @@ function showBackgroundOnly() {
}
function checkStream(serverOptions) {
if (serverOptions.isStreaming && streamStarted === false) {
console.log("start stream!");
if (flvjs.isSupported()) {
var videoElement = document.getElementById('bgvid');
flvPlayer = flvjs.createPlayer({
@@ -327,6 +332,7 @@ function checkStream(serverOptions) {
flvPlayer = null;
streamStarted = false;
}
return false;
}
return false;
}
@@ -339,31 +345,30 @@ function checkStream(serverOptions) {
*/
function preloadImages(allSlides) {
window.f.clearImages();
for (var i in allSlides) {
try {
if (allSlides[i].type === "slide") {
var image = new Image();
image.src = "/render/" + serverOptions.currentBundle + "/" + allSlides[i].uuid + ".png";
image.id = allSlides[i].uuid;
window.f.images.push(image);
getDataUri("/render/" + serverOptions.currentBundle + "/" + allSlides[i].uuid + ".png", allSlides[i].uuid, function (imageId, imageData, image) {
image.id = imageId;
window.f.images.push(image);
window.f.imageData.push(imageData);
});
}
} catch (err) {
console.log(err);
}
}
window.f.setupImages();
}
function reloadImage(data) {
if (serverOptions.currentBundle === data.bundleName) {
window.f.clearImageById(data.uuid);
window.f.setupImages();
var image = new Image();
image.src = "/render/" + data.bundleName + "/" + data.uuid + ".png?" + uuidv4();
image.id = data.uuid;
window.f.images.push(image);
getDataUri("/render/" + data.bundleName + "/" + data.uuid + ".png?" + uuidv4(), data.uuid, function (imageId, imageData, image) {
image.id = imageId;
window.f.images.push(image);
window.f.imageData.push(imageData);
});
}
}
@@ -398,18 +403,20 @@ function checkImages(allSlides) {
for (var i in allIds) {
try {
if (fluxIds.indexOf(allIds[i]) < 0) {
var image = new Image();
image.src = "/render/" + serverOptions.currentBundle + "/" + allIds[i] + ".png";
image.id = allIds[i];
window.f.images.push(image);
getDataUri("/render/" + serverOptions.currentBundle + "/" + allIds[i] + ".png", allIds[i], function (imageId, imageData, image) {
image.id = imageId;
window.f.images.push(image);
window.f.imageData.push(imageData);
});
return true;
}
} catch (err) {
console.log(err);
return false;
}
}
}
return false;
}
/** Generate an uuid
@@ -431,9 +438,7 @@ function updateTimeout() {
function displayWebPage(url) {
var ifr = document.getElementById(getWebLayer());
ifr.contentWindow.location.href = url;
$("#" + getWebLayer()).addClass("fadeIn").removeClass("fadeOut");
$("#" + getWebLayer()).attr('src', url).addClass("fadeIn").removeClass("fadeOut");
$("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn");
layer++;
if (layer > 1) {
@@ -446,12 +451,22 @@ function getWebLayer(offset) {
return "webLayer" + (layer + offset) % 2;
}
function clearIFrame(elementId) {
var frame = document.getElementById(elementId);
if (frame.contentWindow.location.href !== document.location.origin + "/empty") {
frame.contentWindow.location.href = "/empty";
function clearIFrame(id) {
if ($('#' + id).attr('src') !== "/empty") {
$('#' + id).attr('src', '/empty');
}
}
function getDataUri(url, imageId, callback) {
var image = new Image();
image.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
canvas.getContext('2d').drawImage(this, 0, 0);
callback(imageId, canvas.toDataURL('image/png'), this);
};
image.src = url;
}
+68 -71
View File
@@ -26,6 +26,67 @@ $(function () {
fixImageSizes();
displayTime();
setInterval(displayTime, 1000);
// socketio callbacks
/** when connected **/
socket.on('connect', function () {
socket.emit("sync");
});
socket.on('error', function () {
$("#networkstatus").css("opacity", 1);
});
socket.on('disconnect', function () {
$("#networkstatus").css("opacity", 1);
});
socket.on('pong', function () {
updateTimeout();
});
socket.on('callback.blackout', function (data) {
serverOptions = data.serverOptions;
checkBlackout();
});
socket.on('callback.time', function (data) {
serverOptions.displayTime = data;
checkTimeDisplay();
});
/** callback Load **/
socket.on('callbackLoad', function (data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
checkBlackout();
nextSlide(data);
});
/** callback Update **/
socket.on('callback.update', function (data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
checkBlackout();
nextSlide(data);
});
socket.on('callback.reload', function () {
location.reload(true);
});
socket.on('callback.announce', function (data) {
checkBlackout();
nextSlide(data);
});
socket.on('callback.forceSlide', function (data) {
checkBlackout();
nextSlide(data);
});
});
$(window).bind("resize", function () {
@@ -39,68 +100,6 @@ function getLayer(offset) {
}
// socketio callbacks
/** when connected **/
socket.on('connect', function () {
console.log("connect, calling sync!");
socket.emit("sync");
});
socket.on('error', function () {
$("#networkstatus").css("opacity", 1);
});
socket.on('disconnect', function () {
$("#networkstatus").css("opacity", 1);
});
socket.on('pong', function () {
updateTimeout();
});
socket.on('callback.blackout', function (data) {
serverOptions = data.serverOptions;
checkBlackout();
});
socket.on('callback.time', function (data) {
serverOptions.displayTime = data;
checkTimeDisplay();
});
/** callback Load **/
socket.on('callbackLoad', function (data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
checkBlackout();
nextSlide(data);
});
/** callback Update **/
socket.on('callback.update', function (data) {
serverOptions = data.serverOptions;
bundleData = data.bundleData;
checkBlackout();
nextSlide(data);
});
socket.on('callback.reload', function () {
location.reload(true);
});
socket.on('callback.announce', function (data) {
checkBlackout();
nextSlide(data);
});
socket.on('callback.forceSlide', function (data) {
checkBlackout();
nextSlide(data);
});
/**
* Displays the local time for bottom of screen
* hh:mm
@@ -161,9 +160,9 @@ function nextSlide(data) {
$("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn");
$("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn");
setTimeout(function () {
clearIFrame(getLayer());
clearIFrame(getLayer(1));
}, 1000);
clearIFrame(getWebLayer());
clearIFrame(getWebLayer(1));
}, 1500);
$("#helperLayer").addClass("announce");
try {
@@ -307,9 +306,7 @@ function uuidv4() {
var weblayer = 0;
function displayWebPage(url) {
var ifr = document.getElementById(getWebLayer());
ifr.contentWindow.location.href = url;
$("#" + getWebLayer()).addClass("fadeIn").removeClass("fadeOut");
$("#" + getWebLayer()).attr('src', url).addClass("fadeIn").removeClass("fadeOut");
$("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn");
weblayer++;
if (weblayer > 1) {
@@ -323,8 +320,8 @@ function getWebLayer(offset) {
}
function clearIFrame(id) {
var frame = document.getElementById(id),
frameDoc = frame.contentDocument || frame.contentWindow.document;
frameDoc.documentElement.innerHTML = "";
if ($('#' + id).attr('src') !== "/empty") {
$('#' + id).attr('src', '/empty');
}
}
+27 -24
View File
@@ -546,31 +546,34 @@ function removeSelectedObjects() {
}
function cueSlide() {
if (displayId !== null) {
if (confirm('Force display of the current slide?')) {
var duration = null;
if ($.isNumeric($("#duration").val())) {
duration = parseFloat($("#duration").val());
}
var objects = canvas.getObjects('line');
for (let i in objects) {
canvas.remove(objects[i]);
}
let obj = {
json: canvas.toJSON(['id']),
png: canvas.toDataURL('png'),
displayId: displayId,
duration: duration
};
socket.emit("admin.override", obj);
drawGrid();
function cueSlide(id) {
if (id === null) {
var bool = confirm('You are about to display the current slide for ALL DISPLAYS, are you sure?')
if (bool === false) {
return;
}
} else {
alert("Can't find display to announce");
}
if (confirm('Force display of the current slide?') && bool) {
var duration = null;
if ($.isNumeric($("#duration").val())) {
duration = parseFloat($("#duration").val());
}
var objects = canvas.getObjects('line');
for (let i in objects) {
canvas.remove(objects[i]);
}
let obj = {
json: canvas.toJSON(['id']),
png: canvas.toDataURL('png'),
displayId: id,
duration: duration
};
socket.emit("admin.override", obj);
drawGrid();
}
}
+18 -22
View File
@@ -72,6 +72,7 @@ window.flux = {
this.options.transitions = newTrans;
this.images = [];
this.imageData = [];
this.imageLoadedCount = 0;
this.currentImageIndex = 0;
this.nextImageIndex = 1;
@@ -229,20 +230,18 @@ window.flux = {
this.setNextIndex(index);
// Temporarily stop the transition interval
//clearInterval(this.interval);
//this.interval = null;
// clearInterval(this.interval);
// this.interval = null;
this.setupImages();
this.transition(trans, opts);
},
showImageById: function (id, trans, opts) {
let i = 0;
for (var img of this.images) {
if (img.id === id) {
for (var i in this.images) {
if (this.images[i].id === id) {
this.showImage(i, trans, opts);
break;
}
i++;
}
this.clearTempImages();
},
@@ -257,20 +256,21 @@ window.flux = {
}
},
clearImages: function () {
delete this.images;
this.images = [];
this.imageData = [];
},
clearTempImages: function () {
for (var i in this.images) {
if (this.images[i].class === "temp") {
this.images.splice(i, 1);
this.imageData.splice(i, 1);
}
}
},
clearImageById: function (id) {
for (var i in this.images) {
if (this.images[i].id === id) {
this.imageData.splice(i, 1);
this.images.splice(i, 1);
}
}
@@ -400,29 +400,20 @@ window.flux = {
this.updateCaption();
},
setupImages: function () {
var img1 = this.getImage(this.currentImageIndex);
var img1 = this.getImageData(this.currentImageIndex);
css1 = {
'background-image': 'url("' + img1.src + '")',
'background-image': 'url("' + img1.replace(/(\r\n|\n|\r)/gm, "") + '")',
'z-index': 101,
'cursor': 'auto',
'background-repeat': 'no-repeat',
'background-size': this.options.width + "px " + this.options.height + "px"
};
// Does this image have an associated link?
if ($(img1).data('href')) {
css1.cursor = 'pointer';
this.image1.addClass('hasLink');
this.image1.data('href', $(img1).data('href'));
} else {
this.image1.removeClass('hasLink');
this.image1.data('href', null);
}
this.image1.css(css1).children().remove();
var img2 = this.getImageData(this.nextImageIndex);
this.image2.css({
'background-image': 'url("' + this.getImage(this.nextImageIndex).src + '")',
'background-image': 'url("' + img2.replace(/(\r\n|\n|\r)/gm, "") + '")',
'z-index': 100,
'background-repeat': 'no-repeat',
'background-size': this.options.width + "px " + this.options.height + "px",
@@ -470,6 +461,11 @@ window.flux = {
return this.images[index];
},
getImageData: function (index) {
index = index % this.imageData.length;
return this.imageData[index];
},
setNextIndex: function (nextIndex) {
if (nextIndex == undefined)
nextIndex = this.currentImageIndex + 1;
+10 -1
View File
@@ -24,11 +24,20 @@ module.exports = function (websocket, dispatcher) {
res.render('index', {config: config});
});
router.get('/favicon.ico', function (req, res, next) {
res.send("public/favicon.ico");
});
router.get('/display/:id/lite', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
let idx = parseInt(req.params.id);
let volume = req.params.videoVolume || 1.;
res.render('liteDisplay', {config: config, display: availableDisplays[idx], displayId: idx, videoVolume: volume});
res.render('liteDisplay', {
config: config,
display: availableDisplays[idx],
displayId: idx,
videoVolume: volume
});
});
router.get('/display/:id', function (req, res, next) {
+3 -2
View File
@@ -66,9 +66,10 @@
<div class="ui buttons">
<a href="#" onclick="save()" class="ui green button">{{ t("actions.save") }}</a>
{% if displayId != null %}
<a href="#" onclick="cueSlide()" class="ui basic teal button">{{ t("actions.announce") }}</a>
<a href="#" onclick="cueSlide(displayId)" class="ui basic teal button">{{ t("actions.announce") }}</a>
{% endif %}
<a href="#" onclick="window.close()" class="ui red button">{{ t("actions.cancel") }}</a>
<a href="#" onclick="cueSlide(null)" class="ui red button">{{ t("actions.announceAll") }}</a>
<a href="#" onclick="window.close()" class="ui button">{{ t("actions.cancel") }}</a>
</div>
</div>
</div>
+84 -2
View File
@@ -2,12 +2,18 @@
{% block header %}
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect("{{ config.serverUrl }}:{{ config.serverListenPort }}/admin");
</script>
{% endblock %}
{% block body %}
<div class="ui container">
<div class="ui basic segment">
<h1 class="ui center aligned inverted header">
{{ t ("infoscreen") }}
</h1>
<h2 class="ui center aligned inverted dividing header">{{ t("index.displays") }}</h2>
<div class="ui three stackable cards" id="displayList">
@@ -18,13 +24,89 @@
<h3 class="ui center aligned header">{{ display.name }}</h3>
</div>
<div class="extra content">
<a href="/admin?displayId={{ loop.index0 }}" class="ui small button">View</a>
<a href="/admin?displayId={{ loop.index0 }}" class="ui icon button"> <i class="wrench icon"></i></a>
<!-- Controls -->
<div class="ui inverted buttons">
<button class="ui icon button"
onclick="socket.emit('controls.previous', {displayId: parseInt({{ loop.index0 }})});">
<i class="step backward icon"></i>
</button>
<button id="play{{ loop.index0 }}" class="ui icon button"
onclick="socket.emit('controls.play', {displayId: parseInt({{ loop.index0 }})});">
<i class="play icon"></i>
</button>
<button id="pause{{ loop.index0 }}" class="ui icon button"
onclick="socket.emit('controls.pause', {displayId: parseInt({{ loop.index0 }})});">
<i class="pause icon"></i>
</button>
<button class="ui icon button"
onclick="socket.emit('controls.next', {displayId: parseInt({{ loop.index0 }})});">
<i class="step forward icon"></i>
</button>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock %}
<script>
var serverOptions = {};
var bundleData = {};
var displayCount = {{ config.displays.length }};
for (var i = 0; i < displayCount; i++) {
socket.emit('admin.dashboard.sync', {displayId: i});
}
socket.on('callback.update', function (data) {
serverOptions = data.serverOptions;
updateControls(serverOptions);
});
socket.on("callback.dashboard.sync", function (data) {
updateControls(data.serverOptions);
});
socket.on("callback.dashboard.update", function (data) {
updateControls(data.serverOptions);
});
function updateControls(serverOptions) {
var id = serverOptions.displayId;
if (serverOptions.blackout) {
$('#blackout' + id).removeClass('basic');
} else {
$('#blackout' + id).addClass('basic');
}
if (serverOptions.displayTime) {
$('#toggleTime' + id).removeClass('basic');
} else {
$('#toggleTime' + id).addClass('basic');
}
if (serverOptions.isStreaming) {
$('#stream' + id).removeClass('basic');
} else {
$('#stream' + id).addClass('basic');
}
if (serverOptions.loop) {
$('#play' + id).addClass('green');
$('#pause' + id).removeClass('orange');
} else {
$('#play' + id).removeClass('green');
$('#pause' + id).addClass('orange');
}
}
</script>
{% endblock %}
+9 -5
View File
@@ -19,13 +19,13 @@
<div id="helperLayer" class="gpu animated"></div>
<iframe id="webLayer0" class="web fsimage animated"></iframe>
<iframe id="webLayer1" class="web fsimage animated"></iframe>
<iframe id="webLayer0" scrolling="no" class="web fsimage animated"></iframe>
<iframe id="webLayer1" scrolling="no" class="web fsimage animated"></iframe>
<div id="layer0" class="fsimage gpu opacity" style="z-index: 10;">
<div id="layer0" class="fsimage gpu opacity" rel="/empty" style="z-index: 10;">
<img id="img0" style="width: 100%;"/>
</div>
<div id="layer1" class="fsimage gpu opacity" style="z-index: 10;">
<div id="layer1" class="fsimage gpu opacity" rel="/empty" style="z-index: 10;">
<img id="img1" style="width: 100%;"/>
</div>
@@ -40,9 +40,13 @@
</video>
<script>
var socket = io.connect("{{ config.serverUrl }}:{{ config.serverListenPort }}/display-{{ displayId }}");
var displayId = {{ displayId }};
var videoVolume = {{ videoVolume }};
var socket = null;
$(function () {
socket = io.connect("{{ config.serverUrl }}:{{ config.serverListenPort }}/display-{{ displayId }}");
});
</script>
<script src="/js/displayLite.js"></script>
{% endblock %}