From b3f860419d5d7506bae11ab2d17236e526f1982f Mon Sep 17 00:00:00 2001 From: Reaby Date: Thu, 4 Jun 2020 03:04:55 +0300 Subject: [PATCH] adding video slides support! --- locales/fi/translation.json | 10 ++- modules/admin.js | 89 +++++++++++++++++-- modules/display.js | 14 +-- public/js/dashboard.js | 9 +- public/js/display.js | 60 ++++++++++--- routes/admin.js | 11 +++ views/admin/dashboard.twig | 4 +- views/admin/video.twig | 171 ++++++++++++++++++++++++++++++++++++ 8 files changed, 339 insertions(+), 29 deletions(-) create mode 100644 views/admin/video.twig diff --git a/locales/fi/translation.json b/locales/fi/translation.json index bbc7445..f1f07c0 100644 --- a/locales/fi/translation.json +++ b/locales/fi/translation.json @@ -23,8 +23,9 @@ "displayTime": "Näytä aika", "startStream": "Aloita suoratoisto", "forceReload": "Lataa uudelleen", - "createNew": "Luo Uusi", + "createNew": "Luo Uusi", "createNewSlide": "Luo uusi dia", + "addVideo": "Lisää Video", "addWebPage": "Lisää Web-sivu", "announce": "Ilmoita", "announceAll": "Ilmoita Kaikille" @@ -94,6 +95,13 @@ "zoom": "Suurennus", "duration": "Pituus (sekunneissa), tyhjä on oletusarvo", "displayTime": "Näytä aika" + }, + "addVideo": { + "name": "Name", + "url": "url", + "displayTime": "Näytä aika", + "mute": "Mykistä video", + "loop": "Looppaa video" }, "tooltip": { "header": "Lisää otsikko", diff --git a/modules/admin.js b/modules/admin.js index cdd31dc..e444a2f 100644 --- a/modules/admin.js +++ b/modules/admin.js @@ -221,10 +221,20 @@ class admin { } dispatcher.emit("all.override", data); } else { - self.screenView.overrideSlide(data.json, data.png, data.duration, data.transition); + self.screenView.overrideSlide(data.json, null, data.duration, data.transition); } }); + socket.on('admin.overrideVideo', function (data) { + if (data.displayId === null) { + dispatcher.emit("all.override", data); + } else { + self.screenView.overrideSlide(data.json, null, data.json.duration, null); + } + }); + + + socket.on('admin.setBundle', function (data) { self.screenView.changeBundle(data.bundle); self.updateDashboard(io); @@ -288,6 +298,11 @@ class admin { } }); + socket.on("admin.setStatusMessage", function (message) { + self.getView().serverOptions.statusMessage = message; + self.getView().updateUI(); + }); + /** edit web links **/ socket.on('admin.editLink', function (data) { @@ -298,13 +313,8 @@ class admin { json = bundle.findSlideByUuid(data.fileName); } socket.emit("callback.webpage", {bundleData: bundleData, json: json}); - }); - socket.on("admin.setStatusMessage", function (message) { - self.getView().serverOptions.statusMessage = message; - self.getView().updateUI(); - }); socket.on('edit.saveLink', function (data) { @@ -357,6 +367,73 @@ class admin { } }); + /** video **/ + + socket.on('admin.editVideo', function (data) { + let bundle = self.bundleManager.getBundle(data.bundleName); + let bundleData = bundle.getBundleData(); + let json = "{}"; + if (data.fileName) { + json = bundle.findSlideByUuid(data.fileName); + } + socket.emit("callback.video", {bundleData: bundleData, json: json}); + }); + + + socket.on('edit.saveVideo', function (data) { + + let filename = data.filename; + if (filename === "") { + filename = uuidv4(); + } + + if (data.duration === "") { + socket.emit("callback.saveVideo", {erro: "Video duration is not known. Remember to load metadata!"}); + return; + } + + try { + let bundle = self.bundleManager.getBundle(data.bundleName); + + let template = { + uuid: filename, + name: data.name, + duration: data.duration, + enabled: true, + displayTime: data.displayTime, + type: "video", + webUrl: data.url, + mute: data.mute, + loop: data.loop, + index: bundle.allSlides.length, + transition: null + }; + + let obj = bundle.findSlideByUuid(filename); + if (Object.keys(obj).length === 0 && obj.constructor === Object) { + bundle.allSlides.push(template); + } else { + obj.url = data.url; + obj.name = data.name; + obj.duration = data.duration; + obj.displayTime = data.displayTime; + obj.mute = data.mute; + obj.loop = data.loop; + obj.transition = null; + } + + bundle.save(); + + cli.success("save video link"); + socket.emit("callback.saveVideo", {}); + self.updateSlides(); + + } catch (err) { + cli.error(err, "save video link"); + socket.emit("callback.saveVideo", {error: err}); + } + }); + /** edit **/ socket.on('admin.editSlide', function (data) { diff --git a/modules/display.js b/modules/display.js index 4c83542..1499877 100644 --- a/modules/display.js +++ b/modules/display.js @@ -158,7 +158,7 @@ class display { getSlideData() { let bundle = this.getBundle(); - return {bundleData: bundle.getBundleData(), slides: bundle.allSlides, serverOptions: this.serverOptions}; + return { bundleData: bundle.getBundleData(), slides: bundle.allSlides, serverOptions: this.serverOptions }; } /** @@ -177,7 +177,7 @@ class display { toggleBlackout() { this.serverOptions.blackout = this.serverOptions.blackout === false; - this.io.emit("callback.blackout", {serverOptions: this.serverOptions}); + this.io.emit("callback.blackout", { serverOptions: this.serverOptions }); } /** @@ -191,7 +191,7 @@ class display { /** * @event event:announce */ - this.dispatcher.emit("announce", {screens: screens, event: event, data: data}); + this.dispatcher.emit("announce", { screens: screens, event: event, data: data }); } /** @@ -254,18 +254,20 @@ class display { fs.writeFileSync("./tmp/display_" + this.serverOptions.displayId + ".png", pngData.replace(/^data:image\/png;base64,/, ""), "base64"); } - if (duration && duration >= 5) { + if (duration && duration >= 5 && + (json.type === "video" && json.loop === false) + ) { this.serverOptions.loop = true; this.timeoutId = setTimeout(this.mainLoop.bind(this), duration * 1000); } this.displayCurrentSlide(); this.serverOptions.transition = _transition; } - + updateUI() { this.io.emit("callback.updateUI", this.getSlideData()); } - + displayCurrentSlide() { this.announce([this.id, "admin"], "callback.update", this.getSlideData()); } diff --git a/public/js/dashboard.js b/public/js/dashboard.js index dd26972..41e1629 100644 --- a/public/js/dashboard.js +++ b/public/js/dashboard.js @@ -192,7 +192,7 @@ $(window).bind("resize", function () { fixPreview(); }); -function createNew() { +function createNewSlide() { editSlide("", "slide"); } @@ -200,6 +200,10 @@ function addLink() { editSlide("", "webpage"); } +function createNewVideo() { + editSlide("", "video"); +} + function editSlide(name, type) { switch (type) { case "slide": @@ -208,6 +212,9 @@ function editSlide(name, type) { case "webpage": window.open("/admin/edit/link?bundle=" + serverOptions.currentBundle + "&file=" + name + "&displayId=" + displayId, '_blank', 'location=no,height=400,width=600,scrollbars=no,status=no'); break; + case "video": + window.open("/admin/edit/video?bundle=" + serverOptions.currentBundle + "&file=" + name + "&displayId=" + displayId, '_blank', 'location=no,height=600,width=600,scrollbars=no,status=no'); + break; } } diff --git a/public/js/display.js b/public/js/display.js index bf85004..4b3c9a9 100644 --- a/public/js/display.js +++ b/public/js/display.js @@ -73,26 +73,26 @@ $(window).bind("resize", function () { }); if (isPreview === 0) { - document.addEventListener("keydown", function(e) { + document.addEventListener("keydown", function (e) { if (e.keyCode == 13) { toggleFullScreen(); } }, false); } -function toggleFullScreen() { +function toggleFullScreen() { if (isPreview === 0) { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } else { if (document.exitFullscreen) { - document.exitFullscreen(); + document.exitFullscreen(); } } } } - - + + function getLayer(offset) { if (offset === undefined) offset = 0; @@ -228,13 +228,23 @@ function updateStatusMessage() { $('#statusMessage').text(""); } } +function displayVideo(url, loop, mute) { + if (serverOptions.isStreaming) return; + $("#stream").show(); + let video = document.getElementById("stream"); + video.src = url; + video.loop = loop; + video.volume = mute ? 0.0 : 1.0; + video.load(); + video.play(); +} function nextSlide(data) { serverOptions = data.serverOptions; bundleData = data.bundleData; checkTimeDisplay(); updateStatusMessage(); - + if (serverOptions.isAnnounce) { if (serverOptions.announceMeta.type === "webPage") { $("#slider").hide(); @@ -248,6 +258,15 @@ function nextSlide(data) { displayWebPage(serverOptions.announceMeta.webUrl); } + if (serverOptions.announceMeta.type === "video") { + if (serverOptions.announceMeta.displayTime) { + $('#time').removeClass('flipOutX').addClass("flipInX"); + } else { + $('#time').addClass('flipOutX').removeClass("flipInX"); + } + displayVideo(serverOptions.announceMeta.url, serverOptions.announceMeta.loop, serverOptions.announceMeta.mute); + } + if (serverOptions.announceMeta.type === "image") { $("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn"); $("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn"); @@ -275,11 +294,20 @@ function nextSlide(data) { switch (serverOptions.currentMeta.type) { case "webpage": $("#slider").hide(); + let video = document.getElementById("stream"); + video.pause(); + $("#stream").hide(); $("#" + getWebLayer()).css("transform", "scale(" + serverOptions.currentMeta.zoom + ")"); $("#" + getWebLayer()).addClass("fadeIn").removeClass("fadeOut"); - displayWebPage(serverOptions.currentMeta.webUrl); break; + case "video": + displayVideo(serverOptions.currentMeta.url, serverOptions.currentMeta.loop, serverOptions.currentMeta.mute); + setTimeout(function () { + clearIFrame(getWebLayer()); + clearIFrame(getWebLayer(1)); + }, 2500); + break; default: var transition = serverOptions.transition; if (serverOptions.currentMeta.transition !== null) { @@ -288,9 +316,12 @@ function nextSlide(data) { $("#" + getWebLayer()).addClass("fadeOut").removeClass("fadeIn"); $("#" + getWebLayer(1)).addClass("fadeOut").removeClass("fadeIn"); + $("#stream").fadeOut(); $("#slider").show(); window.f.showImageById(serverOptions.currentFile, transition); setTimeout(function () { + let video = document.getElementById("stream"); + video.pause(); clearIFrame(getWebLayer()); clearIFrame(getWebLayer(1)); }, 2500); @@ -301,6 +332,7 @@ function nextSlide(data) { setBackground(bundleData.background); } + function setBackground(background) { background = encodeURI("/background/" + background); if (serverOptions.isStreaming) return; @@ -343,7 +375,7 @@ function checkStream(serverOptions) { if (serverOptions.isStreaming) { if (flvjs.isSupported()) { $("#stream").show(); - var videoElement = document.getElementById('stream'); + var videoElement = document.getElementById('stream'); flvPlayer = flvjs.createPlayer({ type: 'flv', url: serverOptions.streamSource @@ -467,7 +499,7 @@ function checkImages(allSlides) { 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); + // window.f.imageData.push(imageData); }); return true; } @@ -523,13 +555,13 @@ function clearIFrame(id) { function getDataUri(url, imageId, callback) { var image = new Image(); image.onload = function () { - // let canvas = document.createElement('canvas'); - // canvas.width = 1920; // or 'width' if you want a special/scaled size - // canvas.height = 1080; // or 'height' if you want a special/scaled size - // canvas.getContext('2d').drawImage(this, 0, 0); + // let canvas = document.createElement('canvas'); + // canvas.width = 1920; // or 'width' if you want a special/scaled size + // canvas.height = 1080; // or 'height' if you want a special/scaled size + // canvas.getContext('2d').drawImage(this, 0, 0); //callback(imageId, canvas.toDataURL('image/png'), this); callback(imageId, null, this); - // canvas = null; + // canvas = null; }; image.src = url; } diff --git a/routes/admin.js b/routes/admin.js index f77bd49..68331c8 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -181,6 +181,17 @@ module.exports = function (pluginManager, websocket, dispatcher) { }); }); + router.get('/edit/video', function (req, res, next) { + let bundle = req.query['bundle']; + let file = req.query['file']; + let displayId = req.query['displayId'] || 0; + res.render('admin/video', { + config: config, + bundle: bundle, + displayId: displayId, + file: file + }); + }); router.get('/edit/bundleSlides', function (req, res, next) { var bundle = {}; diff --git a/views/admin/dashboard.twig b/views/admin/dashboard.twig index 03a0b3f..709b44a 100644 --- a/views/admin/dashboard.twig +++ b/views/admin/dashboard.twig @@ -81,7 +81,9 @@ {{ t("admin.dashboard.slidesInRotation") }} {% if permission.dashboard.addSlides %} - + {% endif %} {% if permission.dashboard.addWebPage %} diff --git a/views/admin/video.twig b/views/admin/video.twig new file mode 100644 index 0000000..e5127f0 --- /dev/null +++ b/views/admin/video.twig @@ -0,0 +1,171 @@ +{% extends 'layout/edit.twig' %} + +{% block header %} + + +{% endblock %} + +{% block body %} +
+ + +
+
+ + +
+
+ +
+ +
Load Metadata
+
+
+ +
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
{{ t("actions.save") }}
+ +
+
{{ t("actions.announce") }}
+ +
+
{{ t("actions.cancel") }}
+
+
+ + +{% endblock %} +