var fs = require("fs"); var pathlib = require("path"); var sendfile = require("./sendfile"); var error = require("./error"); module.exports = Slideshow; // The individual slide function Slide(dir) { var self = {}; self.dir = dir; self.name = pathlib.parse(dir).name; self.serveSlide = function(parts, res) { sendfile(res, pathlib.join(dir, "index.html")); } self.serveFiles = function(parts, res) { // Redirect to / if /{name} is requested if (parts.pathname.replace(/\//g, "") === self.name) { res.writeHead(302, { location: "/" }); return res.end(); } var name = parts.pathname.substring(1).replace(self.name, ""); sendfile(res, pathlib.join(dir, name)); } self.indexExists = function() { try { fs.accessSync(pathlib.join(dir, "index.html")); return true; } catch (err) { return false; } } try { self.meta = JSON.parse( fs.readFileSync(pathlib.join(dir, "meta.json"))); } catch (err) { if (err.code !== "ENOENT") error(err); self.meta = {}; } return self; } // The slideshow, whose job it is to manage all slides // and tell the client whether it has to update or not function Slideshow(dir, changeInterval) { var self = {}; var currentSlide = null; var awaiters = []; var slides = []; var slideIndex = 0; var nextTimeout; self.sendEvent = function(evt, args) { var str = JSON.stringify({ evt: evt, args: args }); awaiters.forEach(res => res.end(str)); awaiters = []; } // Get the current slide's interval function currentInterval() { var itv = currentSlide.meta.interval; if (itv === undefined) itv = changeInterval; return itv; } // Return if the current slide is enabled and valid function currentEnabled() { return currentSlide.indexExists() && !currentSlide.disabled; } self.getSlideName = getSlideName; function getSlideName() { return currentSlide ? currentSlide.name : "" } self.pushAwaiter = pushAwaiter; function pushAwaiter(res) { awaiters.push(res); } self.serveCurrentSlide = serveCurrentSlide; function serveCurrentSlide(parts, res) { if (currentSlide) currentSlide.serveSlide(parts, res); else error("Current slide requested while no current slide exists", res); } self.getSlides = getSlides; function getSlides() { return slides; } self.next = next; function next() { slideIndex += 1; // Go to the next slide, or restart if (slideIndex >= slides.length) { clearTimeout(nextTimeout); init(); } else { currentSlide = slides[slideIndex]; nextTimeout = setTimeout(next, currentInterval()); } // End all awaiting connections to notify slide change, if (currentEnabled()) { self.sendEvent("next", { name: currentSlide.name }); // Or go to the next slide if the current one doesn't have an index.html // or if the slide is disabled } else { clearTimeout(nextTimeout); setTimeout(next, 0); } } // This function starts the slideshow and goes through the slides // one by one. When done, it starts again by calling this function again. function init() { slides = fs.readdirSync(dir) .sort() .map(file => Slide(pathlib.join(dir, file))); slideIndex = 0; currentSlide = slides[slideIndex]; nextTimeout = setTimeout(next, currentInterval()); } init(); return self; }