parent
1ad4be4bff
commit
78f2802dea
@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
while date +%s ; do
|
while echo 1234567890 ; do
|
||||||
sleep 5
|
sleep 0.2
|
||||||
done
|
done
|
||||||
|
23
jukebox/library/file-backend.js
Normal file
23
jukebox/library/file-backend.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const glob = require('glob');
|
||||||
|
|
||||||
|
class FileBackend {
|
||||||
|
constructor(config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
find(tag, callback) {
|
||||||
|
glob('media/' + tag + ' - *.mp3', (err, files) => {
|
||||||
|
if (files.length > 0) {
|
||||||
|
callback(files[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(config) {
|
||||||
|
return new FileBackend(config);
|
||||||
|
};
|
||||||
|
|
||||||
|
// vim:ts=2 sw=2 et:
|
72
jukebox/library/index.js
Normal file
72
jukebox/library/index.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
class Library extends EventEmitter {
|
||||||
|
constructor(config, backend) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.log_size = 10;
|
||||||
|
this.config = config;
|
||||||
|
this.backend = backend;
|
||||||
|
this.log = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
find(tag) {
|
||||||
|
this.backend.find(tag, path => {
|
||||||
|
if (!path) {
|
||||||
|
this.updateLog(new NotFoundLogEntry(tag));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateLog(new FileLogEntry(tag, path));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLog(entry) {
|
||||||
|
this.log.unshift(entry);
|
||||||
|
if (this.log.length > this.log_size) {
|
||||||
|
this.log.pop();
|
||||||
|
}
|
||||||
|
this.emit('play', entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastTag() {
|
||||||
|
if (this.log.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.log[0].tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLog() {
|
||||||
|
return this.log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogEntry {
|
||||||
|
constructor(tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotFoundLogEntry extends LogEntry {
|
||||||
|
toString() {
|
||||||
|
return `Unknown media: ${this.tag}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileLogEntry extends LogEntry {
|
||||||
|
constructor(tag, path) {
|
||||||
|
super(tag);
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.Library = Library;
|
||||||
|
|
||||||
|
// vim:set ts=2 sw=2 et:
|
@ -1,18 +1,53 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const throttle = require('throttle-debounce/throttle');
|
||||||
|
|
||||||
const ChildProcessEmitter = require('./child-process').ChildProcessEmitter;
|
const ChildProcessEmitter = require('./child-process').ChildProcessEmitter;
|
||||||
|
|
||||||
|
const DEFAULT_PAUSE_THROTTLE = 2000;
|
||||||
|
const DEFAULT_PLAY_THROTTLE = 5000;
|
||||||
|
|
||||||
class MediaPlayer extends ChildProcessEmitter {
|
class MediaPlayer extends ChildProcessEmitter {
|
||||||
constructor(config, logger) {
|
constructor(config, logger) {
|
||||||
super(config.mpg321, logger);
|
super(config.mpg321, logger);
|
||||||
this.stderrFilters.push(line => {
|
|
||||||
return line.substr(0, 3) == '@F '
|
this.stderrFilters.push(line => {
|
||||||
});
|
return line.substr(0, 3) == '@F '
|
||||||
}
|
});
|
||||||
|
|
||||||
|
this.pauseThrottled = throttle(config.pause_throttle || DEFAULT_PAUSE_THROTTLE, () => {
|
||||||
|
this._pause();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.playFileThrottled = throttle(config.play_throttle || DEFAULT_PLAY_THROTTLE, (path) => {
|
||||||
|
this._playFile(path);
|
||||||
|
});
|
||||||
|
|
||||||
|
// default to unthrottled
|
||||||
|
this.pause = this._pauseFile;
|
||||||
|
this.playFile = this._playFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
throttle() {
|
||||||
|
this.pause = this.pauseThrottled;
|
||||||
|
this.playFile = this.playFileThrottled;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.send('STOP');
|
||||||
|
}
|
||||||
|
|
||||||
|
_pause() {
|
||||||
|
this.send('PAUSE');
|
||||||
|
}
|
||||||
|
|
||||||
|
_playFile(path) {
|
||||||
|
this.send("LOAD " + path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(config, logger) {
|
module.exports = function(config, logger) {
|
||||||
return new MediaPlayer(config, logger);
|
return new MediaPlayer(config, logger);
|
||||||
};
|
};
|
||||||
|
|
||||||
// vim:set ts=2 sw=2 et:
|
// vim:set ts=2 sw=2 et:
|
||||||
|
@ -36,7 +36,6 @@ class IndexView extends View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
partials() {
|
partials() {
|
||||||
console.log(views.log);
|
|
||||||
return {
|
return {
|
||||||
log: views.log.template
|
log: views.log.template
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"glob": "^7.1.1",
|
"glob": "^7.1.1",
|
||||||
"morgan": "^1.7.0",
|
"morgan": "^1.7.0",
|
||||||
"mustache": "^2.3.0",
|
"mustache": "^2.3.0",
|
||||||
|
"throttle-debounce": "^1.0.1",
|
||||||
"winston": "^2.3.1",
|
"winston": "^2.3.1",
|
||||||
"ws": "^2.2.2"
|
"ws": "^2.2.2"
|
||||||
},
|
},
|
||||||
|
79
player.js
79
player.js
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
const config = require('./config.json')
|
const config = require('./config.json')
|
||||||
|
|
||||||
const glob = require('glob');
|
|
||||||
|
|
||||||
const views = require('./jukebox/views')(__dirname + '/templates/');
|
const views = require('./jukebox/views')(__dirname + '/templates/');
|
||||||
|
const library = require('./jukebox/library');
|
||||||
|
|
||||||
|
const MediaLibraryFileBackend = require('./jukebox/library/file-backend')(config);
|
||||||
|
const MediaLibrary = new library.Library(config, MediaLibraryFileBackend);
|
||||||
|
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const morgan = require('morgan')
|
const morgan = require('morgan')
|
||||||
@ -21,6 +23,8 @@ logger.level = config.debug ? 'debug' : 'info';
|
|||||||
const MediaPlayer = require('./jukebox/media-player')(config, logger);
|
const MediaPlayer = require('./jukebox/media-player')(config, logger);
|
||||||
const TagReader = require('./jukebox/tag-reader')(config, logger);
|
const TagReader = require('./jukebox/tag-reader')(config, logger);
|
||||||
|
|
||||||
|
MediaPlayer.throttle();
|
||||||
|
|
||||||
var app = express();
|
var app = express();
|
||||||
var server = require('http').createServer();
|
var server = require('http').createServer();
|
||||||
|
|
||||||
@ -28,8 +32,6 @@ const WebSocket = require('ws');
|
|||||||
const WebSocketServer = WebSocket.Server;
|
const WebSocketServer = WebSocket.Server;
|
||||||
var wss = new WebSocketServer({server: server});
|
var wss = new WebSocketServer({server: server});
|
||||||
|
|
||||||
var play_log = [];
|
|
||||||
|
|
||||||
function exitHandler(options, err) {
|
function exitHandler(options, err) {
|
||||||
logger.debug('closing child tasks');
|
logger.debug('closing child tasks');
|
||||||
if (err) logger.debug(err.stack);
|
if (err) logger.debug(err.stack);
|
||||||
@ -45,8 +47,8 @@ function exitHandler(options, err) {
|
|||||||
process.on('exit', exitHandler.bind(null));
|
process.on('exit', exitHandler.bind(null));
|
||||||
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
|
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
|
||||||
|
|
||||||
TagReader.on('message', data => {
|
TagReader.on('message', tag => {
|
||||||
processLine(data);
|
MediaLibrary.find(tag);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (config.debug) {
|
if (config.debug) {
|
||||||
@ -55,61 +57,28 @@ if (config.debug) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var last_tag = null;
|
MediaLibrary.on('play', event => {
|
||||||
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', (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 = {
|
var data = {
|
||||||
html: views.log.render({ play_log: play_log }),
|
html: views.log.render({ play_log: MediaLibrary.getLog() }),
|
||||||
tag: last_tag
|
tag: MediaLibrary.getLastTag()
|
||||||
};
|
};
|
||||||
|
|
||||||
wss.broadcast(JSON.stringify(data));
|
wss.broadcast(JSON.stringify(data));
|
||||||
}
|
});
|
||||||
|
|
||||||
function processLine(data) {
|
MediaLibrary.on('play', event => {
|
||||||
if (Date.now() / 1000 < debounce_until) {
|
if (event.tag === config.stop_id) {
|
||||||
return;
|
MediaPlayer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
last_tag = String(data).trim();
|
if (event.tag === config.pause_id) {
|
||||||
logger.debug("got tag from tag reader", { tag: last_tag });
|
MediaPlayer.pause();
|
||||||
|
}
|
||||||
|
|
||||||
// min 1 sec debounce
|
if (event.path) {
|
||||||
debounce_until = Date.now() / 1000 + 1;
|
MediaPlayer.playFile(event.path);
|
||||||
|
}
|
||||||
lookup(last_tag, function(action, wait_sec) {
|
});
|
||||||
wait_sec = wait_sec || 1;
|
|
||||||
debounce_until = Date.now() / 1000 + wait_sec;
|
|
||||||
if (action) {
|
|
||||||
logger.info("sending action to media player", { action: action, tag: last_tag });
|
|
||||||
MediaPlayer.send(action + "\n");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
app.use(morgan('dev'))
|
app.use(morgan('dev'))
|
||||||
app.use(express.static(__dirname + '/static'))
|
app.use(express.static(__dirname + '/static'))
|
||||||
@ -117,9 +86,9 @@ app.use(express.static(__dirname + '/static'))
|
|||||||
app.get('/', function (req, res, next) {
|
app.get('/', function (req, res, next) {
|
||||||
try {
|
try {
|
||||||
var index = views.index.render({
|
var index = views.index.render({
|
||||||
last_tag: last_tag
|
last_tag: MediaLibrary.getLastTag()
|
||||||
, config: config
|
, config: config
|
||||||
, play_log: play_log
|
, play_log: MediaLibrary.getLog()
|
||||||
});
|
});
|
||||||
|
|
||||||
var html = views.base.render({
|
var html = views.base.render({
|
||||||
|
Loading…
Reference in New Issue
Block a user