Skip to content

Instantly share code, notes, and snippets.

@martin2250
Created November 22, 2016 13:28
Show Gist options
  • Save martin2250/068e471a51c3b684b755ce2aa6e85e3d to your computer and use it in GitHub Desktop.
Save martin2250/068e471a51c3b684b755ce2aa6e85e3d to your computer and use it in GitHub Desktop.
hacked-together mpdemulation plugin for volumio (seriosly don't use this permanently)
'use strict';
var net = require('net');
var libQ = require('kew');
var libFast = require('fast.js');
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000', {reconnect: true});
var volume = 20;
var playing = false;
socket.on('pushState', function(state){
volume = parseInt(state['volume']);
playing = state['status'] == 'play';
console.log("got status");
console.log(state);
});
socket.on('connect', function(){socket.emit('getState');});
// MPD info
var mpdPort = 6500;
var mpdAddress = '0.0.0.0';
var parameterRegex = /(?:".+?"|\S+)/g
var router;
// TODO check if we can move this to the helper and make it GLOBAL?
const command = { // List of all MPD commands
ADD: 'add',
ADDID: 'addid',
ADDTAGID: 'addtagid',
CHANNELS: 'channels',
CLEAR: 'clear',
CLEARERROR: 'clearerror',
CLEARTAGID: 'cleartagid',
CLOSE: 'close',
COMMANDS: 'commands',
CONFIG: 'config',
CONSUME: 'consume',
COUNT: 'count',
CROSSFADE: 'crossfade',
CURRENTSONG: 'currentsong',
DECODERS: 'decoders',
DELETE: 'delete',
DELETEID: 'deleteid',
DISABLEOUTPUT: 'disableoutput',
ENABLEOUTPUT: 'enableoutput',
FIND: 'find',
FINDADD: 'findadd',
IDLE: 'idle',
KILL: 'kill',
LIST: 'list',
LISTALL: 'listall',
LISTALLINFO: 'listallinfo',
LISTFILES: 'listfiles',
LISTMOUNTS: 'listmounts',
LISTPLAYLIST: 'listplaylist',
LISTPLAYLISTINFO: 'listplaylistinfo',
LISTPLAYLISTS: 'listplaylists',
LOAD: 'load',
LSINFO: 'lsinfo',
MIXRAMPDB: 'mixrampdb',
MIXRAMPDELAY: 'mixrampdelay',
MOUNT: 'mount',
MOVE: 'move',
MOVEID: 'moveid',
NEXT: 'next',
NOIDLE: 'noidle',
NOTCOMMANDS: 'notcommands',
OUTPUTS: 'outputs',
PASSWORD: 'password',
PAUSE: 'pause',
PING: 'ping',
PLAY: 'play',
PLAYID: 'playid',
PLAYLIST: 'playlist',
PLAYLISTADD: 'playlistadd',
PLAYLISTCLEAR: 'playlistclear',
PLAYLISTDELETE: 'playlistdelete',
PLAYLISTFIND: 'playlistfind',
PLAYLISTID: 'playlistid',
PLAYLISTINFO: 'playlistinfo',
PLAYLISTMOVE: 'playlistmove',
PLAYLISTSEARCH: 'playlistsearch',
PLCHANGES: 'plchanges',
PLCHANGEPOSID: 'plchangesposid',
PREVIOUS: 'previous',
PRIO: 'prio',
PRIOID: 'prioid',
RANDOM: 'random',
RANGEID: 'rangeid',
READCOMMENTS: 'readcomments',
READMESSAGES: 'readmessages',
RENAME: 'rename',
REPEAT: 'repeat',
REPLAY_GAIN_MODE: 'replay_gain_mode',
REPLAY_GAIN_STATUS: 'replay_gain_status',
RESCAN: 'rescan',
REMOVE: 'rm',
SAVE: 'save',
SEARCH: 'search',
SEARCHADD: 'searchadd',
SEARCHADDPL: 'searchaddpl',
SEEK: 'seek',
SEEKCUR: 'seekcur',
SEEKID: 'seekid',
SENDMESSAGE: 'sendmessage',
SETVOL: 'setvol',
SHUFFLE: 'shuffle',
SINGLE: 'single',
STATS: 'stats',
STATUS: 'status',
STICKER: 'sticker',
STOP: 'stop',
SUBSCRIBE: 'subscribe',
SWAP: 'swap',
SWAPID: 'swapid',
TAGTYPES: 'tagtypes',
TOGGLEOUTPUT: 'toggleoutput',
UNMOUNT: 'unmount',
UNSUBSCRIBE: 'unsubscribe',
UPDATE: 'update',
URLHANDLERS: 'urlhandlers',
VOLUME: 'volume'
};
// Define the InterfaceMPD class
module.exports = InterfaceMPD;
function InterfaceMPD( context) {
var self = this;
self.context=context;
self.commRouter = self.context.coreCommand;
router = self.commRouter;
// helpers
self.helper = require('./helper.js');
self.idles = [];
self.loadCommandHandlers();
// create server
var protocolServer = net.createServer(function(client) {
// set Encoding (TODO check if this is necessary)
client.setEncoding('utf8');
// MPD welcome command
client.write('OK MPD 0.19.0\n'); // TODO not hardcoded?
// Incoming message (maybe a command?)
var buffer = ''; // Buffer since we may not receive whole lines
var lineIndex = 0; // Store the index of '\n' (<- end of line sign)
client.on('data', function(data) {
// add new incoming data to our buffer
buffer += data.toString();
// check if we have a complete line
lineIndex = buffer.indexOf('\n');
if (lineIndex === -1) {
return; // our buffer has received no full line yet
}
var results;
// while we still have a complete line in our buffer (os.EOL == end of line (\r\n))
while (results = buffer.split(/\r?\n/)) {
// get 1 line from our buffer to process
var message = results[0];
// Handle message elsewhere (keep it clean)
self.handleMessage(message, client);
buffer = buffer.substring(lineIndex + 1); // Cuts off the processed line
break;
}
});
}).listen(mpdPort, mpdAddress); // start server
// On server error
protocolServer.on('error', function(err) {
if (err.code === 'EADDRINUSE') {
// address is in use
self.commRouter.pushConsoleMessage('Failed to bind MPD protocol to port ' + mpdPort +
': Address in use.');
} else {
throw err;
}
});
}
// ================================ INTERNAL FUNCTIONS
// Incoming message handler
InterfaceMPD.prototype.handleMessage = function(message, socket) {
var self = this;
console.log(message);
// some vars to help extract command/parameters from line
var nSpaceLocation = 0;
var sCommand = '';
var aParam = [];
// check if there is a space
nSpaceLocation = message.indexOf(' ');
if (nSpaceLocation === -1) {
// no space, only 1 command
sCommand = message.substring(/\r?\n/);
} else {
// a space, before space command, rest parameter
sCommand = message.substring(0, nSpaceLocation);
aParam = message.substring(nSpaceLocation + 1, message.length).match(parameterRegex);
aParam = aParam.map(function(param){return param.replace(/"/, '');});
}
// self.commRouter.pushConsoleMessage('Incoming command: ' + sCommand + '\nParam: '+aParam);
var handler = self.commandHandlers[sCommand];
if (handler)
handler(sCommand, aParam, socket);
else
self.commRouter.pushConsoleMessage('default');
};
InterfaceMPD.prototype.logDone = function(timeStart) {
var self = this;
self.commRouter.pushConsoleMessage('[' + Date.now() + '] ' + '------------------------------ ' + (Date.now() - timeStart) + 'ms');
return libQ.resolve();
};
InterfaceMPD.prototype.logStart = function(sCommand) {
var self = this;
self.commRouter.pushConsoleMessage('\n' + '[' + Date.now() + '] ' + '---------------------------- ' + sCommand);
return libQ.resolve();
};
// ============================ COMMAND HANDLERS
// All handlers are on Alphabetical order of Commands.
// Handler for command: ADD
InterfaceMPD.prototype.handleAdd = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: ADDID
InterfaceMPD.prototype.handleAddid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: ADDTAGID
InterfaceMPD.prototype.handleAddtagid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CHANNELS
InterfaceMPD.prototype.handleChannels = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CLEAR
InterfaceMPD.prototype.handleClear = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CLEARERROR
InterfaceMPD.prototype.handleClearerror = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CLEARTAGID
InterfaceMPD.prototype.handleCleartagid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CLOSE
InterfaceMPD.prototype.handleClose = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: COMMANDS
InterfaceMPD.prototype.handleCommands = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CONFIG
InterfaceMPD.prototype.handleConfig = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CONSUME
InterfaceMPD.prototype.handleConsume = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: COUNT
InterfaceMPD.prototype.handleCount = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CROSSFADE
InterfaceMPD.prototype.handleCrossfade = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: CURRENTSONG
InterfaceMPD.prototype.handleCurrentsong = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: DECODERS
InterfaceMPD.prototype.handleDecoders = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: DELETE
InterfaceMPD.prototype.handleDelete = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: DELETEID
InterfaceMPD.prototype.handleDeleteid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: DISABLEOUTPUT
InterfaceMPD.prototype.handleDisableoutput = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: ENABLEOUTPUT
InterfaceMPD.prototype.handleEnableoutput = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: FIND
InterfaceMPD.prototype.handleFind = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: FINDADD
InterfaceMPD.prototype.handleFindadd = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: IDLE
InterfaceMPD.prototype.handleIdle = function(sCommand, aParam, client) {
var self = this;
// keep client in idle list
self.idles.push(client);
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: KILL
InterfaceMPD.prototype.handleKill = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LIST
InterfaceMPD.prototype.handleList = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTALL
InterfaceMPD.prototype.handleListall = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
self.logStart('Client requests Volumio library by title')
.then(libFast.bind(self.commRouter.volumioGetLibraryByTitle, self.commRouter))
.then(function(library) {
self.pushLibrary.call(self, library, client);
})
.fail(libFast.bind(self.commRouter.pushConsoleMessage, self.commRouter))
.done(function() {
// Respond with default 'OK'
client.write('OK\n');
return self.logDone(timeStart);
});
};
// Handler for command: LISTALLINFO
InterfaceMPD.prototype.handleListallinfo = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTFILES
InterfaceMPD.prototype.handleListfiles = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTMOUNTS
InterfaceMPD.prototype.handleListmounts = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTPLAYLIST
InterfaceMPD.prototype.handleListplaylist = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTPLAYLISTINFO
InterfaceMPD.prototype.handleListplaylistinfo = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LISTPLAYLISTS
InterfaceMPD.prototype.handleListplaylists = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LOAD
InterfaceMPD.prototype.handleLoad = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: LSINFO
InterfaceMPD.prototype.handleLsinfo = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: MIXRAMPDB
InterfaceMPD.prototype.handleMixrampdb = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: MIXRAMPDELAY
InterfaceMPD.prototype.handleMixrampdelay = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: MOUNT
InterfaceMPD.prototype.handleMount = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: MOVE
InterfaceMPD.prototype.handleMove = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: MOVEID
InterfaceMPD.prototype.handleMoveid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: NEXT
InterfaceMPD.prototype.handleNext = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
console.log('Dickbuttnext\n');
// send Next command to CommandRouter
socket.emit('next');
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: NOTCOMMANDS
InterfaceMPD.prototype.handleNotcommands = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: OUTPUTS
InterfaceMPD.prototype.handleOutputs = function(sCommand, aParam, client) {
// Hardcoded, but MUST be tied to system later
client.write('outputid: 0\n');
client.write('outputname: Default\n');
client.write('outputenabled: 1\n');
client.write('OK\n');
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PASSWORD
InterfaceMPD.prototype.handlePassword = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PAUSE
InterfaceMPD.prototype.handlePause = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Send pause command to CommandRouter
self.logStart('Client requests Volumio pause' )
.then(libFast.bind(self.commRouter.volumioPause, self.commRouter))
.fail(libFast.bind(self.commRouter.pushConsoleMessage, self.commRouter))
.done(function() {
return self.logDone(timeStart);
});
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PING
InterfaceMPD.prototype.handlePing = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAY
InterfaceMPD.prototype.handlePlay = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Send play command to CommandRouter
if(playing)
{
playing = false;
socket.emit('pause');
}
else
{
playing = true;
socket.emit('play')
}
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYID
InterfaceMPD.prototype.handlePlayid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLIST
InterfaceMPD.prototype.handlePlaylist = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Fetch queue from CommandRouter
self.logStart('Client requests Volumio queue')
.then(libFast.bind(self.commRouter.volumioGetQueue, self.commRouter))
.then(function(queue) {
// forward queue to helper
self.helper.setQueue(queue);
}).then(function() {
// fetch MPD output from helper
client.write(self.helper.printPlaylist());
})
.fail(libFast.bind(self.commRouter.pushConsoleMessage, self.commRouter))
.done(function() {
return self.logDone(timeStart);
});
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTADD
InterfaceMPD.prototype.handlePlaylistadd = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTCLEAR
InterfaceMPD.prototype.handlePlaylistclear = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTDELETE
InterfaceMPD.prototype.handlePlaylistdelete = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTFIND
InterfaceMPD.prototype.handlePlaylistfind = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTID
InterfaceMPD.prototype.handlePlaylistid = function(sCommand, aParam, client) {
// Temporary Disabled and HardCoded
client.write('ACK [50@0] {playlistid} No such song\n');
// Respond with default 'OK'
// client.write('OK\n');
};
// Handler for command: PLAYLISTINFO
InterfaceMPD.prototype.handlePlaylistinfo = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTMOVE
InterfaceMPD.prototype.handlePlaylistmove = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLAYLISTSEARCH
InterfaceMPD.prototype.handlePlaylistsearch = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLCHANGES
InterfaceMPD.prototype.handlePlchanges = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PLCHANGESPOSID
InterfaceMPD.prototype.handlePlchangesposid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PREVIOUS
InterfaceMPD.prototype.handlePrevious = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
socket.emit('prev');
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PRIO
InterfaceMPD.prototype.handlePrio = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: PRIOID
InterfaceMPD.prototype.handlePrioid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: RANDOM
InterfaceMPD.prototype.handleRandom = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: RANGEID
InterfaceMPD.prototype.handleRangeid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: READCOMMENTS
InterfaceMPD.prototype.handleReadcomments = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: READMESSAGES
InterfaceMPD.prototype.handleReadmessages = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: RENAME
InterfaceMPD.prototype.handleRename = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: REPEAT
InterfaceMPD.prototype.handleRepeat = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: REPLAY_GAIN_MODE
InterfaceMPD.prototype.handleReplay_gain_mode = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: REPLAY_GAIN_STATUS
InterfaceMPD.prototype.handleReplay_gain_status = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: RESCAN
InterfaceMPD.prototype.handleRescan = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: RM
InterfaceMPD.prototype.handleRm = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SAVE
InterfaceMPD.prototype.handleSave = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEARCH
InterfaceMPD.prototype.handleSearch = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEARCHADD
InterfaceMPD.prototype.handleSearchadd = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEARCHADDPL
InterfaceMPD.prototype.handleSearchaddpl = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEEK
InterfaceMPD.prototype.handleSeek = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEEKCUR
InterfaceMPD.prototype.handleSeekcur = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SEEKID
InterfaceMPD.prototype.handleSeekid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SENDMESSAGE
InterfaceMPD.prototype.handleSendmessage = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SETVOL
InterfaceMPD.prototype.handleSetvol = function(sCommand, aParam, client) {
console.log(sCommand);
console.log(aParam);
client.write('OK\n');
};
// Handler for command: SHUFFLE
InterfaceMPD.prototype.handleShuffle = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SINGLE
InterfaceMPD.prototype.handleSingle = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: STATS
InterfaceMPD.prototype.handleStats = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Fetch proper MPD output from helper
self.logStart('Client requests Volumio stats')
.then(client.write(self.helper.printStats()))
.done(function() {
return self.logDone(timeStart);
});
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: STATUS
InterfaceMPD.prototype.handleStatus = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Fetch status from CommandRouter
self.logStart('Client requests Volumio status')
.then(libFast.bind(self.commRouter.volumioGetState, self.commRouter))
// Forward state to pushState function
.then(function(state) {
self.pushState.call(self, state, client);
})
.fail(libFast.bind(self.commRouter.pushConsoleMessage, self.commRouter))
.done(function() {
return self.logDone(timeStart);
});
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: STOP
InterfaceMPD.prototype.handleStop = function(sCommand, aParam, client) {
var self = this;
var timeStart = Date.now();
// Call stop on CommandRouter
self.logStart('Client requests Volumio stop' )
.then(libFast.bind(self.commRouter.volumioStop, self.commRouter))
.fail(libFast.bind(self.commRouter.pushConsoleMessage, self.commRouter))
.done(function() {
return self.logDone(timeStart);
});
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SUBSCRIBE
InterfaceMPD.prototype.handleSubscribe = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SWAP
InterfaceMPD.prototype.handleSwap = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: SWAPID
InterfaceMPD.prototype.handleSwapid = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: TAGTYPES
InterfaceMPD.prototype.handleTagtypes = function(sCommand, aParam, client) {
var self = this;
client.write(self.helper.printTagTypes());
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: TOGGLEOUTPUT
InterfaceMPD.prototype.handleToggleoutput = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: UNMOUNT
InterfaceMPD.prototype.handleUnmount = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: UNSUBSCRIBE
InterfaceMPD.prototype.handleUnsubscribe = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: UPDATE
InterfaceMPD.prototype.handleUpdate = function(sCommand, aParam, client) {
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: URLHANDLERS
InterfaceMPD.prototype.handleUrlhandlers = function(sCommand, aParam, client) {
// HARDCODED, might be fetched from MDP in the future
client.write('handler: http://\n');
client.write('handler: mms://\n');
client.write('handler: mmsh://\n');
client.write('handler: mmst://\n');
client.write('handler: mmsu://\n');
client.write('handler: gopher://\n');
client.write('handler: rtp://\n');
client.write('handler: rtsp://\n');
client.write('handler: rtmp://\n');
client.write('handler: rtmpt://\n');
client.write('handler: rtmps://\n');
// Respond with default 'OK'
client.write('OK\n');
};
// Handler for command: VOLUME
InterfaceMPD.prototype.handleVolume = function(sCommand, aParam, client) {
var i = parseInt(aParam);
console.log("adding " + i + " to volume " + volume)
volume += i;
socket.emit('volume', volume);
client.write('OK\n');
};
// COMMAND HANDLERS END
// =============== STATIC FUNCTIONS
// END OF STATIC FUNCTIONS
// ================================ PUBLIC FUNCTIONS
// These methods are usually called by the CommandRouter, but
// may be used internally as well
// Receive console messages from commandRouter and broadcast to all connected clients
InterfaceMPD.prototype.printConsoleMessage = function(message) {
// MPD clients dont need to receive console messages
// Return a resolved empty promise to represent completion
return libQ.resolve();
};
// Receive music library updates from commandRouter and broadcast to all connected clients
InterfaceMPD.prototype.pushLibrary = function(library, client) {
var self = this;
self.commRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'InterfaceMPD::pushLibrary');
// If a specific client is given, push to just that client
if (client) {
client.write(self.helper.printLibrary(library));
// Else push to all connected clients
} else {
self.idles.forEach(function(c) {
c.write('changed: database');
});
}
};
// Receive player queue updates from commandRouter and broadcast to all connected clients
InterfaceMPD.prototype.pushQueue = function(queue) {
var self = this;
self.commRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'InterfaceMPD::pushQueue');
// pass queue to the helper
self.helper.setQueue(queue);
// broadcast playlist changed to all idlers
self.idles.forEach(function(client) {
client.write('changed: playlist\n');
});
// TODO q-stuff
};
// Receive player state updates from commandRouter and broadcast to all connected clients
InterfaceMPD.prototype.pushState = function(state, socket) {
var self = this;
self.commRouter.pushConsoleMessage('[' + Date.now() + '] ' + 'InterfaceMPD::pushState');
// if requested by client, respond
if (socket) {
socket.write(self.helper.printStatus(state));
// else broadcast to all idlers
} else {
// pass state to the helper
self.helper.setStatus(state);
// broadcast state changed to all idlers
self.idles.forEach(function(client) {
client.write('changed: player\n');
});
}
// TODO q-stuff
};
// END OF PUBLIC FUNCTIONS
InterfaceMPD.prototype.loadCommandHandlers = function() {
var self = this;
self.commandHandlers = {};
self.commandHandlers[command.ADD] = self.handleAdd;
self.commandHandlers[command.ADDID] = self.handleAddid;
self.commandHandlers[command.ADDTAGID] = self.handleAddtagid;
self.commandHandlers[command.CHANNELS] = self.handleChannels;
self.commandHandlers[command.CLEAR] = self.handleClear;
self.commandHandlers[command.CLEARERROR] = self.handleClearerror;
self.commandHandlers[command.CLEARTAGID] = self.handleCleartagid;
self.commandHandlers[command.CLOSE] = self.handleClose;
self.commandHandlers[command.COMMANDS] = self.handleCommands;
self.commandHandlers[command.CONFIG] = self.handleConfig;
self.commandHandlers[command.CONSUME] = self.handleConsume;
self.commandHandlers[command.COUNT] = self.handleCount;
self.commandHandlers[command.CROSSFADE] = self.handleCrossfade;
self.commandHandlers[command.CURRENTSONG] = self.handleCurrentsong;
self.commandHandlers[command.DECODERS] = self.handleDecoders;
self.commandHandlers[command.DELETE] = self.handleDelete;
self.commandHandlers[command.DELETEID] = self.handleDeleteid;
self.commandHandlers[command.DISABLEOUTPUT] = self.handleDisableoutput;
self.commandHandlers[command.ENABLEOUTPUT] = self.handleEnableoutput;
self.commandHandlers[command.FIND] = self.handleFind;
self.commandHandlers[command.FINDADD] = self.handleFindadd;
self.commandHandlers[command.IDLE] = self.handleIdle;
self.commandHandlers[command.KILL] = self.handleKill;
self.commandHandlers[command.LIST] = self.handleList;
self.commandHandlers[command.LISTALL] = self.handleListall;
self.commandHandlers[command.LISTALLINFO] = self.handleListallinfo;
self.commandHandlers[command.LISTFILES] = self.handleListfiles;
self.commandHandlers[command.LISTMOUNTS] = self.handleListmounts;
self.commandHandlers[command.LISTPLAYLIST] = self.handleListplaylist;
self.commandHandlers[command.LISTPLAYLISTINFO] = self.handleListplaylistinfo;
self.commandHandlers[command.LISTPLAYLISTS] = self.handleListplaylists;
self.commandHandlers[command.LOAD] = self.handleLoad;
self.commandHandlers[command.LSINFO] = self.handleLsinfo;
self.commandHandlers[command.MIXRAMPDB] = self.handleMixrampdb;
self.commandHandlers[command.MIXRAMPDELAY] = self.handleMixrampdelay;
self.commandHandlers[command.MOUNT] = self.handleMount;
self.commandHandlers[command.MOVE] = self.handleMove;
self.commandHandlers[command.MOVEID] = self.handleMoveid;
self.commandHandlers[command.NEXT] = self.handleNext;
self.commandHandlers[command.NOTCOMMANDS] = self.handleNotcommands;
self.commandHandlers[command.OUTPUTS] = self.handleOutputs;
self.commandHandlers[command.PASSWORD] = self.handlePassword;
self.commandHandlers[command.PAUSE] = self.handlePause;
self.commandHandlers[command.PING] = self.handlePing;
self.commandHandlers[command.PLAY] = self.handlePlay;
self.commandHandlers[command.PLAYID] = self.handlePlayid;
self.commandHandlers[command.PLAYLIST] = self.handlePlaylist;
self.commandHandlers[command.PLAYLISTADD] = self.handlePlaylistadd;
self.commandHandlers[command.PLAYLISTCLEAR] = self.handlePlaylistclear;
self.commandHandlers[command.PLAYLISTDELETE] = self.handlePlaylistdelete;
self.commandHandlers[command.PLAYLISTFIND] = self.handlePlaylistfind;
self.commandHandlers[command.PLAYLISTID] = self.handlePlaylistid;
self.commandHandlers[command.PLAYLISTINFO] = self.handlePlaylistinfo;
self.commandHandlers[command.PLAYLISTMOVE] = self.handlePlaylistmove;
self.commandHandlers[command.PLAYLISTSEARCH] = self.handlePlaylistsearch;
self.commandHandlers[command.PLCHANGES] = self.handlePlchanges;
self.commandHandlers[command.PLCHANGEPOSID] = self.handlePlchangesposid;
self.commandHandlers[command.PREVIOUS] = self.handlePrevious;
self.commandHandlers[command.PRIO] = self.handlePrio;
self.commandHandlers[command.PRIOID] = self.handlePrioid;
self.commandHandlers[command.RANDOM] = self.handleRandom;
self.commandHandlers[command.RANGEID] = self.handleRangeid;
self.commandHandlers[command.READCOMMENTS] = self.handleReadcomments;
self.commandHandlers[command.READMESSAGES] = self.handleReadmessages;
self.commandHandlers[command.RENAME] = self.handleRename;
self.commandHandlers[command.REPEAT] = self.handleRepeat;
self.commandHandlers[command.REPLAY_GAIN_MODE] = self.handleReplay_gain_mode;
self.commandHandlers[command.REPLAY_GAIN_STATUS] = self.handleReplay_gain_status;
self.commandHandlers[command.RESCAN] = self.handleRescan;
self.commandHandlers[command.REMOVE] = self.handleRm;
self.commandHandlers[command.SAVE] = self.handleSave;
self.commandHandlers[command.SEARCH] = self.handleSearch;
self.commandHandlers[command.SEARCHADD] = self.handleSearchadd;
self.commandHandlers[command.SEARCHADDPL] = self.handleSearchaddpl;
self.commandHandlers[command.SEEK] = self.handleSeek;
self.commandHandlers[command.SEEKCUR] = self.handleSeekcur;
self.commandHandlers[command.SEEKID] = self.handleSeekid;
self.commandHandlers[command.SENDMESSAGE] = self.handleSendmessage;
self.commandHandlers[command.SETVOL] = self.handleSetvol;
self.commandHandlers[command.SHUFFLE] = self.handleShuffle;
self.commandHandlers[command.SINGLE] = self.handleSingle;
self.commandHandlers[command.STATS] = self.handleStats;
self.commandHandlers[command.STATUS] = self.handleStatus;
self.commandHandlers[command.STOP] = self.handleStop;
self.commandHandlers[command.SUBSCRIBE] = self.handleSubscribe;
self.commandHandlers[command.SWAP] = self.handleSwap;
self.commandHandlers[command.SWAPID] = self.handleSwapid;
self.commandHandlers[command.TAGTYPES] = self.handleTagtypes;
self.commandHandlers[command.TOGGLEOUTPUT] = self.handleToggleoutput;
self.commandHandlers[command.UNMOUNT] = self.handleUnmount;
self.commandHandlers[command.UNSUBSCRIBE] = self.handleUnsubscribe;
self.commandHandlers[command.UPDATE] = self.handleUpdate;
self.commandHandlers[command.URLHANDLERS] = self.handleUrlhandlers;
self.commandHandlers[command.VOLUME] = self.handleVolume;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment