# HG changeset patch # User Emmanuel Gil Peyrot # Date 1314150195 25200 # Node ID 3636007053760dfb149af043e8e2b50a46cbd85c Initial commit. diff --git a/config.js b/config.js new file mode 100644 --- /dev/null +++ b/config.js @@ -0,0 +1,2 @@ +exports.jid = 'you@example.org'; +exports.password = 'yourPassword'; diff --git a/lib.js b/lib.js new file mode 100644 --- /dev/null +++ b/lib.js @@ -0,0 +1,159 @@ +var net = require('net'); +var sys = require('sys'); + +function MPD(server, port) { + if (!port) port = '6600'; + if (!server) server = '::'; + + this.connect(port, server); +} + +MPD.prototype = { + stream: null, + is_connected: false, + updateTimer: null, + + status: {}, + cs: {}, + + _callbacks: {}, + + _callback: function() { + this._callback = null; + }, + + close: function() { + this.stream.end(); + this.is_connected = false; + }, + + connect: function(port, server) { + if (this.is_connected == true) { + this.close(); + } + + this.stream = net.createConnection(port, server); + + this.stream.setEncoding('utf8'); + + this.stream.on('connect', this.connected()); + this.stream.on('data', this.data()); + this.stream.on('close', this.closed()); + + this.stream.on('end', function() { + this.end(); + }); + }, + + connected: function() { + var self = this; + + return function() { + self.is_connected = true; + if (self.debug) console.log('MPD connection opened'); + + /*self.updateTimer = setInterval(function() { + if (self.is_connected == true) { + self.send('currentsong', function(cs) { + for (var v in cs) { + if (self.cs[v] != cs[v]) { + self.callback(v, cs[v]); + self.cs[v] = cs[v]; + } + } + }); + + self.send('status', function(status) { + for (var v in status) { + if (self.status[v] != status[v]) { + self.callback(v, status[v]); + self.status[v] = status[v]; + } + } + }); + } else { + clearInterval(self.updateTimer); + } + }, 1000);*/ + + self.callback('connect'); + }; + }, + + data: function() { + var self = this; + + var packet = []; + + return function(data) { + var data = data.toString(); + var commands = data.split('\n'); + + for (var i = 0; i < commands.length; i++) { + if (commands[i].length >= 2) { + packet.push(commands[i]); + + var command = commands[i].split(' '); + + switch (command[0]) { + case 'ACK': + case 'OK': + if (command[1] == 'MPD') { + self.version = command[2]; + } else { + self._callback.call(self, self._parsePacket(packet)); + packet = []; + this._callback = null; + } + break; + } + } + } + }; + }, + + closed: function() { + var self = this; + + return function(had_error) { + if (self.debug) console.log('MPD connection closed'); + self.callback('close'); + }; + }, + + _parsePacket: function(packet) { + var p = {}; + + for (var i = 0; i < packet.length; i++) { + var regx = /^(\w+):\s?(.*)$/i; + var result = regx.exec(packet[i]); + + if (result !== null) { + p[result[1]] = result[2]; + } + } + + return p; + }, + + send: function(str, cb) { + this._callback = cb; + this.stream.write(str + '\n'); + }, + + on: function(type, cb) { + if (!this._callbacks[type]) this._callbacks[type] = []; + + this._callbacks[type].push(cb); + }, + + callback: function(type, data) { + if (this._callbacks[type]) { + for (var c = 0; c < this._callbacks[type].length; c++) { + this._callbacks[type][c].call(this, data); + } + } + } +}; + +module.exports = MPD; diff --git a/xmpp.js b/xmpp.js new file mode 100755 --- /dev/null +++ b/xmpp.js @@ -0,0 +1,48 @@ +#!/usr/bin/env node + +var MPD = require('./lib'); +var xmpp = require('node-xmpp'); +var config = require('./config'); + +var mpd = new MPD(); +var conn = new xmpp.Client(config); +var id = 0; +var NS = 'http://jabber.org/protocol/tune'; + +var publish = function() { + mpd.send('status', function(s) { + mpd.send('currentsong', function(cs) { + var tune = new xmpp.Element('tune', {xmlns: NS}); + + if (cs.file && s.state === 'play') { + // Don't publish "rating" and "uri". + if (cs.Artist) + tune.c('artist').t(cs.Artist); + if (cs.Time) + tune.c('length').t(cs.Time); + if (cs.Album) + tune.c('source').t(cs.Album); + if (cs.Title) + tune.c('title').t(cs.Title); + if (cs.Track) + tune.c('track').t(cs.Track); + } + + conn.send(new xmpp.Element('iq', {type: 'set', id: 'mpd-'+(++id)}) + .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) + .c('publish', {node: NS}) + .c('item') + .cnode(tune).up() + .up() + .up() + .up()); + + mpd.send('idle player', publish); + }); + }); +}; + +// We suppose that the XMPP connection will be open after the MPD one. +conn.on('online', publish); + +// vim: sts=2 et sw=2