pi-rfid-jukebox/player.js

154 lines
3.4 KiB
JavaScript

const config = require('./config.json')
const glob = require('glob');
const express = require('express');
const logger = require('morgan')
const mustache = require('mustache');
const readFileSync = require('fs').readFileSync;
const children = require('./jukebox/children');
var app = express();
var server = require('http').createServer();
const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
var wss = new WebSocketServer({server: server});
var base_tpl = readFileSync(__dirname + '/source/templates/base.mustache', {encoding: 'utf8'});
var index_tpl = readFileSync(__dirname + '/source/templates/index.mustache', {encoding: 'utf8'});
var log_tpl = readFileSync(__dirname + '/source/templates/log.mustache', {encoding: 'utf8'});
mustache.parse(index_tpl),
mustache.parse(log_tpl);
var play_log = [];
children.init(config);
process.on('exit', children.exitHandler.bind(null));
process.on('SIGINT', children.exitHandler.bind(null, {exit:true}));
function setupChildLogging(name, child) {
child.on('process_error', (err) => {
console.log(`[${name}] error=${err}`);
});
child.on('close', (code, signal) => {
console.log(`[${name}] process closed:code=${code} signal=${signal}`);
});
child.on('error', (data) => {
console.log(`[${name}] stderr: ${data}`);
});
}
setupChildLogging('tagreader', children.tagreader);
setupChildLogging('mp3player', children.mp3player);
children.tagreader.on('message', (data) => {
processLine(data);
});
var last_tag = null;
var debounce_until = 0;
function lookup(tag, cb) {
if (tag === config.stop_id) {
return cb('STOP');
}
if (tag === config.pause_id) {
return cb('PAUSE', 2);
}
glob('media/' + tag + ' - *.mp3', function(er, files) {
if (files.length > 0) {
appendLog(files[0]);
return cb("LOAD " + files[0], 5);
}
appendLog(tag);
});
}
function appendLog(message) {
if (play_log.length > 10) {
play_log.pop();
}
play_log.unshift(message);
var data = {
html: mustache.render(log_tpl, { play_log: play_log }),
tag: last_tag
};
wss.broadcast(JSON.stringify(data));
}
function processLine(data) {
if (Date.now() / 1000 < debounce_until) {
return;
}
last_tag = String(data).trim();
console.log("[tag] " + last_tag);
// min 1 sec debounce
debounce_until = Date.now() / 1000 + 1;
lookup(last_tag, function(action, wait_sec) {
wait_sec = wait_sec || 1;
debounce_until = Date.now() / 1000 + wait_sec;
if (action) {
console.log(`[action] [${action}] for [${last_tag}]`);
player.stdin.write(action + "\n");
}
});
}
app.use(logger('dev'))
app.use(express.static(__dirname + '/static'))
app.get('/', function (req, res, next) {
try {
var html = mustache.render(base_tpl, {
title: 'Home'
, last_tag: last_tag
, play_log: play_log
, config: config
}, {
content: index_tpl
, log: log_tpl
})
res.send(html)
} catch (e) {
next(e)
}
});
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
wss.on('connection', function (ws) {
console.log('[websocket] client connected');
ws.on('close', function () {
console.log('[websocket] client disconnected');
});
});
server.on('request', app);
server.listen(config.port, function () {
console.log('[http] listening on http://localhost:' + config.port)
})
// vim:ts=2 sw=2 et: