pi-rfid-jukebox/player.js

200 lines
5.0 KiB
JavaScript
Raw Normal View History

"use strict";
2017-04-08 16:05:39 +00:00
const config = require('./config.json')
const library = require('./jukebox/library');
2019-12-14 21:19:06 +00:00
const ScriptRunner = require('./jukebox/scripts')(config);
const express = require('express');
const morgan = require('morgan');
const handlebars = require('express-handlebars');
2019-12-17 17:12:53 +00:00
const multer = require('multer');
const uuid = require('uuid/v4');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, config.media_path)
},
filename: function (req, file, cb) {
var track_uuid = uuid();
cb(null, track_uuid)
}
});
var upload = multer({
storage: storage,
});
2019-12-14 19:20:18 +00:00
const { createLogger, format, transports } = require('winston');
2019-12-14 21:19:06 +00:00
const { throttle } = require('throttle-debounce');
2019-12-14 19:20:18 +00:00
var logger = createLogger({
2017-04-09 17:55:11 +00:00
transports: [
2019-12-14 19:20:18 +00:00
new transports.Console()
2017-04-09 17:55:11 +00:00
]
});
logger.level = config.debug ? 'debug' : 'info';
const MediaPlayer = require('./jukebox/media-player')(config, logger);
const TagReader = require('./jukebox/tag-reader')(config, logger);
const play_log = require('./jukebox/library/play-log');
const sqlite3 = require('sqlite3');
var db = new sqlite3.Database(config.db);
2019-12-17 18:39:18 +00:00
const MediaLibrarySqliteBackend = require('./jukebox/library/sqlite-backend')(config, db, logger);
const MediaLibrary = new library.Library(config, MediaLibrarySqliteBackend);
const PlayLog = new play_log.PlayLog();
var app = express();
var server = require('http').createServer();
const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;
var wss = new WebSocketServer({server: server});
function exitHandler(options, err) {
2017-04-09 17:55:11 +00:00
logger.debug('closing child tasks');
if (err) logger.debug(err.stack);
2017-04-08 02:01:12 +00:00
// FIXME When do we actually need to call this? Adding these seems
// to have fixed a problem with orphaned children, but not we get
// two sets of "closing child tasks" messages when we shut down.
TagReader.kill();
MediaPlayer.kill();
if (options.exit) {
process.exit();
}
};
process.on('exit', exitHandler.bind(null));
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
2017-04-08 02:01:12 +00:00
2019-12-14 21:19:06 +00:00
const throttledTag = throttle(config.global_throttle, true, tag => {
ScriptRunner.find(tag).then((fulfilled) => {
if (false === fulfilled) {
MediaLibrary.find(tag)
}
}).catch(err => {
logger.error("got an error handling the tag: " + err);
});
});
TagReader.on('message', tag => {
2017-04-10 02:45:21 +00:00
if (tag == 'E1' || tag == 'E2') {
logger.debug("tagreader had rfid read error", { tag: tag });
return;
}
logger.debug("got tag from tagreader", { tag: tag });
2019-12-14 21:19:06 +00:00
throttledTag(tag);
});
if (config.debug) {
2017-04-09 19:08:32 +00:00
MediaPlayer.on('message', line => {
logger.debug("mediaplayer sent message", { line: line });
});
}
MediaPlayer.on('command', tag => {
PlayLog.updateLog(tag);
});
var hbs = handlebars.create({
extname: ".hbs",
});
MediaLibrary.on('action', MediaPlayer.handleTag.bind(MediaPlayer));
app.engine(".hbs", hbs.engine);
app.set('view engine', '.hbs');
app.set('views', __dirname + '/views');
2017-04-09 17:55:11 +00:00
app.use(morgan('dev'))
app.use(express.json())
app.use(express.static(__dirname + '/static'))
PlayLog.on('update', tag => {
app.render("log", { layout: false, play_log: PlayLog.getLog(), }, (err, html) => {
var data = {
html: html,
tag: tag.tag
};
wss.broadcast(JSON.stringify(data));
});
});
app.get('/', function(req, res, next) {
res.render('index', {
last_tag: PlayLog.getLastTag(),
config: config,
play_log: PlayLog.getLog(),
});
});
app.get('/api/tags', function(req, res, next) {
db.all("SELECT tags.tag, count(library.tag) tag_count FROM (SELECT DISTINCT tag FROM tags) tags LEFT JOIN library ON tags.tag = library.tag GROUP BY tags.tag", (err, rows) => {
res.send(rows);
});
});
app.patch('/api/tracks/:track', function(req, res, next) {
var track_uuid = req.params.track,
label = req.body.label,
tag = req.body.tag;
2019-12-17 17:12:53 +00:00
db.run("UPDATE library SET label = ?, tag = ? WHERE uuid = ?", label, tag, track_uuid, err => {
db.get("SELECT * FROM library WHERE uuid = ?", track_uuid, (err, row) => {
res.send(row);
});
});
});
app.get('/api/tracks', function(req, res, next) {
db.all("SELECT * FROM library ORDER BY label ASC", (err, rows) => {
res.send(rows);
});
});
2019-12-17 17:12:53 +00:00
app.post('/api/tracks', upload.single('track'), function(req, res, next) {
db.run("INSERT INTO library (label, uuid) VALUES (?, ?)", req.file.originalname, req.file.filename, err => {
res.redirect('/library');
});
});
app.get('/library', function(req, res, next) {
res.render('library', {
title: 'Library',
});
});
wss.broadcast = function broadcast(data) {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
wss.on('connection', function(ws) {
2017-04-09 17:55:11 +00:00
logger.info('websocket client connected');
ws.on('close', function() {
2017-04-09 17:55:11 +00:00
logger.info('websocket client disconnected');
});
});
server.on('request', app);
server.listen(config.port, function() {
2017-04-09 17:55:11 +00:00
logger.info('express listening on http://localhost:' + config.port)
})
2017-04-08 16:05:39 +00:00
// vim:ts=2 sw=2 et: