Create PlayLog, move tag identification into MediaLibrary
This commit is contained in:
parent
78f2802dea
commit
43ad5281e3
@ -1,6 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
|
const basename = require('path').basename;
|
||||||
|
|
||||||
class FileBackend {
|
class FileBackend {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
@ -10,8 +11,9 @@ class FileBackend {
|
|||||||
find(tag, callback) {
|
find(tag, callback) {
|
||||||
glob('media/' + tag + ' - *.mp3', (err, files) => {
|
glob('media/' + tag + ' - *.mp3', (err, files) => {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
callback(files[0]);
|
callback(basename(files[0]));
|
||||||
}
|
}
|
||||||
|
callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,70 +1,34 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const tags = require('./tags');
|
||||||
|
|
||||||
class Library extends EventEmitter {
|
class Library extends EventEmitter {
|
||||||
constructor(config, backend) {
|
constructor(config, backend) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.log_size = 10;
|
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.backend = backend;
|
this.backend = backend;
|
||||||
this.log = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
find(tag) {
|
find(tag) {
|
||||||
|
if (tag === this.config.stop_id) {
|
||||||
|
this.emit('action', new tags.StopCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tag === this.config.pause_id) {
|
||||||
|
this.emit('action', new tags.PauseCommand());
|
||||||
|
}
|
||||||
|
|
||||||
this.backend.find(tag, path => {
|
this.backend.find(tag, path => {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
this.updateLog(new NotFoundLogEntry(tag));
|
this.emit('action', new tags.NotFoundTag(tag));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateLog(new FileLogEntry(tag, path));
|
this.emit('action', new tags.FileTag(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;
|
module.exports.Library = Library;
|
||||||
|
44
jukebox/library/play-log.js
Normal file
44
jukebox/library/play-log.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
const tags = require('./tags');
|
||||||
|
|
||||||
|
module.exports.PlayLog = class PlayLog extends EventEmitter {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.last_tag = undefined;
|
||||||
|
this.log = [];
|
||||||
|
this.log_size = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLog(tag) {
|
||||||
|
this.last_tag = tag;
|
||||||
|
|
||||||
|
if (tag instanceof tags.NotFoundTag) {
|
||||||
|
this.emit('update', tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log.unshift(tag);
|
||||||
|
if (this.log.length > this.log_size) {
|
||||||
|
this.log.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('update', tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastTag() {
|
||||||
|
if (this.log.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.log[0].tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLog() {
|
||||||
|
return this.log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim:ts=2 sw=2 et:
|
45
jukebox/library/tags.js
Normal file
45
jukebox/library/tags.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
class Tag {
|
||||||
|
constructor(tag) {
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StopCommand extends Tag {
|
||||||
|
toString() {
|
||||||
|
return "Command: STOP";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PauseCommand extends Tag {
|
||||||
|
toString() {
|
||||||
|
return "Command: PAUSE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NotFoundTag extends Tag {
|
||||||
|
toString() {
|
||||||
|
return `Unknown tag: ${this.tag}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileTag extends Tag {
|
||||||
|
constructor(tag, path) {
|
||||||
|
super(tag);
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
StopCommand: StopCommand
|
||||||
|
, PauseCommand: PauseCommand
|
||||||
|
, NotFoundTag: NotFoundTag
|
||||||
|
, FileTag: FileTag
|
||||||
|
};
|
@ -1,11 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const tags = require('./library/tags');
|
||||||
|
|
||||||
const throttle = require('throttle-debounce/throttle');
|
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_PAUSE_THROTTLE = 2000;
|
||||||
const DEFAULT_PLAY_THROTTLE = 5000;
|
const DEFAULT_PLAY_THROTTLE = 5000;
|
||||||
|
const DEFAULT_UNKNOWN_THROTTLE = 2000;
|
||||||
|
|
||||||
class MediaPlayer extends ChildProcessEmitter {
|
class MediaPlayer extends ChildProcessEmitter {
|
||||||
constructor(config, logger) {
|
constructor(config, logger) {
|
||||||
@ -23,6 +26,8 @@ class MediaPlayer extends ChildProcessEmitter {
|
|||||||
this._playFile(path);
|
this._playFile(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.unknown = throttle(config.unknown_throttle || DEFAULT_UNKNOWN_THROTTLE, this._unknown);
|
||||||
|
|
||||||
// default to unthrottled
|
// default to unthrottled
|
||||||
this.pause = this._pauseFile;
|
this.pause = this._pauseFile;
|
||||||
this.playFile = this._playFile;
|
this.playFile = this._playFile;
|
||||||
@ -33,16 +38,35 @@ class MediaPlayer extends ChildProcessEmitter {
|
|||||||
this.playFile = this.playFileThrottled;
|
this.playFile = this.playFileThrottled;
|
||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop(tag) {
|
||||||
|
this.emit('command', tag);
|
||||||
this.send('STOP');
|
this.send('STOP');
|
||||||
}
|
}
|
||||||
|
|
||||||
_pause() {
|
_pause(tag) {
|
||||||
|
this.emit('command', tag);
|
||||||
this.send('PAUSE');
|
this.send('PAUSE');
|
||||||
}
|
}
|
||||||
|
|
||||||
_playFile(path) {
|
_playFile(tag) {
|
||||||
this.send("LOAD " + path);
|
this.emit('command', tag);
|
||||||
|
this.send("LOAD media/" + tag.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
_unknown(tag) {
|
||||||
|
this.emit('command', tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleTag(tag) {
|
||||||
|
if (tag instanceof tags.StopCommand) {
|
||||||
|
this.stop(tag);
|
||||||
|
} else if (tag instanceof tags.PauseCommand) {
|
||||||
|
this.pause(tag);
|
||||||
|
} else if (tag instanceof tags.FileTag) {
|
||||||
|
this.playFile(tag);
|
||||||
|
} else {
|
||||||
|
this.unknown(tag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
const ChildProcessEmitter = require('./child-process').ChildProcessEmitter;
|
const ChildProcessEmitter = require('./child-process').ChildProcessEmitter;
|
||||||
|
|
||||||
class TagReader extends ChildProcessEmitter {
|
class TagReader extends ChildProcessEmitter {
|
||||||
constructor(config, logger) {
|
constructor(config, logger) {
|
||||||
super(config.tag_reader, logger);
|
super(config.tag_reader, logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(config, logger) {
|
module.exports = function(config, logger) {
|
||||||
|
34
player.js
34
player.js
@ -22,6 +22,9 @@ 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);
|
||||||
|
const play_log = require('./jukebox/library/play-log');
|
||||||
|
|
||||||
|
const PlayLog = new play_log.PlayLog();
|
||||||
|
|
||||||
MediaPlayer.throttle();
|
MediaPlayer.throttle();
|
||||||
|
|
||||||
@ -36,6 +39,9 @@ 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);
|
||||||
|
|
||||||
|
// 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();
|
TagReader.kill();
|
||||||
MediaPlayer.kill();
|
MediaPlayer.kill();
|
||||||
|
|
||||||
@ -57,28 +63,20 @@ if (config.debug) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaLibrary.on('play', event => {
|
MediaPlayer.on('command', tag => {
|
||||||
|
PlayLog.updateLog(tag);
|
||||||
|
});
|
||||||
|
|
||||||
|
PlayLog.on('update', tag => {
|
||||||
var data = {
|
var data = {
|
||||||
html: views.log.render({ play_log: MediaLibrary.getLog() }),
|
html: views.log.render({ play_log: PlayLog.getLog() }),
|
||||||
tag: MediaLibrary.getLastTag()
|
tag: tag.tag
|
||||||
};
|
};
|
||||||
|
|
||||||
wss.broadcast(JSON.stringify(data));
|
wss.broadcast(JSON.stringify(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
MediaLibrary.on('play', event => {
|
MediaLibrary.on('action', MediaPlayer.handleTag.bind(MediaPlayer));
|
||||||
if (event.tag === config.stop_id) {
|
|
||||||
MediaPlayer.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.tag === config.pause_id) {
|
|
||||||
MediaPlayer.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.path) {
|
|
||||||
MediaPlayer.playFile(event.path);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(morgan('dev'))
|
app.use(morgan('dev'))
|
||||||
app.use(express.static(__dirname + '/static'))
|
app.use(express.static(__dirname + '/static'))
|
||||||
@ -86,9 +84,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: MediaLibrary.getLastTag()
|
last_tag: PlayLog.getLastTag()
|
||||||
, config: config
|
, config: config
|
||||||
, play_log: MediaLibrary.getLog()
|
, play_log: PlayLog.getLog()
|
||||||
});
|
});
|
||||||
|
|
||||||
var html = views.base.render({
|
var html = views.base.render({
|
||||||
|
Loading…
Reference in New Issue
Block a user